/** * Withdrawal Execution Service * * Handles actual withdrawal from Drift Protocol to wallet */ import BN from 'bn.js' import { PublicKey } from '@solana/web3.js' import { initializeDriftService } from './client' export interface WithdrawalResult { success: boolean amount?: number signature?: string error?: string } export async function withdrawFromDrift( amountUSD: number, destinationWallet?: string ): Promise { try { console.log(`💸 Initiating withdrawal: $${amountUSD.toFixed(2)}`) const driftService = await initializeDriftService() // Get USDC spot market index (typically 0 for USDC) const usdcMarketIndex = 0 // Convert USD amount to token amount (USDC has 6 decimals) // $50.25 → 50,250,000 (raw token amount with 6 decimals) const tokenAmount = new BN(Math.floor(amountUSD * 1_000_000)) console.log(`📊 Withdrawal details:`) console.log(` Amount: $${amountUSD.toFixed(2)} USDC`) console.log(` Token amount: ${tokenAmount.toString()} (raw with 6 decimals)`) console.log(` Market index: ${usdcMarketIndex}`) // Get destination address (default to wallet public key if not specified) const destination = destinationWallet ? new PublicKey(destinationWallet) : new PublicKey(process.env.WALLET_PUBLIC_KEY!) console.log(` Destination: ${destination.toString()}`) // Execute withdrawal via Drift SDK // withdraw(amount, marketIndex, associatedTokenAddress, reduceOnly, subAccountId, txParams, updateFuel) const signature = await driftService.getClient().withdraw( tokenAmount, usdcMarketIndex, destination, false, // reduceOnly 0, // subAccountId undefined, // txParams false // updateFuel ) console.log(`✅ Withdrawal successful!`) console.log(` Transaction: ${signature}`) console.log(` Explorer: https://solscan.io/tx/${signature}`) // Confirm transaction console.log('⏳ Confirming transaction on-chain...') const connection = driftService.getConnection() const confirmation = await connection.confirmTransaction(signature, 'confirmed') if (confirmation.value.err) { throw new Error(`Transaction failed: ${JSON.stringify(confirmation.value.err)}`) } console.log('✅ Transaction confirmed on-chain') return { success: true, amount: amountUSD, signature, } } catch (error: any) { console.error('❌ Withdrawal failed:', error) return { success: false, error: error.message || 'Unknown error during withdrawal', } } } export async function calculateWithdrawalAmount(): Promise<{ availableProfit: number withdrawalAmount: number safeToWithdraw: boolean reason?: string }> { try { const driftService = await initializeDriftService() const health = await driftService.getAccountHealth() const currentBalance = health.freeCollateral // Already a number // Configuration const totalInvested = 546 // From roadmap const withdrawalPercent = parseFloat(process.env.WITHDRAWAL_PROFIT_PERCENT || '10') const minWithdrawalAmount = parseFloat(process.env.MIN_WITHDRAWAL_AMOUNT || '50') const minAccountBalance = parseFloat(process.env.MIN_ACCOUNT_BALANCE || '500') // Calculate available profit const availableProfit = Math.max(0, currentBalance - totalInvested) const withdrawalAmount = availableProfit * (withdrawalPercent / 100) console.log(`💰 Withdrawal calculation:`) console.log(` Current balance: $${currentBalance.toFixed(2)}`) console.log(` Total invested: $${totalInvested.toFixed(2)}`) console.log(` Available profit: $${availableProfit.toFixed(2)}`) console.log(` Withdrawal %: ${withdrawalPercent}%`) console.log(` Withdrawal amount: $${withdrawalAmount.toFixed(2)}`) console.log(` Min withdrawal: $${minWithdrawalAmount.toFixed(2)}`) console.log(` Min account balance: $${minAccountBalance.toFixed(2)}`) // Safety checks if (availableProfit <= 0) { return { availableProfit, withdrawalAmount: 0, safeToWithdraw: false, reason: 'No profits available (current balance ≤ total invested)', } } if (withdrawalAmount < minWithdrawalAmount) { return { availableProfit, withdrawalAmount, safeToWithdraw: false, reason: `Withdrawal amount ($${withdrawalAmount.toFixed(2)}) below minimum ($${minWithdrawalAmount.toFixed(2)})`, } } const balanceAfterWithdrawal = currentBalance - withdrawalAmount if (balanceAfterWithdrawal < minAccountBalance) { return { availableProfit, withdrawalAmount, safeToWithdraw: false, reason: `Withdrawal would drop balance to $${balanceAfterWithdrawal.toFixed(2)} (below minimum $${minAccountBalance.toFixed(2)})`, } } return { availableProfit, withdrawalAmount, safeToWithdraw: true, } } catch (error: any) { console.error('❌ Withdrawal calculation failed:', error) return { availableProfit: 0, withdrawalAmount: 0, safeToWithdraw: false, reason: error.message, } } }