UNPKG

@pythnetwork/solana-utils

Version:

Utility functions for Solana

94 lines (93 loc) 4.15 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.sendTransactionsJito = exports.buildJitoTipInstruction = exports.getRandomTipAccount = exports.TIP_ACCOUNTS = void 0; const ts_log_1 = require("ts-log"); const web3_js_1 = require("@solana/web3.js"); const bs58_1 = __importDefault(require("bs58")); const types_1 = require("jito-ts/dist/sdk/block-engine/types"); exports.TIP_ACCOUNTS = [ "HFqU5x63VTqvQss8hp11i4wVV8bD44PvwucfZ2bU7gRe", "Cw8CFyM9FkoMi7K7Crf6HNQqf4uEMzpKw6QNghXLvLkY", "DfXygSm4jCyNCybVYYK6DwvWqjKee8pbDmJGcLWNDXjh", "ADaUMid9yfUytqMBgopwjb2DTLSokTSzL1zt6iGPaS49", "3AVi9Tg9Uo68tJfuvoKvqKNWKkC5wPdSSdeBnizKZ6jT", "DttWaMuVvTiduZRnguLF7jNxTgiMBZ1hyAumKUiL2KRL", "96gYZGLnJYVFmbjzopPSU6QiEV5fGqZNyN9nmNhvrZU5", "ADuUkR4vqLUMWXxW9gh6D6L8pMSawimctcNZ5pGwDcEt", ]; function getRandomTipAccount() { const randomInt = Math.floor(Math.random() * exports.TIP_ACCOUNTS.length); return new web3_js_1.PublicKey(exports.TIP_ACCOUNTS[randomInt]); } exports.getRandomTipAccount = getRandomTipAccount; function buildJitoTipInstruction(payer, lamports) { return web3_js_1.SystemProgram.transfer({ fromPubkey: payer, toPubkey: getRandomTipAccount(), lamports, }); } exports.buildJitoTipInstruction = buildJitoTipInstruction; async function sendTransactionsJito(transactions, searcherClients, wallet, options = {}, logger = ts_log_1.dummyLogger) { const clients = Array.isArray(searcherClients) ? searcherClients : [searcherClients]; if (clients.length === 0) { throw new Error("No searcher clients provided"); } const maxRetryTimeMs = options.maxRetryTimeMs || 60000; // Default to 60 seconds const delayBetweenCyclesMs = options.delayBetweenCyclesMs || 1000; // Default to 1 second const startTime = Date.now(); const signedTransactions = []; for (const transaction of transactions) { const signers = transaction.signers; let tx = transaction.tx; if (signers) { tx.sign(signers); } tx = await wallet.signTransaction(tx); signedTransactions.push(tx); } const firstTransactionSignature = bs58_1.default.encode(signedTransactions[0].signatures[0]); const bundle = new types_1.Bundle(signedTransactions, 2); let lastError = null; let totalAttempts = 0; while (Date.now() - startTime < maxRetryTimeMs) { // Try all clients in this cycle for (let i = 0; i < clients.length; i++) { const currentClient = clients[i]; totalAttempts++; try { await currentClient.sendBundle(bundle); logger.info({ clientIndex: i, totalAttempts }, `Successfully sent bundle to Jito client after ${totalAttempts} attempts`); return firstTransactionSignature; } catch (err) { lastError = err; logger.error({ clientIndex: i, totalAttempts, err: err.message }, `Attempt ${totalAttempts}: Error sending bundle to Jito client ${i}`); } // Check if we've run out of time if (Date.now() - startTime >= maxRetryTimeMs) { break; } } // If we've tried all clients and still have time, wait before next cycle const timeRemaining = maxRetryTimeMs - (Date.now() - startTime); if (timeRemaining > delayBetweenCyclesMs) { await new Promise((resolve) => setTimeout(resolve, delayBetweenCyclesMs)); } } const totalTimeMs = Date.now() - startTime; const errorMsg = `Failed to send transactions via JITO after ${totalAttempts} attempts over ${totalTimeMs}ms (max: ${maxRetryTimeMs}ms)`; logger.error({ totalAttempts, totalTimeMs, maxRetryTimeMs, lastError: lastError?.message, }, errorMsg); throw lastError || new Error(errorMsg); } exports.sendTransactionsJito = sendTransactionsJito;