Skip to main content
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

Every demo on this page mirrors a file in 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
The SDK:
  • Sorts mint1/mint2 by byte order before derivation.
  • Computes sqrt_price_x64 = floor(sqrt(initialPrice × 10^(dB−dA)) × 2^64).
  • Creates the observation and tick_array_bitmap_extension accounts.
  • Pays the pool-creation fee defined by ammConfig.

Open a position in a chosen range

Source: src/clmm/createPosition.ts
The SDK automatically computes which tick arrays the range touches and bundles 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
To collect fees only, call 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).
Always pass 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

The SDK derives the 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)

The active-orders endpoint returns both unfilled and partially-filled orders in one payload (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

Remaining-account order for SwapV2:
If the swap never needs the extension, omit it; otherwise it is the first remaining account.

Common pitfalls

  • Off-spacing tick endpointsInvalidTickIndex. Always snap via TickUtils.getPriceAndTick.
  • Not enough tick arrays supplied in SwapV2TickArrayNotFound. Use computeAmountOutFormat to 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_x64 for price → 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 harvestAllRewards across many positions.
  • Burning the NFT while rent is still owed to the mintClosePosition also closes the NFT mint and ATA; do not close them separately or the program will revert.
  • Opening a limit order at a non-spaced tickInvalidTickIndex. Always quantize via TickUtils.getPriceAndTick.
  • Calling decreaseLimitOrder on a fully-filled orderInvalidOrderPhase. Use settleLimitOrder then closeLimitOrder instead.
  • Forgetting dynamicFeeConfigId while passing enableDynamicFee: true → the CreateCustomizablePool revert is InvalidDynamicFeeConfigParams. Either turn dynamic fee off, or pick a config from /main/clmm-dynamic-config.

Where to go next

Sources: