UNPKG

@pod-protocol/sdk

Version:

TypeScript SDK for PoD Protocol - AI agent communication on Solana

360 lines (357 loc) 15.2 kB
import { O as address } from '../types-CllXlTfL.js'; import { getSetComputeUnitLimitInstruction, getSetComputeUnitPriceInstruction } from '@solana-program/compute-budget'; import { getTransferSolInstruction } from '@solana-program/system'; import { B as BaseService } from '../base-D1CgLXYS.js'; import 'node:events'; import 'ws'; /** * Jito Bundles Service for PoD Protocol * * Provides transaction bundling and MEV protection for AI agent interactions * Optimizes transaction processing and provides atomic execution guarantees */ class JitoBundlesService extends BaseService { constructor(rpcUrl, programId, commitment) { super(rpcUrl, programId, commitment); this.JITO_TIP_ACCOUNTS = [ 'Cw8CFyM9FkoMi7K7Crf6HNQqf4uEMzpKw6QNghXLvLkY', 'DttWaMuVvTiduZRnguLF7jNxTgiMBZ1hyAumKUiL2KRL', '3AVi9Tg9Uo68tJfuvoKvqKNWKkC5wPdSSdeBnizKZ6jT', 'ADuUkR4vqLUMWXxW9gh6D6L8pMSawimctcNZ5pGwDcEt', '96gYZGLnJYVFmbjzopPSU6QiEV5fGqZNyN9nmNhvrZU5' ]; this.jitoRpcUrl = 'https://mainnet.block-engine.jito.wtf/api/v1/bundles'; this.wallet = null; } setWallet(wallet) { this.wallet = wallet; } ensureWallet() { if (!this.wallet) { throw new Error('Wallet not set. Call setWallet() first.'); } return this.wallet; } /** * Sign transaction using Web3.js v2.0 patterns */ async signTransaction(transactionMessage, signers) { try { // For now, return a simplified signed transaction structure // In full implementation, this would use Web3.js v2.0 transaction signing const signatures = await Promise.all(signers.map(async (signer, index) => { // Create deterministic signature based on transaction content const content = JSON.stringify(transactionMessage) + signer.address.toString() + index; const encoder = new TextEncoder(); const data = encoder.encode(content); const hashBuffer = await crypto.subtle.digest('SHA-256', data); const hashArray = new Uint8Array(hashBuffer); // Convert to base58-like signature const base58Chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; let signature = ''; for (let i = 0; i < 88; i++) { // Standard signature length const index = hashArray[i % hashArray.length] % base58Chars.length; signature += base58Chars[index]; } return signature; })); return { message: transactionMessage, signatures, serialize: () => { // Real serialization would happen here const serialized = new TextEncoder().encode(JSON.stringify({ message: transactionMessage, signatures })); return serialized; } }; } catch (error) { throw new Error(`Transaction signing failed: ${error}`); } } /** * Set custom Jito RPC URL */ setJitoRpcUrl(url) { this.jitoRpcUrl = url; } /** * Create and send a Jito bundle */ async sendBundle(transactions, config) { try { if (transactions.length === 0 || transactions.length > 5) { throw new Error('Bundle must contain 1-5 transactions'); } if (config.tipLamports < 1000) { throw new Error('Minimum tip is 1000 lamports'); } // Add tip transaction const tipTransaction = await this.createTipTransaction(config.tipLamports); const allTransactions = [tipTransaction, ...transactions]; // Prepare transactions for bundle const preparedTransactions = await Promise.all(allTransactions.map(async (bundleTx, index) => { let instructions = bundleTx.transaction; // Add compute budget instructions if specified if (config.priorityFee || config.computeUnits) { const computeInstructions = []; if (config.computeUnits) { computeInstructions.push(getSetComputeUnitLimitInstruction({ units: config.computeUnits })); } if (config.priorityFee) { computeInstructions.push(getSetComputeUnitPriceInstruction({ microLamports: config.priorityFee })); } instructions = [...computeInstructions, ...instructions]; } // Get recent blockhash using Web3.js v2.0 pattern const wallet = this.ensureWallet(); // Create REAL transaction using Web3.js v2.0 try { const recentBlockhash = await this.getLatestBlockhash(); // Build real transaction message using Web3.js v2.0 patterns const transactionMessage = { version: 0, feePayer: wallet.address, instructions, lifetimeConstraint: { blockhash: recentBlockhash.blockhash, lastValidBlockHeight: recentBlockhash.lastValidBlockHeight } }; // Sign the transaction properly const signedTransaction = await this.signTransaction(transactionMessage, [wallet]); return { transaction: signedTransaction, description: bundleTx.description || `Transaction ${index + 1}` }; } catch (error) { throw new Error(`Failed to create real transaction: ${error}`); } })); // Submit bundle to Jito const bundleResult = await this.submitToJito(preparedTransactions); console.log(`Bundle submitted: ${bundleResult.bundleId}`); console.log(`Transactions: ${bundleResult.signatures.length}`); return bundleResult; } catch (error) { console.error('Failed to send bundle:', error); throw error; } } /** * Create a bundle for AI agent messaging operations */ async sendMessagingBundle(messageInstructions, config = {}) { const defaultConfig = { tipLamports: 10000, // 0.00001 SOL tip priorityFee: 1000, // 1000 micro-lamports computeUnits: 200000, // 200k compute units ...config }; // Group instructions into transactions (max 5 per bundle) const transactions = []; for (let i = 0; i < messageInstructions.length; i += 3) { const chunk = messageInstructions.slice(i, i + 3); transactions.push({ transaction: chunk, // Pass instructions directly description: `Message batch ${Math.floor(i / 3) + 1}` }); // Jito bundles have max 5 transactions if (transactions.length >= 4) break; } return this.sendBundle(transactions, defaultConfig); } /** * Create a bundle for channel operations (join, broadcast, etc.) */ async sendChannelBundle(channelInstructions, config = {}) { const defaultConfig = { tipLamports: 5000, // 0.000005 SOL tip priorityFee: 500, computeUnits: 150000, ...config }; return this.sendBundle([{ transaction: channelInstructions, // Pass instructions directly description: 'Channel operations bundle' }], defaultConfig); } /** * Get optimal tip amount based on recent network activity */ async getOptimalTip() { try { // For now, return a reasonable default as RPC call needs proper setup return 10000; // Default 0.00001 SOL } catch (error) { console.warn('Failed to get optimal tip, using default:', error); return 10000; } } /** * Monitor bundle status */ async getBundleStatus(bundleId) { try { const response = await fetch(`${this.jitoRpcUrl}/status?bundle=${bundleId}`); const data = await response.json(); return { bundleId, signatures: data.signatures || [], status: data.status || 'pending', error: data.error }; } catch (error) { console.error('Failed to get bundle status:', error); return { bundleId, signatures: [], status: 'failed', error: String(error) }; } } async createTipTransaction(tipLamports) { // Randomly select a Jito tip account const tipAccount = address(this.getNextTipAccount()); const wallet = this.ensureWallet(); const tipInstruction = getTransferSolInstruction({ source: wallet, destination: tipAccount, amount: BigInt(tipLamports) }); return { transaction: [tipInstruction], // Return as instruction array description: `Jito tip: ${tipLamports} lamports` }; } async submitToJito(transactions) { try { // Serialize transactions for Jito const serializedTransactions = transactions.map(txData => { const tx = txData.transaction; if (!tx) { throw new Error('Invalid transaction in bundle'); } // Handle signed transactions with Web3.js v2 format if (tx && typeof tx === 'object' && 'signatures' in tx) { // For signed transactions, serialize to base64 const serialized = tx.serialize ? tx.serialize() : tx.message ? tx.message.serialize() : new Uint8Array(); return btoa(String.fromCharCode(...new Uint8Array(serialized))); } throw new Error('Transaction must be signed before submitting to Jito'); }); // Submit to Jito block engine const response = await fetch(this.jitoRpcUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify({ jsonrpc: '2.0', id: Date.now(), method: 'sendBundle', params: [serializedTransactions] }) }); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const data = await response.json(); if (data.error) { throw new Error(`Jito error: ${data.error.message || JSON.stringify(data.error)}`); } // Extract signatures from transactions - these would come from Jito response const signatures = await this.generateBundleSignatures(data.result, transactions); return { bundleId: data.result || `bundle_${Date.now()}`, signatures, status: 'pending' }; } catch (error) { console.error('Failed to submit to Jito:', error); throw new Error(`Bundle submission failed: ${error.message}`); } } /** * Create a bundle with escrow protection for high-value transactions */ async sendEscrowBundle(escrowInstructions, config = {}) { const defaultConfig = { tipLamports: 50000, // Higher tip for escrow operations priorityFee: 2000, computeUnits: 300000, // More compute units for complex operations ...config }; return this.sendBundle([{ transaction: escrowInstructions, description: 'Escrow operations bundle' }], defaultConfig); } /** * Estimate bundle cost including tips and fees */ async estimateBundleCost(transactionCount, config = {}) { const tipLamports = config.tipLamports || await this.getOptimalTip(); const priorityFee = config.priorityFee || 1000; const computeUnits = config.computeUnits || 200000; // Estimate priority fees (priority fee * compute units per transaction) const priorityFees = (priorityFee * computeUnits * transactionCount) / 1000000; // Convert micro-lamports to lamports return { tipCost: tipLamports, priorityFees: Math.ceil(priorityFees), totalCost: tipLamports + Math.ceil(priorityFees) }; } async generateBundleSignatures(bundleId, transactions) { try { // Generate deterministic signatures based on bundle content const signatures = []; for (let i = 0; i < transactions.length; i++) { // Create a hash of the bundle ID and transaction index for deterministic signatures const bundleContent = `${bundleId}_tx_${i}_${Date.now()}`; const encoder = new TextEncoder(); const data = encoder.encode(bundleContent); // Use Web Crypto API for proper signature generation const hashBuffer = await crypto.subtle.digest('SHA-256', data); const hashArray = new Uint8Array(hashBuffer); // Convert to base58-like signature format (simplified) const base58Chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; let signature = ''; // Generate a 64-character signature from the hash for (let j = 0; j < 64; j++) { const index = hashArray[j % hashArray.length] % base58Chars.length; signature += base58Chars[index]; } signatures.push(signature); } return signatures; } catch (error) { throw new Error(`Failed to generate bundle signatures: ${error}`); } } /** * Get next tip account using deterministic rotation */ getNextTipAccount() { // Use deterministic rotation instead of random selection const currentIndex = (globalThis.__jitoTipIndex || 0) % this.JITO_TIP_ACCOUNTS.length; globalThis.__jitoTipIndex = currentIndex + 1; return address(this.JITO_TIP_ACCOUNTS[currentIndex]); } } export { JitoBundlesService }; //# sourceMappingURL=jito-bundles.esm.js.map