Introducing RabbitStream⚡, earliest transaction detection from Solana Shreds with gRPC style filtering. Explore Now
shyft logo
Get API Key

Blogs

Dev Guides

Launching liquidity pools on Raydium with safeguarding strategy to counter bot manipulation (Part -1)

Shyft Logo

Team Shyft

· January 22, 2026

Ultimate guide to launch Raydium tokens and preventing price manipulation with pre-purchase strategies

Launching Liquidity Pools and getting the first swaps on Solana

Raydium is a decentralized exchange built on Solana, offering high-speed token swaps. By leveraging automated market makers (AMMs), users can efficiently trade various tokens without relying on centralized intermediaries.

However, new Liquidity Pools on Raydium always face the threat of trading bots manipulating the market, leading to artificial price spikes and followed by sudden dumps, which negatively impacts investor confidence. To prevent this,

In this article, we will explore a counter-acting strategy to this problem by making the initial purchases ourselves. This will mislead the bots into thinking the token is already too expensive and risky to buy, thereby adding price stability.

The entire code is available here on GitHub for you to follow along, feel free to clone the project and try it out.

Before Getting Started

Before diving into the implementation, it’s essential to have the following tools and libraries installed:

  • Solana CLI: For interacting with the Solana network.
  • Raydium SDK: To interact with the Raydium protocol.
  • Jito: For creating and sending Jito bundles.
  • Node.js and npm (or yarn): For project management and package installation.

Steps Involved — A summary

While the overall process might seem complex initially, the following steps will provide a clear understanding of each stage.

  1. Create Liquidity Pool Instruction: Generate the necessary instruction using the Raydium SDK to initiate the liquidity pool creation process.
  2. Determine Pool Address in Advance: Obtain the pool’s address in advance to facilitate subsequent token purchases within the same transaction.
  3. Address Lookup Tables: Optimize transaction size by creating references to frequently used addresses instead of including the entire address in each instruction.
  4. Jito Bundle: Package all generated instructions into a single Jito bundle. Jito bundles are a mechanism for grouping multiple transactions into a single, atomic operation, which ensures all the transactions within the bundle are fully executed or reverted if any part fails. They also require a small tip to prioritize the transaction processing.
  5. Send and Monitor Bundle: Transmit the bundle to the Jito network and continuously track its status, implementing retries if necessary.

Initialization — Setting up a NodeJS Project

To begin, create a new Node.js project and install the required dependencies:

npm install @solana/web3.js @raydium-io/raydium-sdk jito-solana typescript

To effectively interact with the Solana network and Raydium, we need to set up essential configuration parameters. Create a file named config.ts in your project directory and add the following code:

import {
  Connection,
  Keypair,
  PublicKey,
} from '@solana/web3.js';
import {
  ENDPOINT as _ENDPOINT,
  Currency,
  LOOKUP_TABLE_CACHE,
  MAINNET_PROGRAM_ID,
  RAYDIUM_MAINNET,
  Token,
  TOKEN_PROGRAM_ID,
  TxVersion,
} from '@raydium-io/raydium-sdk';

export const rpcUrl: string = 'A Jito RPC Node URL'
export const rpcToken: string | undefined = undefined

export const wallet = Keypair.fromSecretKey(
  new Uint8Array([
    ...key here
  ])
)
export const lpCreateWallet = new Keypair.fromSecretKey(new Uint8Array([...]));


export const connection = new Connection(
  rpcUrl,
  'confirmed'
)

export const PROGRAMIDS = MAINNET_PROGRAM_ID

export const ENDPOINT = _ENDPOINT

export const RAYDIUM_MAINNET_API = RAYDIUM_MAINNET

export const makeTxVersion = TxVersion.V0 // LEGACY

export const addLookupTableInfo = LOOKUP_TABLE_CACHE // only mainnet. other = undefined

These are mostly just configurations that are required to run the project. The rpcUrl takes in the url of an RPC node running Jito. wallet is your solana wallet which you will use to send transactions, and lpCreateWallet is the wallet that will create the Liquidity Pool. We’ll add more configuration details as needed throughout the guide.

Note: For security reasons, it’s highly recommended to use environment variables or a secure configuration management system to store private keys. Avoid hardcoding them directly in your code.

Now we will go on and define the token information. There are a few helper objects which can be imported from the Raydium SDK, in order to define these:

//continuing the config.ts

export const DEFAULT_TOKEN = {
  SOL: new Currency(9, "USDC", "USDC"),
  WSOL: new Token(
    TOKEN_PROGRAM_ID,
    new PublicKey("So11111111111111111111111111111111111111112"),
    9,
    "WSOL",
    "WSOL"
  ),
  USDC: new Token(
    TOKEN_PROGRAM_ID,
    new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"),
    6,
    "USDC",
    "USDC"
  ),
};

The token class imported from Raydium SDK has been used to define the tokens involved. SOL is the quote mint being used for this example, which is generally a part of most swaps on the platform. The base mint token used here is USDC, however you can replace its details with the token you want to swap. Once successfully initialized, we move on towards the swapping process.

The Pool Creation and Swapping Process

Once we have established the total configuration required for the process to run, we now move forward with the actual pool creation and swapping process.

This will be the starting point of the actual process, and for that we will define this inside index.ts file in the root directory of the project.

import { TokenAmount } from "@raydium-io/raydium-sdk";
import { DEFAULT_TOKEN, connection, wallet } from "./config";
import { getWalletTokenAccount } from "./utils";
import BN from "bn.js";
import { createPoolIx } from "./lpCreate";
import { PublicKey } from "@solana/web3.js";
import createLookupTable from "./createLookupTable";
import createSwapIx from "./swapCreate";
import submitJitoBundle from "./submitJitoBundle";

async function main() {
.....//rest of the code

Token and Amount Definitions


Within the main function, define the base and quote tokens for the liquidity pool:

const inputToken = DEFAULT_TOKEN.WSOL; // replace with base token
const outputToken = DEFAULT_TOKEN.USDC; // replace with quote token

const createLpBaseAmount = new BN(100000000000000);  //amount of base token
const createLpQuoteAmount = new BN(100000000000000); //amount of quote

The input and output token here are defined in the config.ts file, and you can use your own tokens as per requirement.

OpenBook Market ID and Swap Amount

Obtain the OpenBook market ID corresponding to your desired token pair (not covered in this guide). Specify the initial swap amount using the TokenAmount class from the Raydium SDK:

// Openbook market ID
const marketId = "marketId";
const inputTokenAmount = new TokenAmount(inputToken, 10000); // Amount of SOL to use per swap

For this example, we are setting 10000 (in lamports) as an arbtitrary account for first N Swaps.

Fetching Wallet Token Accounts

Raydium SDK functions uses TokenAccount objects, so we need a tool to convert Solana Wallets to TokenAccount Objects. The following utility function does the above specified task (defined in utils.ts under src/)

export async function getWalletTokenAccount(
  connection: Connection,
  wallet: PublicKey
): Promise<TokenAccount[]> {
  const walletTokenAccount = await connection.getTokenAccountsByOwner(wallet, {
    programId: TOKEN_PROGRAM_ID,
  });
  return walletTokenAccount.value.map((i) => ({
    pubkey: i.pubkey,
    programId: i.account.owner,
    accountInfo: SPL_ACCOUNT_LAYOUT.decode(i.account.data),
  }));
}

This function retrieves token accounts associated with the specified wallet address.

Creating Liquidity Pool Instructions

Since we have already setup a wallet token account enumerator (in the previous step), we can now dive into the code of Create Pool instruction:

  1. Fetch necessary account information: Retrieve relevant account data for the wallet, tokens, and OpenBook market.
  2. Construct liquidity pool instructions: Generate the instructions required for creating the pool and transferring initial liquidity.
  3. Handle potential errors and edge cases: Implement robust error handling to prevent unexpected issues.

Implementing the createPoolIx Function

Let’s expand on the createPoolIx function introduced in the previous section:

import {
  LOOKUP_TABLE_CACHE,
  Liquidity,
  LiquidityPoolKeys,
  MAINNET_PROGRAM_ID,
  MARKET_STATE_LAYOUT_V3,
  Percent,
  TokenAccount,
  TokenAmount,
  TxVersion,
  jsonInfo2PoolKeys,
  InnerSimpleV0Transaction,
  LiquidityPoolKeysV4,
} from "@raydium-io/raydium-sdk";
import { getComputeBudgetConfig, getWalletTokenAccount } from "./utils";
import { DEFAULT_TOKEN, connection } from "./config";
import {
  Keypair,
  PublicKey,
  PublicKeyInitData,
  TransactionMessage,
  VersionedTransaction,
} from "@solana/web3.js";
import { unpackMint } from "@solana/spl-token";
import BN from "bn.js";

const inputToken = DEFAULT_TOKEN.WSOL; // USDC
const outputToken = DEFAULT_TOKEN.USDC; // RAY

interface createPoolIxReturnType {
  poolKeys: LiquidityPoolKeysV4;
  createPoolTx: VersionedTransaction;
}

// openbook market id

const marketId = "marketId here";

// raydium create pool instructions
export async function createPoolIx(
  marketId: PublicKey,
  wallet: Keypair,
  tokenAccounts: TokenAccount[],
  baseMint: PublicKey,
  quoteMint: PublicKey,
  baseAmount: BN,
  quoteAmount: BN
): Promise<void | createPoolIxReturnType> {

The createPoolIx function requires specific inputs: OpenBook market ID, LP creator wallet, token account information, base and quote mint details, and desired token amounts. It returns either a set of pool keys and a transaction, or an error. To construct the necessary pool keys, we must perform on-chain lookups.

const tokenAccountInfo = await getWalletTokenAccount(
    connection,
    wallet.publicKey
  );
  const marketBufferInfo = await connection.getAccountInfo(marketId);
  if (!marketBufferInfo) throw Error("no marketBufferInfo");
  const {
    baseVault: marketBaseVault,
    quoteVault: marketQuoteVault,
    bids: marketBids,
    asks: marketAsks,
    eventQueue: marketEventQueue,
  } = MARKET_STATE_LAYOUT_V3.decode(marketBufferInfo.data);
  console.log("Base mint: ", baseMint.toString());
  console.log("Quote mint: ", quoteMint.toString());

  const accountInfo_base = await connection.getAccountInfo(baseMint);
  if (!accountInfo_base) throw Error("no accountInfo_base");
  const baseTokenProgramId = accountInfo_base.owner;
  const baseDecimals = unpackMint(
    baseMint,
    accountInfo_base,
    baseTokenProgramId
  ).decimals;
  console.log("Base Decimals: ", baseDecimals);

We extract essential data from the OpenBook market account using the MARKET_STATE_LAYOUT_V3 decoder. This is basically an account layout, which helps us to decode the OpenBook account data. This information, combined with token details, is used to create a comprehensive pool keys object.

This is pretty much the first few steps of how we can get started with pool creation process, and the first steps. Do checkout the next part of this article where we go on to complete the create pool function and setting up the swaps using Jito bundle.

Up Next: Launching liquidity pool on Raydium and Safeguarding Strategies to Counter Bot Manipulation — Part 2

Resources

Arb Bot
Liquidity Bot
Liquidity Pool
Sniper Bot
Solana gRPC Network
SPL Token

Related Posts

How to reconnect and replay slots with Solana Yellowstone gRPC
Shyft

How to reconnect and replay slots with Solana Yellowstone gRPC

In this article you will learn how to implement a reconnect logic for your Solana gRPC streams with replay functionality...

January 24, 2026

How to modify Solana Yellowstone gRPC subscribe requests without disconnecting
Shyft

How to modify Solana Yellowstone gRPC subscribe requests without disconnecting

Learn how to modify your yellowstone gRPC Subscribe Requests on Solana without stopping your stream or losing data ...

January 24, 2026

Real-Time Solana Data Streaming with gRPC: Accounts, Transactions, Blocks
Shyft

Real-Time Solana Data Streaming with gRPC: Accounts, Transactions, Blocks

A comprehensive guide on how to stream Transactions, Accounts, and Block updates swiftly using Shyft’s gRPC Services ...

January 22, 2026

Get in touch with our discord community and keep up with the latest feature
releases. Get help from our developers who are always here to help you take off.

GithubTwitterLinked inDiscordTelegramBlogsBlogs

Products

RabbitStreamgRPC NetworkSuperIndexerSolana APIs
Contact Us|Email: genesis@shyft.to