UNPKG

delegate-framework

Version:

A TypeScript framework for building robust, production-ready blockchain workflows with comprehensive error handling, logging, and testing. Maintained by delegate.fun

206 lines 9.21 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Allocator = void 0; const web3_js_1 = require("@solana/web3.js"); const spl_token_1 = require("@solana/spl-token"); const base_delegate_1 = require("./base-delegate"); const jupiter_1 = require("./swap/jupiter"); const raydium_1 = require("./swap/raydium"); class Allocator extends base_delegate_1.BaseDelegate { constructor(connection, signerKeypair, heliusClient, feeTakerKeypair) { super(connection, signerKeypair, feeTakerKeypair); this.heliusClient = heliusClient; // Initialize swap protocols this.jupiterSwap = new jupiter_1.JupiterSwap(signerKeypair, connection, { heliusClient }); this.raydiumSwap = new raydium_1.RaydiumSwap(signerKeypair, { heliusClient }); } async executeDelegate(delegateOptions) { const requestId = this.generateRequestId(); try { this.logOperation('allocator_execution_started', { requestId }); this.validateOptions(delegateOptions); const { allocations, slippageBps = 50, costBuffer = 0.005 } = delegateOptions; if (!allocations || allocations.length === 0) { throw new Error("Allocations are required"); } // Get sender's SOL balance const senderBalance = await this.heliusClient.getBalance(this.signerKeypair.publicKey); const solBalanceInSol = senderBalance / web3_js_1.LAMPORTS_PER_SOL; this.logOperation('balance_retrieved', { requestId, balance: solBalanceInSol }); const signatures = []; const allocationResults = []; // Process each allocation for (let i = 0; i < allocations.length; i++) { const allocation = allocations[i]; if (!allocation) { this.logOperation('allocation_skipped', { requestId, reason: 'undefined_allocation', index: i }); continue; } try { const result = await this.processAllocation(allocation, solBalanceInSol, costBuffer, slippageBps, i + 1, allocations.length); signatures.push(result.signature); allocationResults.push(result); this.logOperation('allocation_processed', { requestId, contractAddress: allocation.contractAddress, percentage: allocation.percentage, signature: result.signature }); } catch (error) { await this.handleError(error instanceof Error ? error : new Error(String(error)), { requestId, contractAddress: allocation.contractAddress }); // Continue with next allocation instead of failing completely this.logOperation('allocation_skipped', { requestId, contractAddress: allocation.contractAddress, error: error instanceof Error ? error.message : String(error) }); continue; } } this.logOperation('allocator_execution_completed', { requestId, signatures }); return { success: true, signatures, allocations: allocationResults }; } catch (error) { await this.handleError(error instanceof Error ? error : new Error(String(error)), { requestId }); throw error; } } validateOptions(delegateOptions) { if (!delegateOptions.allocations || !Array.isArray(delegateOptions.allocations)) { throw new Error("allocations must be a non-empty array"); } if (delegateOptions.allocations.length === 0) { throw new Error("At least one allocation is required"); } let totalPercentage = 0; for (const allocation of delegateOptions.allocations) { if (!allocation.contractAddress) { throw new Error("contractAddress is required for each allocation"); } this.validatePublicKey(allocation.contractAddress, 'contractAddress'); if (typeof allocation.percentage !== 'number' || allocation.percentage <= 0) { throw new Error("percentage must be a positive number for each allocation"); } totalPercentage += allocation.percentage; } if (totalPercentage > 100) { throw new Error("Total allocation percentage cannot exceed 100%"); } if (delegateOptions.slippageBps !== undefined) { this.validateNumberField(delegateOptions.slippageBps, 'slippageBps', 0, 10000); } if (delegateOptions.costBuffer !== undefined) { this.validateNumberField(delegateOptions.costBuffer, 'costBuffer', 0); } } async processAllocation(allocation, solBalanceInSol, costBuffer, slippageBps, currentIndex, totalAllocations) { const { contractAddress, percentage } = allocation; // Calculate amount to allocate const amountToAllocate = (solBalanceInSol * (percentage / 100)) - costBuffer; if (amountToAllocate <= 0) { throw new Error(`Insufficient balance for allocation: ${amountToAllocate} SOL`); } this.logOperation('allocation_calculation', { contractAddress, percentage, amountToAllocate, currentIndex, totalAllocations }); // Get or create token account for the target token const mint = new web3_js_1.PublicKey(contractAddress); await this.retryOperation(async () => { return await (0, spl_token_1.getOrCreateAssociatedTokenAccount)(this.connection, this.signerKeypair, mint, this.signerKeypair.publicKey, true); }, 3); // Execute swap from SOL to target token const swapResult = await this.executeSwapWithFallback("So11111111111111111111111111111111111111112", // SOL contractAddress, amountToAllocate, slippageBps / 100 // Convert basis points to percentage ); if (!swapResult.success || !swapResult.signature) { throw new Error(`Swap failed for ${contractAddress}: ${swapResult.error}`); } return { contractAddress, percentage, amountAllocated: amountToAllocate, signature: swapResult.signature }; } async executeSwapWithFallback(fromAsset, toAsset, amount, slippage) { // Try Jupiter first try { const result = await this.retryOperation(() => this.executeJupiterSwap(fromAsset, toAsset, amount, slippage), 3); if (result.success) { return { ...result, signature: result.signature }; } } catch (error) { this.logOperation('jupiter_swap_failed', { fromAsset, toAsset, amount, error: error instanceof Error ? error.message : String(error) }); } // Fallback to Raydium try { const result = await this.retryOperation(() => this.executeRaydiumSwap(fromAsset, toAsset, amount, slippage), 3); if (result.success) { return { ...result, signature: result.signature }; } } catch (error) { this.logOperation('raydium_swap_failed', { fromAsset, toAsset, amount, error: error instanceof Error ? error.message : String(error) }); } return { success: false, error: "Both Jupiter and Raydium swaps failed" }; } async executeJupiterSwap(fromAsset, toAsset, amount, slippage) { // Get quote const quote = await this.jupiterSwap.getQuote(fromAsset, toAsset, amount, slippage); if (!quote) { throw new Error("Failed to get Jupiter quote"); } // Create transaction const transaction = await this.jupiterSwap.createSwapTransaction(quote); // Execute swap const result = await this.jupiterSwap.executeSwap(transaction); return result; } async executeRaydiumSwap(fromAsset, toAsset, amount, slippage) { // Get quote const quote = await this.raydiumSwap.getQuote(fromAsset, toAsset, amount, slippage); if (!quote) { throw new Error("Failed to get Raydium quote"); } // Create transaction const transaction = await this.raydiumSwap.createSwapTransaction(quote); // Execute swap const result = await this.raydiumSwap.executeSwap(transaction); return result; } } exports.Allocator = Allocator; //# sourceMappingURL=allocator.js.map