I am trying to do a simple swap on Solana block chain and I have tried both Alchemy and Quicknode but the success rate of my swap is very low.. 2 out of three times it fails and I cant even figure a way to properly log the reason ofthe failure
below is my script:
const axios = require('axios');
const dotenv = require('dotenv');
const { Connection, Keypair, sendAndConfirmRawTransaction, VersionedTransaction, ComputeBudgetProgram, Transaction, TransactionInstruction, TransactionMessage, PublicKey } = require('@solana/web3.js');
const winston = require('winston');
require('winston-daily-rotate-file');
dotenv.config();
const ALCHEMY_RPC_ENDPOINT = process.env.ALCHEMY_RPC_ENDPOINT; // Alchemy's RPC endpoint
const QUICKNODE_ENDPOINT = process.env.QUICKNODE_ENDPOINT; // QuickNode's endpoint for fetching priority fees
const WALLET_PRIVATE_KEY = process.env.WALLET_PRIVATE_KEY;
const SOL_AMOUNT = 0.3 * 1e9; // Amount of SOL to swap in lamports
const MAX_RETRIES = 1; // Maximum number of retries for transactions
const SLIPPAGE_BPS = 1000; // Slippage in basis points (3%)
const DEFAULT_PRIORITY_FEE = 50000; // Default priority fee in microLamports
// Set up Winston logger
const transport = new winston.transports.DailyRotateFile({
filename: 'logs/application-%DATE%.log',
datePattern: 'YYYY-MM-DD',
zippedArchive: true,
maxSize: '20m',
maxFiles: '14d'
});
const logger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.printf(({ timestamp, level, message }) => `${timestamp} [${level}]: ${message}`)
),
transports: [
transport,
new winston.transports.Console()
]
});
async function getQuote(inputMint, outputMint, amount, slippageBps) {
const url = `https://quote-api.jup.ag/v6/quote?inputMint=${inputMint}&outputMint=${outputMint}&amount=${amount}&slippageBps=${slippageBps}`;
logger.info(`Fetching quote from: ${url}`);
try {
const response = await axios.get(url);
logger.info('Quote fetched successfully:', JSON.stringify(response.data));
return response.data;
} catch (error) {
logger.error('Error fetching quote:', error.response?.data || error.message);
return null;
}
}
async function checkTransactionStatus(connection, txid) {
try {
const confirmation = await connection.confirmTransaction(txid, 'confirmed');
logger.info(`Transaction confirmation response: ${JSON.stringify(confirmation)}`);
if (confirmation.value.err) {
logger.error(`Transaction failed with error: ${JSON.stringify(confirmation.value.err)}`);
throw new Error(`Transaction failed with error: ${JSON.stringify(confirmation.value.err)}`);
}
return confirmation;
} catch (error) {
logger.error(`Transaction status check failed: ${error.message}`);
throw new Error(`Transaction status check failed: ${error.message}`);
}
}
async function simulateTransaction(connection, transaction) {
try {
const simulation = await connection.simulateTransaction(transaction);
logger.info('Simulation result:', JSON.stringify(simulation));
if (simulation.value.err) {
logger.error('Simulation failed with error:', JSON.stringify(simulation.value.err));
logger.error('Simulation logs:', JSON.stringify(simulation.value.logs));
throw new Error(`Simulation failed with error: ${JSON.stringify(simulation.value.err)}`);
}
logger.info('Transaction simulation logs:', JSON.stringify(simulation.value.logs));
return simulation.value.unitsConsumed;
} catch (error) {
logger.error(`Transaction simulation failed: ${error.message}`, { error: error });
throw new Error(`Transaction simulation failed: ${error.message}`);
}
}
async function executeSwap(quoteResponse, payer, connection, priorityFee, computeUnitLimit) {
logger.info("Preparing to execute swap...");
const postData = {
quoteResponse: quoteResponse,
userPublicKey: payer.publicKey.toString(),
wrapAndUnwrapSol: true,
priorityFee: priorityFee
};
try {
const swapResponse = await axios.post('https://quote-api.jup.ag/v6/swap', postData, {
headers: { 'Content-Type': 'application/json' }
});
logger.info('Swap API response:', JSON.stringify(swapResponse.data));
const transactionBuffer = Buffer.from(swapResponse.data.swapTransaction, 'base64');
const transaction = VersionedTransaction.deserialize(transactionBuffer);
transaction.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
transaction.sign([payer]);
const unitsConsumed = await simulateTransaction(connection, transaction);
logger.info(`Units consumed by the transaction: ${unitsConsumed}`);
logger.info("Sending transaction...");
let txid = null;
let attempt = 0;
while (attempt < MAX_RETRIES) {
try {
txid = await sendAndConfirmRawTransaction(connection, transaction.serialize(), {
skipPreflight: true,
preflightCommitment: 'confirmed'
});
logger.info(`Transaction sent, ID: ${txid}`);
const status = await checkTransactionStatus(connection, txid);
logger.info(`Transaction status: ${JSON.stringify(status)}`);
return txid;
} catch (error) {
logger.error(`Attempt ${attempt + 1} failed: ${error.message}`, { error: error });
attempt++;
}
}
throw new Error(`Swap failed after ${MAX_RETRIES} attempts.`);
} catch (error) {
logger.error('Swap execution failed:', error.response?.data || error.message);
return null;
}
}
async function getSimulationUnits(connection, instructions, payer) {
const testInstructions = [
ComputeBudgetProgram.setComputeUnitLimit({ units: 1_400_000 }),
...instructions,
];
const testVersionedTxn = new VersionedTransaction(
new TransactionMessage({
instructions: testInstructions,
payerKey: payer,
recentBlockhash: (await connection.getLatestBlockhash()).blockhash,
}).compileToV0Message()
);
const simulation = await connection.simulateTransaction(testVersionedTxn, {
replaceRecentBlockhash: true,
sigVerify: false,
});
if (simulation.value.err) {
logger.error('Simulation failed with error:', JSON.stringify(simulation.value.err));
return undefined;
}
return simulation.value.unitsConsumed;
}
async function startSwap() {
let useQuickNode = true;
while (true) {
try {
const mintAddress = '43uhykFm8Y9gLvHrWs7r7w1HCKu6vikDi7j394FaSfNz'; // Hardcoded mint address
const quote = await getQuote('So11111111111111111111111111111111111111112', mintAddress, SOL_AMOUNT, SLIPPAGE_BPS);
if (!quote) {
logger.error('Failed to fetch quote. Aborting swap.');
continue;
}
const privateKeyArray = JSON.parse(WALLET_PRIVATE_KEY);
const payer = Keypair.fromSecretKey(Uint8Array.from(privateKeyArray));
const connection = new Connection(useQuickNode ? QUICKNODE_ENDPOINT : ALCHEMY_RPC_ENDPOINT, 'confirmed');
logger.info(`Swapping ${SOL_AMOUNT / 1e9} SOL for token ${mintAddress}`);
const selectedPriorityFee = DEFAULT_PRIORITY_FEE;
logger.info(`Selected priority fee: ${selectedPriorityFee}`);
// Fetch the instructions to include in the simulation
const instructions = [
// Add your necessary instructions here
];
const unitsConsumed = await getSimulationUnits(connection, instructions, payer.publicKey);
logger.info(`Units consumed in the simulation: ${unitsConsumed}`);
if (unitsConsumed) {
const computeUnitLimit = Math.ceil(unitsConsumed * 1.05); // Adding a margin of error
logger.info(`Setting compute unit limit to: ${computeUnitLimit}`);
const priorityFeeInstruction = ComputeBudgetProgram.setComputeUnitPrice({
microLamports: selectedPriorityFee,
});
const computeUnitLimitInstruction = ComputeBudgetProgram.setComputeUnitLimit({
units: computeUnitLimit,
});
instructions.push(priorityFeeInstruction);
instructions.push(computeUnitLimitInstruction);
const transaction = new Transaction().add(...instructions);
transaction.feePayer = payer.publicKey;
transaction.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
transaction.sign(payer);
const txid = await executeSwap(quote, payer, connection, selectedPriorityFee, computeUnitLimit);
if (txid) {
logger.info('Swap successful:', txid);
break;
} else {
logger.error('Swap failed.');
}
} else {
logger.error('Failed to simulate transaction. Aborting swap.');
}
} catch (error) {
logger.error('An unexpected error occurred:', error);
}
useQuickNode = !useQuickNode; // Alternate between QuickNode and Alchemy
}
}
startSwap();
the code does have a success rate but 2 out of three times it fails . I want to have near to 100 percent success rate even if it means increasing the priority fee
I get the following error
2024-07-28T19:47:41.058Z [info]: Fetching quote from: https://quote-api.jup.ag/v6/quote?inputMint=43uhykFm8Y9gLvHrWs7r7w1HCKu6vikDi7j394FaSfNz&outputMint=So11111111111111111111111111111111111111112&amount=300000000&slippageBps=1000&swapMode=ExactOut
2024-07-28T19:47:42.036Z [info]: Quote fetched successfully:
2024-07-28T19:47:42.039Z [info]: Swapping token 43uhykFm8Y9gLvHrWs7r7w1HCKu6vikDi7j394FaSfNz for 0.3 SOL
2024-07-28T19:47:42.039Z [info]: Selected priority fee: 500000
2024-07-28T19:47:43.099Z [info]: Units consumed in the simulation: 150
2024-07-28T19:47:43.099Z [info]: Setting compute unit limit to: 158
2024-07-28T19:47:43.301Z [info]: Preparing to execute swap...
2024-07-28T19:47:44.160Z [info]: Swap API response:
2024-07-28T19:47:44.631Z [info]: Simulation result:
2024-07-28T19:47:44.631Z [info]: Transaction simulation logs:
2024-07-28T19:47:44.631Z [info]: Units consumed by the transaction: 108149
2024-07-28T19:47:44.631Z [info]: Sending transaction...
2024-07-28T19:48:15.124Z [error]: Attempt 1 failed: Transaction was not confirmed in 30.00 seconds. It is unknown if it succeeded or failed. Check signature 2hP6XxMeuhY5w3Vw4MPjt3h76mgJ3rdNQByoPKSeX9pijJg3wAKBWd9ig5VxLKP1BXVR11i69viurrLjApPHpmxD using the Solana Explorer or CLI tools.
2024-07-28T19:48:15.128Z [error]: Swap execution failed:
2024-07-28T19:48:15.128Z [error]: Swap failed.
please help me figure out what is wrong