mirror of
https://github.com/fdundjer/solana-sniper-bot.git
synced 2025-11-10 04:22:05 +10:00
132 lines
4.7 KiB
TypeScript
132 lines
4.7 KiB
TypeScript
import {
|
|
BlockhashWithExpiryBlockHeight,
|
|
Keypair,
|
|
PublicKey,
|
|
SystemProgram,
|
|
Connection,
|
|
TransactionMessage,
|
|
VersionedTransaction,
|
|
} from '@solana/web3.js';
|
|
import { TransactionExecutor } from './transaction-executor.interface';
|
|
import { logger } from '../helpers';
|
|
import axios, { AxiosError } from 'axios';
|
|
import bs58 from 'bs58';
|
|
import { Currency, CurrencyAmount } from '@raydium-io/raydium-sdk';
|
|
|
|
export class JitoTransactionExecutor implements TransactionExecutor {
|
|
// https://jito-labs.gitbook.io/mev/searcher-resources/json-rpc-api-reference/bundles/gettipaccounts
|
|
private jitpTipAccounts = [
|
|
'Cw8CFyM9FkoMi7K7Crf6HNQqf4uEMzpKw6QNghXLvLkY',
|
|
'DttWaMuVvTiduZRnguLF7jNxTgiMBZ1hyAumKUiL2KRL',
|
|
'96gYZGLnJYVFmbjzopPSU6QiEV5fGqZNyN9nmNhvrZU5',
|
|
'3AVi9Tg9Uo68tJfuvoKvqKNWKkC5wPdSSdeBnizKZ6jT',
|
|
'HFqU5x63VTqvQss8hp11i4wVV8bD44PvwucfZ2bU7gRe',
|
|
'ADaUMid9yfUytqMBgopwjb2DTLSokTSzL1zt6iGPaS49',
|
|
'ADuUkR4vqLUMWXxW9gh6D6L8pMSawimctcNZ5pGwDcEt',
|
|
'DfXygSm4jCyNCybVYYK6DwvWqjKee8pbDmJGcLWNDXjh',
|
|
];
|
|
|
|
private JitoFeeWallet: PublicKey;
|
|
|
|
constructor(
|
|
private readonly jitoFee: string,
|
|
private readonly connection: Connection,
|
|
) {
|
|
this.JitoFeeWallet = this.getRandomValidatorKey();
|
|
}
|
|
|
|
private getRandomValidatorKey(): PublicKey {
|
|
const randomValidator = this.jitpTipAccounts[Math.floor(Math.random() * this.jitpTipAccounts.length)];
|
|
return new PublicKey(randomValidator);
|
|
}
|
|
|
|
public async executeAndConfirm(
|
|
transaction: VersionedTransaction,
|
|
payer: Keypair,
|
|
latestBlockhash: BlockhashWithExpiryBlockHeight,
|
|
): Promise<{ confirmed: boolean; signature?: string }> {
|
|
logger.debug('Starting Jito transaction execution...');
|
|
this.JitoFeeWallet = this.getRandomValidatorKey(); // Update wallet key each execution
|
|
logger.trace(`Selected Jito fee wallet: ${this.JitoFeeWallet.toBase58()}`);
|
|
|
|
try {
|
|
const fee = new CurrencyAmount(Currency.SOL, this.jitoFee, false).raw.toNumber();
|
|
logger.trace(`Calculated fee: ${fee} lamports`);
|
|
|
|
const jitTipTxFeeMessage = new TransactionMessage({
|
|
payerKey: payer.publicKey,
|
|
recentBlockhash: latestBlockhash.blockhash,
|
|
instructions: [
|
|
SystemProgram.transfer({
|
|
fromPubkey: payer.publicKey,
|
|
toPubkey: this.JitoFeeWallet,
|
|
lamports: fee,
|
|
}),
|
|
],
|
|
}).compileToV0Message();
|
|
|
|
const jitoFeeTx = new VersionedTransaction(jitTipTxFeeMessage);
|
|
jitoFeeTx.sign([payer]);
|
|
|
|
const jitoTxsignature = bs58.encode(jitoFeeTx.signatures[0]);
|
|
|
|
// Serialize the transactions once here
|
|
const serializedjitoFeeTx = bs58.encode(jitoFeeTx.serialize());
|
|
const serializedTransaction = bs58.encode(transaction.serialize());
|
|
const serializedTransactions = [serializedjitoFeeTx, serializedTransaction];
|
|
|
|
// https://jito-labs.gitbook.io/mev/searcher-resources/json-rpc-api-reference/url
|
|
const endpoints = [
|
|
'https://mainnet.block-engine.jito.wtf/api/v1/bundles',
|
|
'https://amsterdam.mainnet.block-engine.jito.wtf/api/v1/bundles',
|
|
'https://frankfurt.mainnet.block-engine.jito.wtf/api/v1/bundles',
|
|
'https://ny.mainnet.block-engine.jito.wtf/api/v1/bundles',
|
|
'https://tokyo.mainnet.block-engine.jito.wtf/api/v1/bundles',
|
|
];
|
|
|
|
const requests = endpoints.map((url) =>
|
|
axios.post(url, {
|
|
jsonrpc: '2.0',
|
|
id: 1,
|
|
method: 'sendBundle',
|
|
params: [serializedTransactions],
|
|
}),
|
|
);
|
|
|
|
logger.trace('Sending transactions to endpoints...');
|
|
const results = await Promise.all(requests.map((p) => p.catch((e) => e)));
|
|
|
|
const successfulResults = results.filter((result) => !(result instanceof Error));
|
|
|
|
if (successfulResults.length > 0) {
|
|
logger.trace(`At least one successful response`);
|
|
logger.debug(`Confirming jito transaction...`);
|
|
return await this.confirm(jitoTxsignature, latestBlockhash);
|
|
} else {
|
|
logger.debug(`No successful responses received for jito`);
|
|
}
|
|
|
|
return { confirmed: false };
|
|
} catch (error) {
|
|
if (error instanceof AxiosError) {
|
|
logger.trace({ error: error.response?.data }, 'Failed to execute jito transaction');
|
|
}
|
|
logger.error('Error during transaction execution', error);
|
|
return { confirmed: false };
|
|
}
|
|
}
|
|
|
|
private async confirm(signature: string, latestBlockhash: BlockhashWithExpiryBlockHeight) {
|
|
const confirmation = await this.connection.confirmTransaction(
|
|
{
|
|
signature,
|
|
lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
|
|
blockhash: latestBlockhash.blockhash,
|
|
},
|
|
this.connection.commitment,
|
|
);
|
|
|
|
return { confirmed: !confirmation.value.err, signature };
|
|
}
|
|
}
|