Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.raydium.io/llms.txt

Use this file to discover all available pages before exploring further.

AMM v4 is significantly more account-heavy than CPMM or CLMM because every operation touches OpenBook state. This page groups the accounts into “pool-owned” and “OpenBook-owned” sections so an integrator can quickly see which side is which.

Inventory

An AMM v4 pool binds to exactly one OpenBook market at creation. The full live picture is:
CategoryAccountOwnerRole
PoolAmmInfoAMM v4 programPool state: fees accrued, status, references to vaults and OpenBook market.
Poolamm_authorityAMM v4 programProgram-owned PDA that signs vault moves. Shared across all AMM v4 pools.
Poolamm_open_ordersOpenBookThe pool’s OpenBook OpenOrders account for this market.
Poolamm_target_ordersAMM v4 programPool-side grid of target limit orders to post back onto OpenBook.
Poolpool_coin_token_accountSPL TokenPool’s coin-side vault (ATA of amm_authority).
Poolpool_pc_token_accountSPL TokenPool’s pc-side vault.
Poollp_mintSPL TokenFungible LP mint.
Poolpool_withdraw_queueAMM v4 programLegacy queue for delayed withdrawals; kept zero-length.
Poolpool_temp_lpAMM v4 programAuxiliary LP account used during Initialize.
Market (OpenBook)serum_marketOpenBookThe market itself (base/quote mints, vault signer, etc.).
Marketserum_bids, serum_asksOpenBookThe bid and ask queues.
Marketserum_event_queueOpenBookPending events (fills, cancellations).
Marketserum_coin_vault, serum_pc_vaultSPL TokenOpenBook’s market-level vaults.
Marketserum_vault_signerOpenBookMarket-level PDA that signs serum_*_vault moves.
Note: “serum” is kept as the prefix in AMM v4’s IDL and field names for backward compatibility. It refers to the OpenBook market today.

AmmInfo

The pool’s root state account. Large (≈ 752 bytes) because it carries both pool and OpenBook references inline.
// programs/amm/src/state.rs (abridged; field order / names follow the IDL)
pub struct AmmInfo {
    pub status: u64,           // bitmask: swap/deposit/withdraw/crank enabled
    pub nonce:  u64,           // bump used to derive amm_authority
    pub order_num: u64,
    pub depth: u64,
    pub coin_decimals: u64,
    pub pc_decimals:   u64,
    pub state:         u64,    // internal state machine
    pub reset_flag:    u64,
    pub min_size:      u64,
    pub vol_max_cut_ratio: u64,
    pub amount_wave: u64,
    pub coin_lot_size: u64,    // mirrors OpenBook market
    pub pc_lot_size:   u64,
    pub min_price_multiplier: u64,
    pub max_price_multiplier: u64,
    pub sys_decimal_value: u64,

    pub fees: Fees,            // trade/protocol/fund fee rates
    pub state_data: StateData,

    // Pool-owned accounts:
    pub coin_vault: Pubkey,
    pub pc_vault:   Pubkey,
    pub coin_vault_mint: Pubkey,
    pub pc_vault_mint:   Pubkey,
    pub lp_mint:  Pubkey,
    pub open_orders: Pubkey,   // pool's OpenOrders on OpenBook
    pub market: Pubkey,        // OpenBook market
    pub market_program: Pubkey, // OpenBook program ID
    pub target_orders: Pubkey,
    pub withdraw_queue: Pubkey,
    pub lp_vault:       Pubkey, // = pool_temp_lp
    pub owner: Pubkey,          // admin (multisig)
    pub lp_reserve: u64,
    pub padding: [u64; 3],
}

pub struct Fees {
    pub min_separate_numerator:   u64,     // 5
    pub min_separate_denominator: u64,     // 10_000
    pub trade_fee_numerator:      u64,     // 25  → used by OpenBook integration
    pub trade_fee_denominator:    u64,     // 10_000
    pub pnl_numerator:            u64,     // 12  → protocol's share OF the swap fee
    pub pnl_denominator:          u64,     // 100 → so 12/100 = 12% of fee, = 0.03% of volume
    pub swap_fee_numerator:       u64,     // 25  → 0.25% gross swap fee
    pub swap_fee_denominator:     u64,     // 10_000
}

pub struct StateData {
    pub need_take_pnl_coin: u64,
    pub need_take_pnl_pc:   u64,
    pub total_pnl_pc:   u64,
    pub total_pnl_coin: u64,
    pub pool_open_time: u64,
    pub punish_pc_amount: u64,
    pub punish_coin_amount: u64,
    pub orderbook_to_init_time: u64,
    pub swap_coin_in_amount: u128,
    pub swap_pc_out_amount:  u128,
    pub swap_acc_pc_fee:    u64,
    pub swap_pc_in_amount:  u128,
    pub swap_coin_out_amount: u128,
    pub swap_acc_coin_fee:  u64,
}
Integrator-facing fields:
  • coin_vault, pc_vault — the pool’s SPL Token vaults. coin is token_0 by Serum/OpenBook convention (base), pc is token_1 (quote).
  • coin_decimals, pc_decimals — matching the mints.
  • open_orders, target_orders, market — must be passed to every swap/deposit/withdraw instruction.
  • fees.swap_fee_numerator / swap_fee_denominator — the combined trade fee. Default 25 / 10_000 = 0.25%.
  • status — bitmask gating operations. Admin-settable via AdminSetStatus.
  • state_data.need_take_pnl_* — delta between gross accrued fees and what’s been swept. TakePnl zeroes these.

