Skip to main content
Version banner.
  • SDK: @raydium-io/raydium-sdk-v2@0.2.64-alpha
  • Cluster: Solana mainnet-beta
  • Stable AMM program ID: 5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h (see reference/program-addresses)
  • Last verified: 2026-09-09 against SDK 0.2.64-alpha source and the raydium-sdk-V2-demo amm/trade demos
The SDK’s liquidity module handles Stable AMM pools natively. Stable pools surface as version: 5 (or pooltype: "StablePool") on ApiV3PoolInfoStandardItem; the same addLiquidity / removeLiquidity / swap helpers work for them as for AMM v4 (version: 4) constant-product pools — the SDK detects the variant and emits the correct instructions automatically. The off-chain stable-curve math lives in src/raydium/liquidity/stable.ts.

Setup

initLayout() is not optional for Stable pools. liquidity.computeAmountOut branches on poolInfo.version: for version 4 it uses the constant-product formula, and for anything else it reads this.stableLayout.stableModelData and interpolates the lookup table. That cache is empty until initLayout() runs, so quoting a v5 pool without it produces garbage rather than an error. It is idempotent and cheap — call it once at startup.The transaction builders (swap, addLiquidity, removeLiquidity) do not need it: they dispatch on pooltype.includes("StablePool") and emit AmmV5* instructions, and the amount bounds you pass in are already computed.
liquidity.computeAmountIn does not support Stable pools. Unlike computeAmountOut, it has no version branch — it always applies the constant-product inverse, so on a v5 pool it returns a wrong maxAmountIn. For an exact-output swap against a Stable pool, invert with getDxByDyBaseIn yourself (see Off-chain quote helpers below) and pass the result to swap with fixedSide: "out".

Identifying a Stable pool

Two equivalent signals on ApiV3PoolInfoStandardItem:
Both AMM v4 (version: 4, constant-product) and Stable AMM (version: 5) flow through the same LiquidityModule API on the SDK. Internally the module dispatches to:
  • InstructionType.AmmV4AddLiquidity / AmmV4RemoveLiquidity for v4 pools
  • InstructionType.AmmV5AddLiquidity / AmmV5RemoveLiquidity for v5 (Stable) pools
The pool’s programId (returned with the pool keys) tells the SDK which program to CPI into; you do not need to hardcode it.

Find a pool by mint pair

If the mint pair has both a v4 (constant-product) pool and a v5 (stable) pool, the response includes both — pick the one your flow needs, or hand them to the AMM Routing program and let it pick the best route.

Swap through a Stable pool

The LiquidityModule.swap flow is the same shape as for v4 pools — just hand it a v5 pool object. Two details are easy to get wrong: computeAmountOut needs the pool’s live reserves grafted onto the pool info (the API item alone does not carry them), and its slippage is a plain number, not a Percent:
The SDK reads the pool’s programId from the pool keys and dispatches into the Stable AMM program. No special programId argument is needed.

Add and remove liquidity

addLiquidity and removeLiquidity work identically across v4 and v5 pools:
Internally the SDK emits InstructionType.AmmV5AddLiquidity because pooltype.includes("StablePool") is true. The corresponding removeLiquidity flow is symmetric — feed in lpAmount and the minimum amounts you will accept on each side.

Off-chain quote helpers (stable.ts)

For server-side quoting or backtesting, the SDK exposes the underlying stable-curve math:
These are pure functions — no RPC, no signing. The on-chain ModelDataInfo is fetched once by initLayout() and cached inside raydium.liquidity.stableLayout, readable as .stableModelData. initStableModelLayout() is idempotent: it re-fetches only while validDataCount === 0, so calling initLayout() again is free. Pass current reserves (x, y) and the helpers compute by binary-searching the lookup table and linearly interpolating between the two surrounding DataElement rows. See products/stable/math for the underlying algorithm.

Routing through AMM Routing (multi-hop / best-price)

If you do not want to pick a venue yourself, the AMM Routing program will consider every Raydium AMM (v4 / CPMM / CLMM / Stable) and route through whichever combination is best: The router is a five-call pipeline rather than a single swap(), and it is written out in full — with the caching advice that makes it usable in production — on products/routing/code-demos. The shape is:
There is no raydium.tradeV2.fetchRoutes, and tradeV2.swap does not accept inputMint / outputMint / slippage — it takes an already-computed swapInfo from getAllRouteComputeAmountOut. For a single known pool, use that pool type’s own builder (raydium.liquidity.swap for AMM v4 and Stable, raydium.cpmm.swap, raydium.clmm.swap) as shown earlier on this page.
This is the recommended path for production swappers and aggregators — you never need to manually decide whether a Stable pool exists or whether it is the better venue today.

Recommendations

  1. For end-user swaps, prefer the tradeV2 routing flow. It handles every Raydium pool type including Stable.
  2. For pool-specific operations (LP add / remove on a known Stable pool), use the LiquidityModule directly — it auto-detects v5 pools.
  3. For off-chain quoting / analytics, call getStablePrice / getDyByDxBaseIn / getDxByDyBaseIn after initLayout(). No RPC traffic per quote after the model data is cached.
  4. Do not hand-encode raw SwapBaseIn instructions. The 2026-06-22 upgrade removed the dead OpenBook accounts, so the new swap layout takes 9 accounts (the old 18-account layout still parses for backwards compatibility). Deposit is now 12 accounts (old 14 compatible), Withdraw 12 (old 21/22 compatible), and WithdrawPnl 10 with no compatibility path. The SDK’s pre-built helpers select the correct layout and ordering for you; rolling your own is error-prone. See products/stable/instructions for the full account tables.

Where to go next

  • Math — how the lookup-table interpolation works.
  • Instructions — full instruction reference.
  • AMM Routing — multi-pool routing across AMM v4, CPMM, CLMM, Stable.
Sources: