/** * Withdrawal Stats API * * Returns current account statistics for withdrawal calculations */ import { NextResponse } from 'next/server' import { getPrismaClient } from '@/lib/database/trades' import { initializeDriftService } from '@/lib/drift/client' export async function GET() { try { const prisma = getPrismaClient() // Get current Drift balance and actual deposits const driftService = await initializeDriftService() const health = await driftService.getAccountHealth() const currentBalance = health.freeCollateral // Already a number // Get actual deposits from Drift Protocol (ground truth from blockchain) const user = driftService.getUser() const userAccount = user.getUserAccount() const usdcSpotPosition = userAccount.spotPositions.find( (pos: any) => pos.marketIndex === 0 // USDC market index ) const cumulativeDeposits = usdcSpotPosition ? Number(usdcSpotPosition.cumulativeDeposits.toString()) / 1_000_000 : 546 // Fallback to hardcoded if query fails (shouldn't happen) const totalInvested = cumulativeDeposits // Use actual deposits as "invested" // Calculate total P&L from database (v8 trades only, exclude archived) const trades = await prisma.trade.findMany({ where: { exitReason: { not: null }, status: { not: 'archived' }, // Exclude pre-v8 trades }, select: { realizedPnL: true, entryPrice: true, exitPrice: true, positionSizeUSD: true, direction: true, }, }) // Recalculate P&L from entry/exit prices (fixes compounding bugs) const totalPnL = trades.reduce((sum, trade) => { const correctPnL = trade.positionSizeUSD * ( trade.direction === 'long' ? (trade.exitPrice - trade.entryPrice) / trade.entryPrice : (trade.entryPrice - trade.exitPrice) / trade.entryPrice ) return sum + correctPnL }, 0) // Get total withdrawn from .env const totalWithdrawn = parseFloat(process.env.TOTAL_WITHDRAWN || '0') // Calculate available profit // Current balance is what's left after deposits + P&L - previous withdrawals // Available profit = current balance (what we have now, which includes trading profit/loss) const availableProfit = Math.max(0, currentBalance) // Calculate inferred previous withdrawals // If deposits + P&L - current balance > 0, that's what was withdrawn const inferredWithdrawals = Math.max(0, cumulativeDeposits + totalPnL - currentBalance) // Calculate next withdrawal amount const withdrawalPercent = parseFloat(process.env.WITHDRAWAL_PROFIT_PERCENT || '10') const nextWithdrawalAmount = availableProfit * (withdrawalPercent / 100) // Calculate next withdrawal time let nextWithdrawalTime: string | null = null if (process.env.ENABLE_AUTO_WITHDRAWALS === 'true' && process.env.LAST_WITHDRAWAL_TIME) { const lastWithdrawal = new Date(process.env.LAST_WITHDRAWAL_TIME) const intervalHours = parseFloat(process.env.WITHDRAWAL_INTERVAL_HOURS || '168') const nextTime = new Date(lastWithdrawal.getTime() + intervalHours * 60 * 60 * 1000) nextWithdrawalTime = nextTime.toISOString() } else if (process.env.ENABLE_AUTO_WITHDRAWALS === 'true') { // First withdrawal - schedule from now const intervalHours = parseFloat(process.env.WITHDRAWAL_INTERVAL_HOURS || '168') const nextTime = new Date(Date.now() + intervalHours * 60 * 60 * 1000) nextWithdrawalTime = nextTime.toISOString() } return NextResponse.json({ success: true, currentBalance: parseFloat(currentBalance.toFixed(2)), totalInvested, totalPnL: parseFloat(totalPnL.toFixed(2)), totalWithdrawn, availableProfit: parseFloat(availableProfit.toFixed(2)), nextWithdrawalAmount: parseFloat(nextWithdrawalAmount.toFixed(2)), nextWithdrawalTime, }) } catch (error: any) { console.error('Failed to load withdrawal stats:', error) return NextResponse.json({ success: false, error: error.message, currentBalance: 0, totalInvested: 546, totalPnL: 0, totalWithdrawn: 0, availableProfit: 0, nextWithdrawalAmount: 0, nextWithdrawalTime: null, }) } }