The OpenBook wiring

No longer active. AMM v4 pools no longer share liquidity to OpenBook — the limit-order grid has been deactivated. The OpenBook accounts described in this section remain on each pool’s AmmInfo and are still validated by V1 swap entrypoints (and by Initialize, Deposit, Withdraw) for backwards compatibility, but the on-book state they reference is empty in practice. Use the V2 swap entrypoints (SwapBaseInV2 / SwapBaseOutV2) which skip these accounts entirely and represent the canonical execution path today.
When you call any V1 read or write instruction on an AMM v4 pool, you must pass the OpenBook accounts. The program re-derives and validates them, so passing a mismatched set reverts. (The V2 swap variants do not require these accounts at all.)
const market = ...;  // OpenBook market PublicKey

// Fields OpenBook exposes on its market account:
const marketDecoded = OpenBookMarket.decode(marketAccountData);
const {
  bids:           serumBids,
  asks:           serumAsks,
  eventQueue:     serumEventQueue,
  requestQueue:   serumRequestQueue,
  baseVault:      serumCoinVault,
  quoteVault:     serumPcVault,
  vaultSignerNonce,
} = marketDecoded;

const serumVaultSigner = PublicKey.createProgramAddressSync(
  [market.toBuffer(), u64ToBytes(vaultSignerNonce)],
  OPENBOOK_PROGRAM_ID,
);
The AMM’s amm_open_orders is an OpenBook-owned account holding the pool’s limit-order state on this market: active orders, settled balances, referrers, etc. amm_target_orders is AMM-side: it holds the AMM’s intended grid (price/size for each order slot) so the program can cheaply compare against what’s currently posted and place / cancel the diff.

Authority PDAs

There is exactly one amm_authority PDA for the entire AMM v4 program. Its seed is trivial (["amm authority"]) and its bump is stored on every AmmInfo. This authority signs all token moves for all AMM v4 pools.
const AMM_V4_PROGRAM_ID = new PublicKey(
  "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8",
);
const [ammAuthority] = PublicKey.findProgramAddressSync(
  [Buffer.from("amm authority")],
  AMM_V4_PROGRAM_ID,
);
There is a separate pool-scoped authority derived per pool to sign OpenBook operations (amm_authority above actually covers both in this program’s design; different versions used different derivation, so check the specific pool’s AmmInfo.nonce in code).

Vaults

The pool’s SPL Token vaults are standard token accounts whose owner is amm_authority. Not ATAs — their addresses are specific PDAs derived at Initialize with ["amm_associated_seed", coin_mint_or_pc_mint, market, amm_id] seeds. Addresses are stored on AmmInfo; derivation is a one-time curiosity. Token-2022 is not supported. The program hardcodes SPL Token’s program ID for all vault moves. Attempting to bind an AMM v4 pool to a Token-2022 mint fails at Initialize.

LP mint

A classic SPL Token mint whose authority is amm_authority. Total supply tracks LP ownership of the pool; burning LP returns tokens from both vaults pro-rata. Because AMM v4 predates CPMM, there is no lp_supply mirror in the pool state — read the mint’s on-chain supply directly.

Status bitmask

AmmInfo.status gates operations. Bits (position may differ across program versions — confirm via the source):
BitFlagEffect
0SWAP_DISABLEDSwap* rejects.
1DEPOSIT_DISABLEDDeposit rejects.
2WITHDRAW_DISABLEDWithdraw rejects.
3CLMM_LIKE_MIGRATEMigration-gate flag used by ops.
The Raydium multisig sets these via AdminCancelOrders, AdminSetParams, etc.

Observation / oracle

AMM v4 has no dedicated observation account. Other protocols that need an on-chain TWAP typically consume OpenBook’s book crossings indirectly or read off-chain. If you need a Raydium TWAP with program support, use CPMM or CLMM.

Deriving a pool’s accounts from scratch

Because AMM v4 was not designed for deterministic per-pair PDAs (it pre-dates that Solana convention), the canonical amm_id is a seeded keypair derived with:
ammId = createWithSeed(
  owner: ammAuthority,
  seed:  marketPubkey.toBase58().slice(0, 32),
  programId: AMM_V4_PROGRAM_ID,
)
The same seeded-key pattern applies to amm_open_orders, amm_target_orders, amm_withdraw_queue, pool_temp_lp, pool_coin_token_account, pool_pc_token_account, and lp_mint. The SDK and API pre-compute these for you; see raydium-sdk-v2’s Liquidity.getAssociatedPoolKeys. In practice, integrators read the pool’s full account set from GET https://api-v3.raydium.io/pools/info/ids?ids=<POOL_ID> or from the SDK. Hand-deriving is rarely needed.

Lifecycle quick reference

EventAccounts createdAccounts destroyed
Initialize2amm_info, amm_open_orders, amm_target_orders, vaults, lp_mint, pool_withdraw_queue, pool_temp_lp
Deposit— (may create user LP ATA)
Withdraw
SwapBaseIn / SwapBaseOut— (may create user ATA)
TakePnl
MonitorStep (crank)
Pools and their accounts persist indefinitely. Even if liquidity is fully withdrawn, AmmInfo stays.

What to read where

Sources: