Files
trading_bot_v4/app/api/withdrawals/execute/route.ts
mindesbunister ca7b49f745 feat: Add automated profit withdrawal system
- UI page: /withdrawals with stats dashboard and config form
- Settings API: GET/POST for .env configuration
- Stats API: Real-time profit and withdrawal calculations
- Execute API: Safe withdrawal with Drift SDK integration
- Drift service: withdrawFromDrift() with USDC spot market (index 0)
- Safety checks: Min withdrawal amount, min account balance, profit-only
- Telegram notifications: Withdrawal alerts with Solscan links
- Dashboard navigation: Added Withdrawals card (3-card grid)

User goal: 10% of profits automatically withdrawn on schedule
Current: Manual trigger ready, scheduled automation pending
Files: 5 new (withdrawals page, 3 APIs, Drift service), 2 modified
2025-11-19 18:07:07 +01:00

101 lines
3.2 KiB
TypeScript

/**
* Withdrawal Execution API
*
* POST: Execute withdrawal of trading profits
*/
import { NextRequest, NextResponse } from 'next/server'
import { calculateWithdrawalAmount, withdrawFromDrift } from '@/lib/drift/withdraw'
import fs from 'fs'
import path from 'path'
import { sendTelegramNotification } from '@/lib/notifications/telegram'
const ENV_PATH = path.join(process.cwd(), '.env')
export async function POST(request: NextRequest) {
try {
console.log('🎯 Manual withdrawal triggered')
// Calculate withdrawal amount with safety checks
const calculation = await calculateWithdrawalAmount()
if (!calculation.safeToWithdraw) {
console.log(`⚠️ Withdrawal blocked: ${calculation.reason}`)
return NextResponse.json({
success: false,
error: calculation.reason,
availableProfit: calculation.availableProfit,
withdrawalAmount: calculation.withdrawalAmount,
})
}
console.log(`✅ Withdrawal approved: $${calculation.withdrawalAmount.toFixed(2)}`)
// Execute withdrawal
const result = await withdrawFromDrift(calculation.withdrawalAmount)
if (!result.success) {
return NextResponse.json({
success: false,
error: result.error,
}, { status: 500 })
}
// Update LAST_WITHDRAWAL_TIME and TOTAL_WITHDRAWN in .env
const currentTotal = parseFloat(process.env.TOTAL_WITHDRAWN || '0')
const newTotal = currentTotal + calculation.withdrawalAmount
const now = new Date().toISOString()
let envContent = fs.readFileSync(ENV_PATH, 'utf-8')
// Update LAST_WITHDRAWAL_TIME
const timeRegex = /^LAST_WITHDRAWAL_TIME=.*$/m
if (timeRegex.test(envContent)) {
envContent = envContent.replace(timeRegex, `LAST_WITHDRAWAL_TIME=${now}`)
} else {
envContent += `\nLAST_WITHDRAWAL_TIME=${now}`
}
// Update TOTAL_WITHDRAWN
const totalRegex = /^TOTAL_WITHDRAWN=.*$/m
if (totalRegex.test(envContent)) {
envContent = envContent.replace(totalRegex, `TOTAL_WITHDRAWN=${newTotal}`)
} else {
envContent += `\nTOTAL_WITHDRAWN=${newTotal}`
}
fs.writeFileSync(ENV_PATH, envContent)
// Send Telegram notification
try {
await sendTelegramNotification({
type: 'withdrawal',
amount: calculation.withdrawalAmount,
signature: result.signature!,
availableProfit: calculation.availableProfit,
totalWithdrawn: newTotal,
})
} catch (telegramError) {
console.error('Failed to send Telegram notification:', telegramError)
// Don't fail the withdrawal if notification fails
}
console.log(`✅ Withdrawal complete! $${calculation.withdrawalAmount.toFixed(2)} → wallet`)
console.log(`📊 Total withdrawn: $${newTotal.toFixed(2)}`)
return NextResponse.json({
success: true,
amount: calculation.withdrawalAmount,
signature: result.signature,
totalWithdrawn: newTotal,
timestamp: now,
})
} catch (error: any) {
console.error('❌ Withdrawal execution failed:', error)
return NextResponse.json({
success: false,
error: error.message || 'Withdrawal execution failed',
}, { status: 500 })
}
}