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 || [] // Debug: log ALL orders to see what we have console.log(`📋 Raw orders length: ${orders.length}`) orders.forEach((order, index) => { if (!order.baseAssetAmount.isZero()) { console.log(`📋 Order ${index}:`, { orderId: order.orderId, status: order.status, orderType: order.orderType, baseAssetAmount: order.baseAssetAmount.toString(), price: order.price ? order.price.toString() : null, triggerPrice: order.triggerPrice ? order.triggerPrice.toString() : null, reduceOnly: order.reduceOnly, marketIndex: order.marketIndex }) } }) // Filter for active orders - handle both numeric and object status formats const activeOrders = orders.filter(order => { if (order.baseAssetAmount.isZero()) return false // Handle object-based status (new format) if (typeof order.status === 'object') { return order.status.hasOwnProperty('open') } // Handle numeric status (old format) return order.status === 0 }) // Show ALL orders with non-zero amounts for debugging const allOrders = orders.filter(order => !order.baseAssetAmount.isZero() // Only filter out empty orders ) console.log(`📋 Found ${activeOrders.length} active orders, ${allOrders.length} total orders (${orders.length} order slots)`) // Debug: log all order statuses const statusCounts = orders.reduce((acc, order) => { if (!order.baseAssetAmount.isZero()) { 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' // Handle object-based orderType if (typeof order.orderType === 'object') { if (order.orderType.market !== undefined) orderType = 'MARKET' else if (order.orderType.limit !== undefined) orderType = 'LIMIT' else if (order.orderType.triggerMarket !== undefined) orderType = 'TRIGGER_MARKET' else if (order.orderType.triggerLimit !== undefined) orderType = 'TRIGGER_LIMIT' else if (order.orderType.oracle !== undefined) orderType = 'ORACLE' } else { // Handle numeric orderType 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' // Handle object-based direction if (typeof order.direction === 'object') { if (order.direction.long !== undefined) direction = 'LONG' else if (order.direction.short !== undefined) direction = 'SHORT' } else { // Handle numeric direction switch (order.direction) { case 0: direction = 'LONG'; break case 1: direction = 'SHORT'; break } } // Get status as string let statusString = 'UNKNOWN' if (typeof order.status === 'object') { if (order.status.open !== undefined) statusString = 'OPEN' else if (order.status.filled !== undefined) statusString = 'FILLED' else if (order.status.canceled !== undefined) statusString = 'CANCELED' } else { switch (order.status) { case 0: statusString = 'OPEN'; break case 1: statusString = 'FILLED'; break case 2: statusString = 'CANCELED'; 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: statusString, marketIndex, isActive: typeof order.status === 'object' ? order.status.hasOwnProperty('open') : order.status === 0, raw: { status: order.status, orderType: order.orderType, direction: order.direction, baseAssetAmount: order.baseAssetAmount.toString() } } }) const ordersResult = { success: true, orders: formattedOrders, totalOrders: allOrders.length, // Return ALL orders, not just active activeOrders: activeOrders.length, // But also show active count timestamp: Date.now(), rpcEndpoint: getRpcStatus().currentEndpoint, details: { wallet: keypair.publicKey.toString(), totalOrderSlots: orders.length, activeOrderSlots: activeOrders.length, allOrderSlots: allOrders.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 }) }