How to Monitor New Solana Raydium V4 Liquidity Pool Creation

·

Monitoring new liquidity pools on Raydium V4 on the Solana blockchain can provide valuable insights for developers and traders. This guide explains a method to listen for and parse transactions related to new pool creation, specifically those involving the initialize2 method. By following this approach, you can obtain details like paired token names and initial deposit amounts, which can be extended to gather more pool information.

Core Concepts and Approach

The process involves two main steps: listening for specific transaction logs on the Raydium V4 program and then parsing those transactions to extract relevant pool data. This method leverages Solana's Web3.js library and other tools to interact with the blockchain and decode transaction information.

Understanding liquidity pool creation is crucial for those involved in decentralized finance (DeFi) on Solana. New pools often represent emerging trading pairs or new token launches, making timely detection valuable for market analysis and automated trading strategies.

Step 1: Listening to Raydium V4 Logs

To detect new pool creations, you need to monitor logs from the Raydium Liquidity Pool V4 program address. The key is to filter transactions that contain the initialize2 method call, which is typically associated with pool initialization.

Here is a conceptual overview of the code setup required:

const connection = new solanaWeb3.Connection('{RPC_ENDPOINT}', 'confirmed');
const raydiumV4Address = '675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8';
const raydiumV4PublicKey = new solanaWeb3.PublicKey(raydiumV4Address);

connection.onLogs(
  raydiumV4PublicKey,
  ({ logs, err, signature }) => {
    if (err) return;
    if (logs && logs.some(log => log.includes("initialize2"))) {
      console.log("Signature for 'initialize2':", signature);
    }
  },
  "confirmed"
);

Replace {RPC_ENDPOINT} with your preferred Solana RPC provider URL. This script will output transaction signatures for every initialize2 invocation, which you can then use to fetch and parse the full transaction details.

Step 2: Parsing the Transaction

Once you have a transaction signature, the next step is to retrieve and parse the transaction to extract pool information. This involves decoding the instruction data and fetching account details from the transaction.

Fetching Transaction Details

Use the obtained signature to get the parsed transaction:

const tx = await connection.getParsedTransaction(
  signature,
  {
    maxSupportedTransactionVersion: 0,
    commitment: 'confirmed'
  });

Extracting Account Information

From the transaction instructions, identify the accounts involved. The liquidity pool account and the two token accounts are at specific indices:

const accounts = tx?.transaction.message.instructions.find(ix => ix.programId.toBase58() === raydiumV4Address).accounts;
const LPIndex = 4;
const tokenAIndex = 8;
const tokenBIndex = 9;
const LPAccount = accounts[LPIndex]
const tokenAAccount = accounts[tokenAIndex];
const tokenBAccount = accounts[tokenBIndex];

Fetching Token Metadata

To get token names and decimals, fetch the token mint information and metadata:

async function fetchTokenInfo(tokenPublicKey){
  const mintAddress = new solanaWeb3.PublicKey(tokenPublicKey);
  const mintInfo = await splToken.getMint(connection, mintAddress);
  let metadataPda = await deprecated.Metadata.getPDA(mintAddress);
  let metdadataContent = await Metadata.fromAccountAddress(connection, metadataPda);
  return [metdadataContent.data.name, mintInfo.decimals];
}
const tokenA = await fetchTokenInfo(tokenAAccount.toBase58());
const tokenB = await fetchTokenInfo(tokenBAccount.toBase58());

Decoding Instruction Data

The instruction data contains details like initial amounts and open time. Decode it using a buffer layout:

const instructionData = bs58.decode(tx?.transaction.message.instructions.find(ix => ix.programId.toBase58() === raydiumV4Address).data);
const RAYDIUM_INSTRUCTION_LAYOUT = struct([
  u8('discriminator'),
  u8('nonce'),
  nu64('opentime'),
  nu64('initPcAmount'),
  nu64('initCoinAmount')
]);
const decodedInstruction = RAYDIUM_INSTRUCTION_LAYOUT.decode(instructionData);

The opentime field may represent a Unix timestamp for scheduled openings or zero for immediate access.

Displaying the Results

Finally, log the extracted information in a readable format:

console.log(`TX: https://solscan.io/tx/${signature}`);
const displayData = [
  { "Token": tokenA[0].replace(/\x00/g, ''), "Account Public Key": tokenAAccount.toBase58(), "Amount": decodedInstruction.initCoinAmount/Math.pow(10, tokenA[1]) },
  { "Token": tokenB[0].replace(/\x00/g, ''), "Account Public Key": tokenBAccount.toBase58(), "Amount": decodedInstruction.initPcAmount/Math.pow(10, tokenB[1]) }
];
console.log(`New LP: ${LPAccount.toBase58()}`)
console.table(displayData);

This will output the new liquidity pool address, the tokens involved, and their initial amounts.

Complete Code Example

Below is a consolidated version of the code that combines both listening and parsing steps. Ensure you have the necessary Node.js packages installed before running.

const solanaWeb3 = require('@solana/web3.js');
const splToken = require('@solana/spl-token');
const { Metadata, deprecated } = require('@metaplex-foundation/mpl-token-metadata');
const bs58 = require('bs58');
const { struct, u8, nu64 } = require('@solana/buffer-layout');

const connection = new solanaWeb3.Connection('http://your-rpc-endpoint', 'confirmed');
const raydiumV4Address = '675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8'
const raydiumV4PublicKey = new solanaWeb3.PublicKey(raydiumV4Address);

async function main() {
  connection.onLogs(
    raydiumV4PublicKey,
    ({ logs, err, signature }) => {
      if (err) return;
      if (logs && logs.some(log => log.includes("initialize2"))) {
        fetchPoolInfo(signature, connection);
      }
    },
    "confirmed"
  );
}

async function fetchPoolInfo(signature, connection) {
  const tx = await connection.getParsedTransaction( signature, { maxSupportedTransactionVersion: 0, commitment: 'confirmed' });
  const accounts = tx?.transaction.message.instructions.find(ix => ix.programId.toBase58() === raydiumV4Address).accounts;
  
  const LPIndex = 4;
  const tokenAIndex = 8;
  const tokenBIndex = 9;
  const LPAccount = accounts[LPIndex]
  const tokenAAccount = accounts[tokenAIndex];
  const tokenBAccount = accounts[tokenBIndex];

  const tokenA = await fetchTokenInfo(tokenAAccount.toBase58());
  const tokenB = await fetchTokenInfo(tokenBAccount.toBase58());

  const instructionData = bs58.decode(tx?.transaction.message.instructions.find(ix => ix.programId.toBase58() === raydiumV4Address).data);
  const RAYDIUM_INSTRUCTION_LAYOUT = struct([
    u8('discriminator'),
    u8('nonce'),
    nu64('opentime'),
    nu64('initPcAmount'),
    nu64('initCoinAmount')
  ]);
  const decodedInstruction = RAYDIUM_INSTRUCTION_LAYOUT.decode(instructionData);

  console.log(`TX: https://solscan.io/tx/${signature}`);
  const displayData = [
    { "Token": tokenA[0].replace(/\x00/g, ''), "Account Public Key": tokenAAccount.toBase58(), "Amount": decodedInstruction.initCoinAmount/Math.pow(10, tokenA[1]) },
    { "Token": tokenB[0].replace(/\x00/g, ''), "Account Public Key": tokenBAccount.toBase58(), "Amount": decodedInstruction.initPcAmount/Math.pow(10, tokenB[1]) }
  ];
  console.log(`New LP: ${LPAccount.toBase58()}`);
  console.table(displayData);
}

async function fetchTokenInfo(tokenPublicKey){
  const mintAddress = new solanaWeb3.PublicKey(tokenPublicKey);
  const mintInfo = await splToken.getMint(connection, mintAddress);
  let metadataPda = await deprecated.Metadata.getPDA(mintAddress);
  let metdadataContent = await Metadata.fromAccountAddress(connection, metadataPda);
  return [metdadataContent.data.name, mintInfo.decimals];
}

main().catch(console.error);

Remember to replace the RPC endpoint with a valid one and handle any potential errors in a production environment.

Applications and Next Steps

This monitoring technique can be the foundation for more advanced DeFi tools. For instance, you could build a real-time alert system for new pools, analyze initial liquidity conditions, or integrate with trading bots. The parsed data can also be stored for historical analysis and trend identification.

👉 Explore more strategies for blockchain monitoring

Understanding the structure of Solana transactions and the Raydium program is key to adapting this code for other purposes. Always refer to the latest program documentation and updates, as indices and data structures might change.

Frequently Asked Questions

What is the Raydium V4 program address?
The Raydium Liquidity Pool V4 program address on Solana is 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8. This is used to identify transactions related to pool creation and management on the Raydium decentralized exchange.

Why monitor new liquidity pools?
New pools often indicate new token listings or trading pairs. Monitoring them in real-time allows traders and developers to react quickly to market opportunities, such as early investment chances or arbitrage possibilities.

Can this method be used for other DEXs on Solana?
The general approach of listening to program logs and parsing transactions is applicable to other decentralized exchanges on Solana. However, the specific program address, account indices, and instruction layouts will differ, requiring adjustments to the code.

How reliable is this method?
This method relies on the public Solana RPC nodes and the consistency of the Raydium program's logging. While generally reliable, network latency or RPC issues might cause missed transactions. Using a dedicated RPC provider can improve reliability.

What are the common challenges?
Challenges include handling RPC rate limits, decoding complex instruction data, and managing the volume of transactions on a busy network. Efficient code and error handling are essential for robust operation.

Can I get more information than just token names and amounts?
Yes, the transaction contains a wealth of data. By expanding the parsing logic, you can extract additional details like pool fees, creator information, or even integrate with price oracle data for deeper analysis.