@pythnetwork/solana-utils
Version:
Utility functions for Solana
94 lines (93 loc) • 4.15 kB
JavaScript
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;
;