As of the 2026-07 program upgrade, AMM v4’s OpenBook / Serum dependency has been removed. The legacy v1
SwapBaseIn / SwapBaseOut, Deposit, and Withdraw instructions keep their old account layouts for backwards compatibility: the market accounts are still accepted in their old positions, but they are no longer validated or used (no CPI is issued). New integrations should use the V2 swap entrypoints, which omit the market accounts entirely. Several instructions have been removed and now revert — see the changelog entry. The account lists below use the field names from the Raydium SDK; the underlying IDL sometimes uses serum_* prefixes.The 2026-09 program upgrade adds one admin instruction, WithdrawExcessLamports (tag 18), and drops the rent sysvar from CreateConfigAccount. Everything a trader or LP calls is unchanged. See the 2026-09-09 changelog entry.Instruction inventory
The SDK exposes builders for the user-facing instructions only. Upkeep instructions are typically invoked by the Raydium keeper.
Removed / no longer callable (their client builders were deleted):
Initialize (tag 0, use Initialize2), MonitorStep (2), MigrateToOpenBook (5), WithdrawSrm (8), PreInitialize (10, use Initialize2), SimulateInfo (12), AdminCancelOrders (13).
A transaction carrying one of these tags fails; the program never executes the instruction. Treat all seven as gone rather than as error paths to handle.
Initialize2
Bootstrap a new AMM v4 pool bound to an existing OpenBook market.
Arguments
W, signer S)
Two accepted layouts. The 19-account list above is the recommended one. For backwards
compatibility the program also reads a 21-account legacy layout, which inserts an ignored
amm_open_orders at position 7 and an ignored market_program at position 16 — this is what
the in-repo initialize2 instruction builder still emits. Any other length is parsed
positionally against the legacy layout and will fail.- LP minted to the creator =
sqrt(init_coin_amount × init_pc_amount) − 10^coin_mint.decimals. LP decimals equalcoin_mint.decimals, so the subtracted amount is exactly one whole LP token; it is never minted and is permanently out of circulation. Ifsqrt(...)is below that, the instruction reverts withInitLpAmountTooLess. AmmInfo.lp_amountstores the fullsqrt(...), not the minted amount — solp_mint.supplyis permanently one whole LP token lower thanamm.lp_amount. All pro-rata math usesamm.lp_amount.- No OpenBook orders are posted (the order-book grid has been removed).
AmmInfo.marketrecords the account passed in slot 15, butAmmInfo.open_ordersandAmmInfo.market_programare both written asPubkey::default(), andcoin_lot_size/pc_lot_size/min_sizeare initialized to0. On the legacy 21-account layout the extraamm_open_ordersandmarket_programaccounts are read and discarded.
InvalidCoinMint (coin and pc mint identical), InvalidConfigAccount (wrong amm_config PDA), InvalidFee (wrong create-pool-fee destination), InvalidProgramAddress (wrong amm_authority or wrong nonce), RepeatCreateAmm (a pool already exists for this market), InitLpAmountTooLess, InvalidSupply (either init amount is 0, or the LP mint already has supply), AlreadyInUse.
Deposit
Add liquidity.
Arguments
Math — standard pro-rata. Using the pool’s effective reserves (vaults + on-book), the SDK computes the coin/pc pair that yields the given LP amount and checks it against
max_*. Reverts with ExceededSlippage if either side exceeds the cap.
Withdraw
Burn LP, receive both sides.
Arguments
There is no longer any settle-from-OpenBook step — the pro-rata math uses the vault balances directly.
SwapBaseIn
Exact-input swap. Always an AMM-path swap (does not route through OpenBook matching).
Use the V2 variants for new code. Since AMM v4’s OpenBook dependency has been removed, the V1 entrypoints (
SwapBaseIn, SwapBaseOut) still expect the full 17-account list (or 18 with the optional target-orders account), but the OpenBook/market accounts are now accepted positionally and ignored — they are not validated and no CPI is issued. Passing a wrong account count still reverts with WrongAccountsNumber, but the market account contents are no longer checked. New integrations should use SwapBaseInV2 / SwapBaseOutV2, which take a much smaller account list and represent the canonical execution path today. The V1 forms are documented here for completeness and for reading existing on-chain transactions.
Math — see
products/amm-v4/math.
Preconditions
AmmStatus::from_u64(amm.status).swap_permission()is true — that is,statusis1(Initialized),6(SwapOnly) or7(WaitingTrade).statusis an enum value, not a bitmask; seeproducts/amm-v4/accounts.amm.state_data.pool_open_time <= now.amount_in > 0.user_source_token_accountholds at leastamount_in.
- User loses
amount_inof source token, gainsamount_out ≥ minimum_amount_outof dest token. - The swap fee stays in the vaults, raising the invariant
k. Theneed_take_pnl_*counters are not touched by swaps — protocol PnL is recomputed from thekdelta on the nextDeposit,WithdraworWithdrawPnl(Processor::calc_take_pnl). - Note: the
state_data.swap_*_in_amount/swap_*_out_amountanalytics counters are no longer updated — their values are frozen. Use trade logs for volume analytics.
ExceededSlippage, InvalidInput, InvalidStatus, NotAllowed (coin/pc mint identical).
SwapBaseOut
Exact-output, inverse of SwapBaseIn. Same accounts.
Arguments
SwapBaseInV2 / SwapBaseOutV2
Variant swap entrypoints (tags 16 / 17) that skip the OpenBook accounts entirely. The math is identical to the V1 path, but the account list shrinks to just the AMM side and the user — 8 accounts, and amm_open_orders is not passed:
Pool reserves are now the vault balances (minus pending PnL), so quote math is straightforward and identical to the v1 path. Use V2 to save compute and avoid passing the (now-ignored) market accounts. The Raydium router always uses the V2 form when routing through AMM v4.
Arguments are the same as the V1 forms (
amount_in / minimum_amount_out for SwapBaseInV2; max_amount_in / amount_out for SwapBaseOutV2).
MonitorStep and other removed instructions
Historically, MonitorStep cranked the pool’s OpenBook interaction: it settled filled orders (moving proceeds from the market vaults into the pool vaults via OpenBook CPI), cancelled stale orders, and posted new orders to close the gap between target_orders and amm_open_orders. With the OpenBook dependency removed, there is nothing to crank and the instruction is gone. Any keeper or integration that still calls it must remove the call.
WithdrawPnl / TakePnl
Admin sweep of accrued protocol fees.
Arguments
WithdrawPnltakes no args; it readsneed_take_pnl_*and moves those exact amounts.
Effect
- Transfers
need_take_pnl_coinfrompool_coin_token_accounttopnl_coin_token_account. - Same for pc.
- Zeros
need_take_pnl_coinandneed_take_pnl_pc. - Logic change: if the vault balance is insufficient to cover accrued PnL, the instruction returns
TakePnlErrordirectly (it no longer manipulates order-book state).
SetParams
Admin param changes, called by the Raydium multisig. Arguments are a param: u8 tag + payload.
CreateConfigAccount / UpdateConfigAccount
Admin management of the program-level AmmConfig PDA (seed ["amm_config_account_seed"]). The account holds exactly three meaningful fields — pnl_owner, cancel_owner and create_pool_fee — plus two reserved padding regions; there is no pool-creation flag. UpdateConfigAccount sets pnl_owner with param = 0, cancel_owner with param = 1, and create_pool_fee with param = 2.
Changed in 2026-09, and backwards-compatible.
CreateConfigAccount no longer reads the rent sysvar. Its account list is now 4 accounts, down from 5:The program reads rent parameters from
Rent::get() instead of deserializing a passed-in sysvar account — what the Solana 3.0 dependency bump made natural.The removed account was last in the list, and the handler reads its accounts positionally through next_account_info with no length check. An existing admin tool that still passes the old 5-account list therefore keeps working: the trailing rent account is simply never read. Update it when convenient, not urgently. UpdateConfigAccount is unchanged.Initialize2 keeps the rent sysvar in position 3, and still uses it: the program stopped calling Rent::from_account_info on it, but it is still forwarded into the spl_token::initialize_account and initialize_mint CPIs that create the pool’s vaults and LP mint. Do not drop it from the account list.
WithdrawExcessLamports
Admin sweep of lamports sitting above the rent-exempt minimum on accounts the program controls. Added in the 2026-09 upgrade to recover the over-funding that the SIMD-0437 rent reduction leaves behind on accounts created before each step.
It moves only the excess. Token balances, account data, owners, and pool state are untouched, and the instruction is a no-op on an account already at its minimum — so it is safe to fire repeatedly and again after each rollout step.
Arguments — none. The payload is the single tag byte 18.
Accounts
How each source account is handled
The program dispatches on the source account’s
owner:
Common errors —
InvalidSignAccount (wrong signer), InvalidSplTokenProgram (wrong program in slot 3), InvalidProgramAddress (wrong amm_authority), LamportsCalculateError (custom code 60; the wSOL round-trip did not net to zero), and InsufficientFunds from the program-owned path when an account holds less than its own rent minimum.
No SDK builder. @raydium-io/raydium-sdk-v2 does not ship a builder for this instruction, and neither does the raydium-sdk-V2-demo repo — it is an admin path. Encode it by hand, the way the wallet-side sweep in solana-fundamentals/rent-and-reclaimable-rent does for the token-program instruction.
State-change matrix
The OpenBook column is gone — no instruction touches an order book anymore.Where to go next
products/amm-v4/code-demos— TypeScript examples for swap and LP flows.products/amm-v4/fees—WithdrawPnldetails and the fee split.reference/error-codes— forward-reference table (AMM v4 errors are listed on that page).
- Raydium AMM program —
raydium-io/raydium-amm - Raydium SDK v2
Liquiditymodule - OpenBook program — account validations on the market side

