diff --git a/app/api/drift/orders/route.js b/app/api/drift/orders/route.js new file mode 100644 index 0000000..bb1730c --- /dev/null +++ b/app/api/drift/orders/route.js @@ -0,0 +1,163 @@ +import { NextResponse } from 'next/server' +import { executeWithFailover, getRpcStatus } from '../../../../lib/rpc-failover.js' + +export async function GET() { + try { + console.log('📋 Getting Drift open orders...') + + // Log RPC status + const rpcStatus = getRpcStatus() + console.log('🌐 RPC Status:', rpcStatus) + + // Check if environment is configured + if (!process.env.SOLANA_PRIVATE_KEY) { + return NextResponse.json({ + success: false, + error: 'Drift not configured - missing SOLANA_PRIVATE_KEY' + }, { status: 400 }) + } + + // Execute orders check with RPC failover + const result = await executeWithFailover(async (connection) => { + // Import Drift SDK components + const { DriftClient, initialize } = await import('@drift-labs/sdk') + const { Keypair } = await import('@solana/web3.js') + const { AnchorProvider, BN } = await import('@coral-xyz/anchor') + + const privateKeyArray = JSON.parse(process.env.SOLANA_PRIVATE_KEY) + const keypair = Keypair.fromSecretKey(new Uint8Array(privateKeyArray)) + + // Use the correct Wallet class from @coral-xyz/anchor/dist/cjs/nodewallet + const { default: NodeWallet } = await import('@coral-xyz/anchor/dist/cjs/nodewallet.js') + const wallet = new NodeWallet(keypair) + + // Initialize Drift SDK + const env = 'mainnet-beta' + const sdkConfig = initialize({ env }) + + const driftClient = new DriftClient({ + connection, + wallet, + programID: sdkConfig.DRIFT_PROGRAM_ID, + opts: { + commitment: 'confirmed', + }, + }) + + try { + await driftClient.subscribe() + console.log('✅ Connected to Drift for orders check') + + // Check if user has account + let userAccount + try { + userAccount = await driftClient.getUserAccount() + } catch (accountError) { + await driftClient.unsubscribe() + throw new Error('No Drift user account found. Please initialize your account first.') + } + + // Get open orders + const orders = userAccount.orders || [] + + // Show ALL orders for debugging - not just status 0 + const allOrders = orders.filter(order => + !order.baseAssetAmount.isZero() // Only filter out empty orders + ) + + console.log(`📋 Found ${allOrders.length} total orders (${orders.length} order slots)`) + + // Debug: log all order statuses + const statusCounts = orders.reduce((acc, order) => { + acc[order.status] = (acc[order.status] || 0) + 1 + return acc + }, {}) + console.log('📊 Order status breakdown:', statusCounts) + + const formattedOrders = allOrders.map(order => { + const marketIndex = order.marketIndex + const symbol = ['SOL', 'BTC', 'ETH', 'APT', 'AVAX', 'BNB', 'MATIC', 'ARB', 'DOGE', 'OP'][marketIndex] || `UNKNOWN_${marketIndex}` + + let orderType = 'UNKNOWN' + switch (order.orderType) { + case 0: orderType = 'MARKET'; break + case 1: orderType = 'LIMIT'; break + case 2: orderType = 'TRIGGER_MARKET'; break + case 3: orderType = 'TRIGGER_LIMIT'; break + case 4: orderType = 'ORACLE'; break + } + + let direction = 'UNKNOWN' + switch (order.direction) { + case 0: direction = 'LONG'; break + case 1: direction = 'SHORT'; break + } + + return { + orderId: order.orderId, + symbol: `${symbol}-PERP`, + orderType, + direction, + size: (Number(order.baseAssetAmount) / 1e9).toFixed(6), + price: order.price ? (Number(order.price) / 1e6).toFixed(4) : null, + triggerPrice: order.triggerPrice ? (Number(order.triggerPrice) / 1e6).toFixed(4) : null, + reduceOnly: order.reduceOnly, + status: order.status, + marketIndex + } + }) + + const ordersResult = { + success: true, + orders: formattedOrders, + totalOrders: activeOrders.length, + timestamp: Date.now(), + rpcEndpoint: getRpcStatus().currentEndpoint, + details: { + wallet: keypair.publicKey.toString(), + totalOrderSlots: orders.length, + activeOrderSlots: activeOrders.length + } + } + + await driftClient.unsubscribe() + + console.log('📋 Orders retrieved:', { + totalActiveOrders: activeOrders.length, + rpcEndpoint: getRpcStatus().currentEndpoint + }) + + return ordersResult + + } catch (driftError) { + console.error('❌ Drift orders error:', driftError) + + try { + await driftClient.unsubscribe() + } catch (cleanupError) { + console.warn('⚠️ Cleanup error:', cleanupError.message) + } + + throw driftError + } + }, 3) // Max 3 retries across different RPCs + + return NextResponse.json(result) + + } catch (error) { + console.error('❌ Orders API error:', error) + + return NextResponse.json({ + success: false, + error: 'Failed to get Drift orders', + details: error.message, + rpcStatus: getRpcStatus() + }, { status: 500 }) + } +} + +export async function POST() { + return NextResponse.json({ + message: 'Use GET method to retrieve Drift orders' + }, { status: 405 }) +} diff --git a/app/api/drift/trade/route.js b/app/api/drift/trade/route.js index 56ab27d..81df958 100644 --- a/app/api/drift/trade/route.js +++ b/app/api/drift/trade/route.js @@ -258,7 +258,7 @@ export async function POST(request) { await new Promise(resolve => setTimeout(resolve, 5000)) // 2. Calculate stop loss and take profit prices - const stopLossPercent = riskPercent / 100 // Convert 2% to 0.02 + const stopLossPercent = Math.max(riskPercent / 100, 0.02) // Minimum 2% to avoid "too close" issues const takeProfitPercent = stopLossPercent * 2 // 2:1 risk reward ratio let stopLossPrice, takeProfitPrice @@ -274,8 +274,9 @@ export async function POST(request) { console.log(`🎯 Risk management:`, { stopLossPrice: stopLossPrice.toFixed(4), takeProfitPrice: takeProfitPrice.toFixed(4), - riskPercent: `${riskPercent}%`, - rewardRatio: '2:1' + riskPercent: `${stopLossPercent * 100}%`, + rewardRatio: '2:1', + priceDifference: Math.abs(currentPrice - stopLossPrice).toFixed(4) }) let stopLossTx = null, takeProfitTx = null @@ -286,7 +287,13 @@ export async function POST(request) { console.log('🛡️ Placing stop loss order...') const stopLossTriggerPrice = new BN(Math.floor(stopLossPrice * 1e6)) - const stopLossOrderPrice = new BN(Math.floor(stopLossPrice * 0.99 * 1e6)) // Slightly worse price to ensure execution + const stopLossOrderPrice = new BN(Math.floor(stopLossPrice * 0.995 * 1e6)) // 0.5% slippage buffer + + console.log(`🛡️ Stop Loss Details:`, { + triggerPrice: (stopLossTriggerPrice.toNumber() / 1e6).toFixed(4), + orderPrice: (stopLossOrderPrice.toNumber() / 1e6).toFixed(4), + baseAssetAmount: baseAssetAmount.toString() + }) stopLossTx = await driftClient.placePerpOrder({ orderType: OrderType.TRIGGER_LIMIT, @@ -301,6 +308,13 @@ export async function POST(request) { console.log('✅ Stop loss placed:', stopLossTx) } catch (slError) { console.warn('⚠️ Stop loss failed:', slError.message) + // Log more details about the stop loss failure + console.warn('🛡️ Stop loss failure details:', { + stopLossPrice, + currentPrice, + priceDiff: Math.abs(currentPrice - stopLossPrice), + percentDiff: ((Math.abs(currentPrice - stopLossPrice) / currentPrice) * 100).toFixed(2) + '%' + }) } } @@ -310,7 +324,14 @@ export async function POST(request) { console.log('🎯 Placing take profit order...') const takeProfitTriggerPrice = new BN(Math.floor(takeProfitPrice * 1e6)) - const takeProfitOrderPrice = new BN(Math.floor(takeProfitPrice * 1.01 * 1e6)) // Slightly better price to ensure execution + const takeProfitOrderPrice = new BN(Math.floor(takeProfitPrice * 1.005 * 1e6)) // 0.5% slippage for execution + + console.log('🎯 Take Profit Details:', { + takeProfitPrice: takeProfitPrice.toFixed(4), + triggerPrice: (Number(takeProfitTriggerPrice) / 1e6).toFixed(4), + orderPrice: (Number(takeProfitOrderPrice) / 1e6).toFixed(4), + baseAssetAmount: baseAssetAmount.toString() + }) takeProfitTx = await driftClient.placePerpOrder({ orderType: OrderType.TRIGGER_LIMIT, @@ -322,9 +343,13 @@ export async function POST(request) { reduceOnly: true, }) - console.log('✅ Take profit placed:', takeProfitTx) + console.log('✅ Take profit placed successfully:', takeProfitTx) } catch (tpError) { - console.warn('⚠️ Take profit failed:', tpError.message) + console.error('❌ Take profit placement failed:', { + error: tpError.message, + code: tpError.code, + logs: tpError.logs || 'No logs available' + }) } } diff --git a/prisma/prisma/dev.db b/prisma/prisma/dev.db index ba4b9f7..6eaa640 100644 Binary files a/prisma/prisma/dev.db and b/prisma/prisma/dev.db differ