// Solana WebSocket URL
const WS_URL = process.env.SOLANA_WS_URL || 'https://api.mainnet-beta.solana.com/';
const connection = new Connection(WS_URL, 'confirmed');
const RAYDIUM_AMM_PROGRAM_ID = new PublicKey(process.env.RAYDIUM_AMM_PROGRAM_ID);
async function subscribeRaydium() {
console.log("Listening for new Raydium LP transactions...");
connection.onLogs(RAYDIUM_AMM_PROGRAM_ID, async (log) => {
try {
if (log.logs.some(line => line.includes('InitializeInstruction2') || line.includes('CreatePool'))) {
console.log("New AMM LP transaction found!");
const signature = log.signature;
const tokenData = await processRaydiumLpTransaction(connection, signature);
if (tokenData) {
const sniperConfig = {
baseToken: process.env.BASE_TOKEN,
targetToken: tokenData.coinMint,
buyAmount: parseFloat(process.env.BUY_AMOUNT) || 1,
sellTargetPrice: parseFloat(process.env.SELL_TARGET_PRICE) || 2,
tokenData: tokenData
};
console.log(`Launching sniper for token ${sniperConfig.targetToken} with buy amount ${sniperConfig.buyAmount}`);
SniperManager.addSniper(sniperConfig);
}
}
} catch (error) {
console.error("Error processing log:", error.message);
}
}, 'confirmed');
}
// Asynchronous function to process LP transactions on Raydium
async function processRaydiumLpTransaction(connection, signature) {
try {
// Fetch transaction details by its signature
const transactionDetails = await connection.getTransaction(signature, {
commitment: 'confirmed',
maxSupportedTransactionVersion: 0,
});
console.log("--------------------------------",transactionDetails,"--------------------------");
// Check if transaction details were found
if (!transactionDetails) {
console.error('No transaction details found for signature:', signature);
return; // Exit the function if no details are found
}
// Extract the message from the transaction
const message = transactionDetails.transaction?.message;
console.log("transactionDetails.transaction?.message")
// Check for the presence of message and accountKeys array
if (!message || !Array.isArray(message.staticAccountKeys)) {
console.error("accountKeys is undefined or not an array");
return; // Exit the function if accountKeys is missing or not an array
}
console.log("Transaction Message:", message);
// Convert account keys to string format
const accounts = message.staticAccountKeys.map(key => key.toString()) || [];
// Check if account keys are present
if (accounts.length === 0) {
console.error("No account keys found.");
return; // Exit the function if no account keys are found
}
console.log("Accounts:", accounts);
// Check for the presence of instructions in the message
if (!message.instructions) {
console.warn("Instructions are missing in this transaction.");
return; // Exit the function if instructions are missing
}
// Loop through all instructions in the message
for (const ix of message.instructions) {
// Check if programIdIndex is within bounds of the accounts array
if (ix.programIdIndex >= accounts.length) {
console.error("programIdIndex out of bounds:", ix.programIdIndex);
continue; // Skip to the next iteration if the index is out of bounds
}
// Get the program ID from the accounts array
const programId = accounts[ix.programIdIndex];
// Check if the program is Raydium AMM and if instruction data is present
if (programId === RAYDIUM_AMM_PROGRAM_ID.toString() && ix.data.length > 0) {
// Extract token data from the instruction
const tokenData = extractTokenData(ix, accounts);
// If token data is successfully extracted, save it to MongoDB
if (tokenData) {
await saveToMongo(tokenData);
return tokenData; // Return the extracted data
}
}
}
} catch (error) {
// Log any errors that occur during processing
console.error('Error fetching/processing transaction:', error.message);
}
}
// Helper function to extract token data from instruction
function extractTokenData(ix, accounts) {
try {
// Extract various mint and account details from the instruction
const mint0 = accounts[ix.accounts[8]];
const mint1 = accounts[ix.accounts[9]];
const lpTokenMint = accounts[ix.accounts[7]];
const deployer = accounts[ix.accounts[17]];
const poolId = accounts[ix.accounts[4]];
const baseVault = accounts[ix.accounts[10]];
const quoteVault = accounts[ix.accounts[11]];
const ammAuthority = accounts[ix.accounts[5]];
const ammTarget = accounts[ix.accounts[13]];
const ammOpenOrder = accounts[ix.accounts[6]];
const marketProgram = accounts[ix.accounts[15]];
const marketId = accounts[ix.accounts[16]];
// Return an object containing the extracted token data
return {
programId: new PublicKey(accounts[ix.accounts[0]]).toString(),
ammId: new PublicKey(poolId).toString(),
ammAuthority: new PublicKey(ammAuthority).toString(),
ammOpenOrders: new PublicKey(ammOpenOrder).toString(),
lpMint: new PublicKey(lpTokenMint).toString(),
coinMint: new PublicKey(mint0).toString(),
pcMint: new PublicKey(mint1).toString(),
coinVault: new PublicKey(baseVault).toString(),
pcVault: new PublicKey(quoteVault).toString(),
ammTargetOrders: new PublicKey(ammTarget).toString(),
serumMarket: new PublicKey(marketId).toString(),
serumProgram: new PublicKey(marketProgram).toString(),
deployer: new PublicKey(deployer).toString()
};
} catch (error) {
// Log any errors that occur during token data extraction
console.error("Error extracting token data:", error.message);
return null; // Return null if extraction fails
}
}
That gets only staticAccountKeys, I need to accountkeys