Version banner. All demos target
@raydium-io/raydium-sdk-v2@0.2.42-alpha against Solana mainnet-beta, verified 2026-04. Program IDs come from reference/program-addresses via the SDK.Setup
raydium-sdk-V2-demo/src/clmm; the GitHub link sits next to each section. Bootstrap follows the demo repo’s config.ts.template (source) — disableFeatureCheck: true is the recommended setting for any non-trivial integration:
Create a CLMM pool
Source:src/clmm/createPool.ts
- Sorts
mint1/mint2by byte order before derivation. - Computes
sqrt_price_x64 = floor(sqrt(initialPrice × 10^(dB−dA)) × 2^64). - Creates the
observationandtick_array_bitmap_extensionaccounts. - Pays the pool-creation fee defined by
ammConfig.
Open a position in a chosen range
Source:src/clmm/createPosition.ts
InitTickArray instructions if any are uninitialized.
Increase liquidity on an existing position
Source:src/clmm/increaseLiquidity.ts
Decrease liquidity (and collect fees at the same time)
Source:src/clmm/decreaseLiquidity.ts and src/clmm/closePosition.ts
decreaseLiquidity with liquidity = new BN(0). The instruction’s side-effect is settling tokens_fees_owed_{0,1} and transferring them out.
To close the position entirely after zeroing liquidity and fees, pass closePosition: true on the final decreaseLiquidity call. The SDK appends ClosePosition and burns the NFT.
Collect reward(s)
Source:src/clmm/harvestAllRewards.ts
harvestAllRewards walks every position on every pool passed in, batches CollectReward (and any UpdateRewardInfos) instructions, and splits them across transactions if needed.
Swap
Source:src/clmm/swap.ts
computeAmountOutFormat walks the tick map off-chain using the same logic as the on-chain program and returns:
- the expected amount out,
- the minimum amount out after slippage,
- the list of tick-array accounts the actual swap will touch (
remainingAccounts).
remainingAccounts returned by the simulation: if you pass too few, the swap reverts mid-walk with TickArrayNotFound; if you pass stale ones, wasted compute.
Create a customizable CLMM pool
createCustomizablePool is the new entry point that exposes the dynamic-fee and single-sided-fee toggles at pool-creation time. It takes the same shape as createPool plus three additions:
createPool continues to work for the default-fee, no-limit-order, no-dynamic-fee path. Use createCustomizablePool whenever you need any of the three new knobs. See products/clmm/instructions for the on-chain account list.
Limit orders
A limit order parks user input at a single tick and is filled FIFO when a swap crosses that tick. Outputs are pushed to the owner’s ATA at settle time; the owner does not need to be online to be filled.Open a limit order
LimitOrderState PDA from (pool, owner, tick, nonce), bumps the per-(pool, owner) LimitOrderNonce, and inserts the order into the FIFO cohort at that tick.
Increase / decrease an open order
decreaseLimitOrder can only remove from the unfilled portion of the order; the filled portion is locked until settlement. Both instructions revert with InvalidOrderPhase if the order has already been fully filled.
Settle a filled order
settleLimitOrder reads the order’s unfilled_ratio_x64 against the cohort tracker, computes the filled output, and transfers it to the owner’s ATA. The owner can call this themselves; limit_order_admin (an off-chain operational keeper) can also call it on the owner’s behalf — the output still goes to the owner.
For closing fully-settled orders to recover rent, use closeLimitOrder (single) or closeAllLimitOrder (batch). For settling many at once, settleAllLimitOrder packs as many SettleLimitOrder calls as fit into a v0 tx.
List a wallet’s parked orders (off-chain)
totalAmount / filledAmount / pendingSettle distinguish the phases). For closed-order history use /limit-order/history/order/list-by-user?wallet=… (per-wallet, paginated by nextPageId); for the full event log of a specific order use /limit-order/history/event/list-by-pda?pda=….
Rust CPI skeleton
SwapV2:
Common pitfalls
- Off-spacing tick endpoints →
InvalidTickIndex. Always snap viaTickUtils.getPriceAndTick. - Not enough tick arrays supplied in
SwapV2→TickArrayNotFound. UsecomputeAmountOutFormatto get the full list. - Full-range position without the bitmap extension → the extension PDA must be writable; the SDK handles this automatically.
- Mistaking
sqrt_price_x64forprice→ a factor-of-2 confusion here is particularly painful. When in doubt, let the SDK compute it from a human-readable price. - Collecting rewards too eagerly → each collect costs one transaction. Batch via
harvestAllRewardsacross many positions. - Burning the NFT while rent is still owed to the mint →
ClosePositionalso closes the NFT mint and ATA; do not close them separately or the program will revert. - Opening a limit order at a non-spaced tick →
InvalidTickIndex. Always quantize viaTickUtils.getPriceAndTick. - Calling
decreaseLimitOrderon a fully-filled order →InvalidOrderPhase. UsesettleLimitOrderthencloseLimitOrderinstead. - Forgetting
dynamicFeeConfigIdwhile passingenableDynamicFee: true→ theCreateCustomizablePoolrevert isInvalidDynamicFeeConfigParams. Either turn dynamic fee off, or pick a config from/main/clmm-dynamic-config.
Where to go next
sdk-api/typescript-sdk— complete SDK surface.sdk-api/rest-api— quote and pool-metadata endpoints.user-flows/create-clmm-pool— non-code walkthrough.integration-guides/aggregator— routing CLMM as part of a path.

