Skip to main content
What this does. Creates a new CLMM pool at the fee tier of your choice, then opens an initial concentrated position. Two transactions, one script. Code is lifted from the official demos in raydium-sdk-V2-demo/src/clmm and adapted to a single Node-runnable file.

Setup

Make sure you’ve read the Quick start prerequisites and have RPC_URL, KEYPAIR, and the deps installed. CLMM pool creation has a one-time fee plus per-tick-array rent for the initial position. You’ll also need both seed mints in your wallet — opening a position when the price sits inside the chosen range requires liquidity on both sides.

Step 1 — config.ts

Save as config.ts. This is the same shape as the demo repo’s src/config.ts.templatedisableFeatureCheck is forced to true (recommended for any non-trivial integration so the SDK does not block on its startup feature-detect call):

Step 2 — createPool.ts

Save alongside config.ts. Source: src/clmm/createPool.ts.

Step 3 — createPosition.ts

Source: src/clmm/createPosition.ts.

Step 4 — utils.ts

Source: src/clmm/utils.ts.

Run it

What just happened

Transaction 1 — raydium.clmm.createPool initialized:
  • the pool state at the canonical PDA for (mint1, mint2, ammConfig),
  • token_0_vault and token_1_vault (sorted by mint byte order),
  • the observation ring buffer,
  • the inline tick-array bitmap,
and set the initial sqrt_price_x64 from your initialPrice. Transaction 2 — raydium.clmm.openPositionFromBase opened a concentrated position:
  • minted a position NFT to your wallet (the NFT is the position; transferring it transfers the position),
  • allocated tick arrays at the lower and upper bounds (one-time rent if first position in those ranges; tick arrays are never closed by the program, so subsequent positions in the same arrays pay no extra rent),
  • deposited inputAmount of mint1 and the matching pair amount of mint2 (computed by PoolUtils.getLiquidityAmountOutFromAmountIn),
  • credited the position with liquidity proportional to the range width.
The narrower the range, the higher the capital efficiency per dollar of TVL — and the more painful the impermanent loss when price drifts out of range. The range used above ([0.000001, 100000]) is effectively full-range; tighten it to concentrate fees near current spot.

Picking a fee tier

clmmConfigs[0] is the lowest-fee tier. The full set is published at GET https://api-v3.raydium.io/main/clmm-config: See user-flows/choosing-a-pool-type for a full decision matrix.

Common errors

  • Pool already exists for this config — A CLMM pool already exists for this (mint1, mint2, ammConfig) triple. Look up the existing pool ID and skip Step 2.
  • Insufficient funds for amount B — Your wallet has the requested amount of mintA but not the matching mintB. Opening a position when the price sits inside the range requires liquidity on both sides.
  • Tick out of range — Your lowerPrice or upperPrice falls outside the representable price range. Use a more reasonable range relative to current price.
  • Stale price — A quote from the API can be 5–60 seconds stale. If executePosition fails on slippage, uncomment the getRpcClmmPoolInfo block in createPosition.ts to re-fetch the live price right before signing.

Caveats

  • Position NFT is your only handle. Lose the NFT or transfer it, lose access to the position. Treat it like a key.
  • Out-of-range positions earn no fees. If price moves outside [lowerPrice, upperPrice], your position is parked entirely in one asset and earns nothing until you rebalance.
  • Tick array rent is one-way. The first position to touch a never-initialised tick array pays its rent; the program does not expose a path to close tick arrays, so that rent is permanent. Subsequent positions in the same array are free.

Next

Sources: