1
// 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

1
  • message: MessageV0 { header: [Object], staticAccountKeys: [Array], recentBlockhash: 'FZJWcGc9AQsHDbNhKw3eQakeg8rpDHL2YUVinXi2P4LH', compiledInstructions: [Array], addressTableLookups: [Array] }, Where is accountKeys
    – Mmm Mmms
    Commented Nov 1 at 10:43

1 Answer 1

1

The accountKeys field is renamed to staticAccountKeys in web3.js, so just look at staticAccountKeys.

Here's the code that changes the field name: https://github.com/solana-labs/solana-web3.js/blob/a240574ec6f0776e002fcb64a3d5af8b27e27e4d/src/connection.ts#L479

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.