The invariant
The pool maintainscoin_reserve × pc_reserve = k, where (after the 2026-07 OpenBook removal):
- Reserves are now vault-only. The historical open-order term (tokens the pool had escrowed as OpenBook limit orders) has been dropped — it was zero in practice long before the removal. You can compute
kdirectly from the on-chain vault balances. - The PnL accrual (
need_take_pnl_*) is subtracted so the curve is conserved when the admin sweeps fees. Same principle as CPMM’sprotocol_fees_*exclusion.
calc_total_without_take_pnl_no_orderbook (the old orderbook-aware variant is gone).
Every Swap* operation enforces k' ≥ k after adding the LP’s fee share back into the reserves.
Fee convention
AMM v4 uses ratio fees (numerator/denominator pairs) rather than the1/1_000_000 convention of CPMM / CLMM. The on-chain Fees struct (see Fees::initialize in the program source) defaults to:
- Total swap fee:
swap_fee = amount_in × 25 / 10_000 = 0.25%of the gross input. - Protocol share:
pnl_numerator / pnl_denominator = 12 / 100 = 12%of the swap fee, which works out to0.25% × 12% = 0.03%of volume. This share accrues to the PnL counters and is swept byWithdrawPnl. - LP share: the remaining
88%of the swap fee, which works out to0.25% × 88% = 0.22%of volume. Stays in the pool and inflatesk. - No fund share. AMM v4 does not have the CPMM/CLMM fund-fee split.
pnl_numerator / pnl_denominator is a fraction of the fee, not of trade volume — a common misreading of these field names.
trade_fee_numerator / trade_fee_denominator (also 25 / 10_000) was historically used by the OpenBook integration when computing fee-inclusive prices for the AMM’s limit-order grid. With the OpenBook code removed, this field is vestigial; the active swap fee is swap_fee_*.
Deviations from these defaults are rare but do exist on a handful of legacy pools; always read the fees from AmmInfo.fees before quoting.
Direct swap math (AMM path)
The simplest case: user swaps against the pool’s vaults without interacting with OpenBook. The pool’s internal reserves (including on-book allocations) are the denominator. SwapBaseIn (exact input):MonitorStep / implicit-settle path that used to refresh the OpenBook side has been removed.
SwapBaseOut (exact output):
Order-book interaction (historical)
Removed. The grid construction described in this section reflects how AMM v4 originally mirrored the curve onto an OpenBook market. The OpenBook integration — including the
MonitorStep crank and the build_orders grid logic — has been removed from the program (2026-07 upgrade). The math below is preserved purely as historical context for what the on-chain target_orders / amm_open_orders accounts were once sized for.AmmInfo parameters:
depth— number of price levels per side.amount_wave— base unit of size per level.min_size,coin_lot_size,pc_lot_size— OpenBook market constraints.state_data.swap_acc_coin_fee,swap_acc_pc_fee— cumulative fee counters since lastTakePnl.
target_orders computed in build_orders and compared with amm_open_orders each MonitorStep. Any divergence results in cancellations + new posts. Freshly filled orders on OpenBook settle into the pool vaults on the next operation that refreshes the OpenBook side.
Integrators rarely need to compute the grid — the Raydium keeper maintains it — but it is useful to know that:
- A pool with significant on-book liquidity has that liquidity contributing to
k, not sitting idle. - A stale OpenBook market (event queue full, cranks blocked) prevents grid updates; the AMM can then quote prices that diverge from the visible order book until the next crank.
Settlement step (PnL)
The 0.03% protocol share accrues intostate_data.need_take_pnl_coin and state_data.need_take_pnl_pc. TakePnl moves these amounts out of the vaults to the admin-specified destination, then zeroes the counters.
Crucial property: reserves in the invariant are always computed minus accrued PnL, so TakePnl does not move the curve. This matches the CPMM convention.
Worked example
Pool state:coin_reserve = 1_000_000_000_000(1,000,000 coin-side; 6 decimals)pc_reserve = 2_000_000_000_000(2,000,000 pc-side; 6 decimals)- Fees: default
swap = 25/10_000,pnl = 3/10_000.
SwapBaseIn exact-input 1_000_000_000 coin (1,000 coin).
2_200_000) is not broken out anywhere — it is simply the residual that raises k'.
Precision rules
- Reserve multiplications use
u128; final divisions round toward zero. swap_feerounds up (so the pool does not undercharge).amount_inforSwapBaseOutrounds up (so the user does not underpay).- Pools with extreme reserve ratios can hit
ZeroTradingTokenson very small inputs; same convention as CPMM.
Limitations vs CPMM
- AMM v4’s reserves are now vault-only, so you can quote directly from the vault balances (minus
need_take_pnl_*) — the previous requirement to add theopen_orders.free/open_orders.lockedamounts no longer applies. The SDK / API quote remains the simplest option. - AMM v4 does not expose a structured on-chain TWAP. External consumers that want an AMM-v4-backed price must compute it themselves from trade logs.
- Token-2022 is not supported.
Where to go next
products/amm-v4/instructions— whereSwapBaseIn,Deposit, etc. plug in.products/amm-v4/fees— full fee mechanics,TakePnldetails.algorithms/constant-product— the shared derivation.
- Raydium AMM program source —
raydium-io/raydium-amm - Raydium SDK v2
Liquiditymodule

