import { Connection, Keypair, VersionedTransaction, PublicKey } from '@solana/web3.js' import fetch from 'cross-fetch' export interface JupiterQuote { inputMint: string inAmount: string outputMint: string outAmount: string otherAmountThreshold: string swapMode: string slippageBps: number priceImpactPct: string routePlan: any[] } export interface TradeOrder { id: string symbol: string side: 'BUY' | 'SELL' amount: number entryPrice?: number stopLoss?: number takeProfit?: number status: 'PENDING' | 'FILLED' | 'CANCELLED' | 'MONITORING' txId?: string timestamp: number } class JupiterDEXService { private connection: Connection private keypair: Keypair | null = null private activeOrders: TradeOrder[] = [] // Token mint addresses private tokens = { SOL: 'So11111111111111111111111111111111111111112', // Wrapped SOL USDC: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', USDT: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB', } constructor() { const rpcUrl = process.env.SOLANA_RPC_URL || 'https://api.mainnet-beta.solana.com' this.connection = new Connection(rpcUrl, 'confirmed') this.initializeWallet() } private initializeWallet() { try { if (process.env.SOLANA_PRIVATE_KEY) { const privateKeyArray = JSON.parse(process.env.SOLANA_PRIVATE_KEY) this.keypair = Keypair.fromSecretKey(new Uint8Array(privateKeyArray)) console.log('✅ Jupiter DEX wallet initialized:', this.keypair.publicKey.toString()) } else { console.warn('⚠️ No SOLANA_PRIVATE_KEY found for Jupiter DEX') } } catch (error) { console.error('❌ Failed to initialize Jupiter DEX wallet:', error) } } async getQuote( inputMint: string, outputMint: string, amount: number, slippageBps: number = 50 // 0.5% slippage ): Promise { try { const url = `https://quote-api.jup.ag/v6/quote?inputMint=${inputMint}&outputMint=${outputMint}&amount=${amount}&slippageBps=${slippageBps}` console.log('🔍 Getting Jupiter quote:', { inputMint, outputMint, amount }) const response = await fetch(url) if (!response.ok) { throw new Error(`Jupiter API error: ${response.status}`) } const quote = await response.json() console.log('📊 Jupiter quote received:', quote) return quote } catch (error) { console.error('❌ Failed to get Jupiter quote:', error) return null } } async executeSwap( inputMint: string, outputMint: string, amount: number, slippageBps: number = 50 ): Promise<{ success: boolean txId?: string error?: string }> { if (!this.keypair) { return { success: false, error: 'Wallet not initialized' } } try { console.log('🔄 Executing Jupiter swap:', { inputMint, outputMint, amount }) // 1. Get quote const quote = await this.getQuote(inputMint, outputMint, amount, slippageBps) if (!quote) { return { success: false, error: 'Failed to get quote' } } // 2. Get swap transaction const swapResponse = await fetch('https://quote-api.jup.ag/v6/swap', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ quoteResponse: quote, userPublicKey: this.keypair.publicKey.toString(), wrapAndUnwrapSol: true, }) }) if (!swapResponse.ok) { throw new Error(`Swap API error: ${swapResponse.status}`) } const { swapTransaction } = await swapResponse.json() // 3. Deserialize and sign transaction const swapTransactionBuf = Buffer.from(swapTransaction, 'base64') const transaction = VersionedTransaction.deserialize(swapTransactionBuf) transaction.sign([this.keypair]) // 4. Submit transaction const txId = await this.connection.sendTransaction(transaction) // 5. Confirm transaction const confirmation = await this.connection.confirmTransaction(txId, 'confirmed') if (confirmation.value.err) { return { success: false, error: `Transaction failed: ${confirmation.value.err}` } } console.log('✅ Jupiter swap successful:', txId) return { success: true, txId } } catch (error: any) { console.error('❌ Jupiter swap failed:', error) return { success: false, error: error.message } } } async executeTrade(params: { symbol: string side: 'BUY' | 'SELL' amount: number stopLoss?: number takeProfit?: number tradingPair?: string quickSwap?: boolean }): Promise<{ success: boolean orderId?: string txId?: string error?: string }> { try { const { symbol, side, amount, stopLoss, takeProfit, tradingPair, quickSwap } = params console.log('🎯 Executing real DEX trade:', params) // Handle different trading pairs let inputMint: string let outputMint: string let amountLamports: number if (quickSwap || tradingPair === 'SOL/USDC') { // SOL to USDC swap inputMint = this.tokens.SOL outputMint = this.tokens.USDC amountLamports = Math.floor(amount * 1000000000) // SOL has 9 decimals } else if (tradingPair === 'USDC/SOL') { // USDC to SOL swap inputMint = this.tokens.USDC outputMint = this.tokens.SOL amountLamports = Math.floor(amount * 1000000) // USDC has 6 decimals } else { // Default behavior based on side inputMint = side === 'BUY' ? this.tokens.USDC : this.tokens.SOL outputMint = side === 'BUY' ? this.tokens.SOL : this.tokens.USDC amountLamports = side === 'BUY' ? Math.floor(amount * 1000000) // USDC has 6 decimals : Math.floor(amount * 1000000000) // SOL has 9 decimals } // Execute the swap const swapResult = await this.executeSwap(inputMint, outputMint, amountLamports) if (!swapResult.success) { return { success: false, error: swapResult.error } } // Create order tracking const orderId = `jupiter_${Date.now()}_${Math.random().toString(36).substr(2, 8)}` const order: TradeOrder = { id: orderId, symbol, side, amount, stopLoss, takeProfit, status: stopLoss || takeProfit ? 'MONITORING' : 'FILLED', txId: swapResult.txId, timestamp: Date.now() } this.activeOrders.push(order) // Start monitoring for TP/SL if needed if (stopLoss || takeProfit) { this.startOrderMonitoring(order) } return { success: true, orderId, txId: swapResult.txId } } catch (error: any) { console.error('❌ DEX trade execution failed:', error) return { success: false, error: error.message } } } private async startOrderMonitoring(order: TradeOrder) { console.log('👁️ Starting TP/SL monitoring for order:', order.id) // This would run in a background process // For now, we'll log that monitoring started // TODO: Implement continuous price monitoring // - Check current price every few seconds // - Execute reverse trade when TP/SL is hit // - Update order status } getActiveOrders(): TradeOrder[] { return this.activeOrders } async cancelOrder(orderId: string): Promise { const orderIndex = this.activeOrders.findIndex(o => o.id === orderId) if (orderIndex >= 0) { this.activeOrders[orderIndex].status = 'CANCELLED' return true } return false } isConfigured(): boolean { return this.keypair !== null } } export const jupiterDEXService = new JupiterDEXService() export default JupiterDEXService