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.

This page is the authoritative instruction reference for the AMM Routing program. For code examples, see products/routing/code-demos. For error meanings, see reference/error-codes.

Instruction summary

TagDiscriminatorExactVariant
0SwapBaseInWithUserAccountInputLegacy
1SwapBaseOutWithUserAccountOutputLegacy
5CreateSyncNativeUtility
6CloseTokenAccountUtility
8SwapBaseInInputCurrent
9SwapBaseOutOutputCurrent
Legend:
  • Exact: which amount is fixed by the caller (Input = exact-input amount_in; Output = exact-output amount_out).
  • Variant: Legacy instructions require a non-empty limit_prices deque even if no CLMM hop is in the route. Current instructions (8 / 9) treat an empty limit_prices as “no checks”, which is the recommended path for new code.
All swap variants route intermediate tokens through user-controlled ATAs — the user owns the input ATA, every intermediate ATA, and the output ATA. For new integrations, use tag 8 (SwapBaseIn) or tag 9 (SwapBaseOut) unless you have a specific reason to call a Legacy variant. These are the entry points new code should use. Argument structure is the same as the Legacy variants but limit_prices may be empty.

SwapBaseIn (tag 8)

Exact-input multi-hop swap. The caller fixes amount_in; the router executes hop-by-hop and asserts that the final amount lands at or above minimum_amount_out. Arguments
amount_in:            u64
minimum_amount_out:   u64
limit_prices:         VecDeque<u128>  // optional; empty deque means no per-hop CLMM price check
Accounts
[
  <user_input_ata> W S,         // signer; balance >= amount_in
  <user_intermediate_ata_1> W,  // one per intermediate hop
  ... <user_intermediate_ata_N> W,
  <user_output_ata> W,
  <token_program>,

  <pool_program_hop_1>,         // identifies which AMM family hop 1 is
  <pool_state_hop_1> W,
  ... <other accounts required by hop 1's program>,

  <pool_program_hop_2>,
  <pool_state_hop_2> W,
  ... <hop 2 accounts>,

  ... [repeat per hop]
]
The exact account list per hop depends on the underlying AMM program (AMM v4 / CPMM / CLMM / Stable). The router CPIs into each in turn and validates the program ID matches one of the four supported programs. Pre-conditions
  • Caller signs with user_input_ata.
  • user_input_ata.amount >= amount_in.
  • Each intermediate user ATA exists and is owned by the caller.
  • If any hop is CLMM and you want price-bound enforcement, supply one limit_prices entry per CLMM hop.
Post-conditions
  • user_input_ata balance decreased by amount_in.
  • user_output_ata balance increased by ≥ minimum_amount_out.
  • Each intermediate ATA is left with zero net change (the route consumes whatever it produced one hop earlier).
Common errors
  • ExceededSlippage — final output < minimum_amount_out.
  • InvalidInput — empty route, malformed accounts, or unsupported pool_program.
  • SqrtPriceX64 — a CLMM hop’s price moved outside the supplied limit_prices bound (only when limit_prices is non-empty).

SwapBaseOut (tag 9)

Exact-output multi-hop swap. The caller fixes amount_out; the router asserts that the actual input does not exceed maximum_amount_in. Arguments
maximum_amount_in:   u64
amount_out:          u64
limit_prices:        VecDeque<u128>  // optional; empty deque means no per-hop CLMM price check
Accounts — same structure as tag 8. Pre-conditions
  • Caller signs with user_input_ata; balance >= maximum_amount_in (worst case).
  • Each intermediate and the output ATA exist.
Post-conditions
  • user_input_ata decreased by the actual amount needed (≤ maximum_amount_in).
  • user_output_ata increased by exactly amount_out.
Common errors
  • ExceededSlippage — required input exceeds maximum_amount_in.
  • InvalidInput, SqrtPriceX64 — as for tag 8.

Legacy swap instructions

These older variants are still callable on the live program and are documented here for completeness. Prefer tag 8 / tag 9 for new code; both Legacy variants below require a non-empty limit_prices deque even when no CLMM hop is involved, which makes them awkward to use.

SwapBaseInWithUserAccount (tag 0)

Exact-input multi-hop swap, identical in shape to tag 8 but with the stricter limit_prices requirement. Arguments
amount_in:           u64
minimum_amount_out:  u64
limit_prices:        VecDeque<u128>  // required, non-empty
Accounts — same shape as SwapBaseIn (tag 8). All intermediate slots must be ATAs owned by the caller. Pre-conditions
  • Caller signs with user_input_ata.
  • user_input_ata.amount >= amount_in.
  • All intermediate user ATAs exist and are owned by the caller.
  • limit_prices is non-empty (one entry per CLMM hop; pad with placeholder values if no CLMM hop is involved).
Post-conditions
  • user_input_ata balance decreased by amount_in.
  • user_output_ata balance increased by ≥ minimum_amount_out.
Common errors
  • ExceededSlippage.
  • InvalidInput — empty limit_prices is rejected on this Legacy variant.
  • SqrtPriceX64.

SwapBaseOutWithUserAccount (tag 1)

Exact-output swap, the Legacy counterpart to SwapBaseOut (tag 9). Arguments
maximum_amount_in:   u64
amount_out:          u64
limit_prices:        VecDeque<u128>  // required, non-empty
Accounts — same shape as tag 0 / tag 9. Pre-conditions
  • Caller signs with user_input_ata.
  • user_input_ata.amount >= maximum_amount_in.
  • All intermediate user ATAs exist and are owned by the caller.
  • limit_prices is non-empty.
Post-conditions
  • user_input_ata decreased by the actual amount needed (≤ maximum_amount_in).
  • user_output_ata increased by exactly amount_out.
Common errors
  • ExceededSlippage.
  • InvalidInput.
  • SqrtPriceX64.

Utility instructions

CreateSyncNative (tag 5)

Create (if missing) and sync a wSOL ATA in one step. Convenient when wrapping SOL inline alongside a swap. Arguments
amount: u64    // SOL to wrap (lamports)
Accounts
[
  <user_wsol_ata> W,            // ATA for wSOL; created if missing
  <user_native_account> W S,    // signer; SOL is debited from here
  <wsol_mint>,
  <system_program>,
  <token_program>,
  <associated_token_program>,
]
Effect
  • Creates user_wsol_ata if it does not yet exist.
  • Transfers amount lamports from the signer’s native SOL balance to the ATA.
  • Calls SyncNative on the ATA so its token balance reflects the new lamports.
Common errors
  • InvalidOwneruser_wsol_ata’s owner is not the signer.

CloseTokenAccount (tag 6)

Close a token account and return its rent to the destination wallet. Pairs with CreateSyncNative: after a wSOL-leg swap, call CloseTokenAccount to recover the rent that backed the wSOL ATA. Arguments — none. Accounts
[
  <token_account_to_close> W,
  <destination_for_rent> W,
  <owner> S,
  <token_program>,
]
Effect
  • Closes token_account_to_close.
  • Transfers the rent-exempt lamport balance (~0.00203928 SOL on mainnet for a vanilla SPL Token account) to destination_for_rent.
  • The token account must have zero token balance.
Common errors
  • InvalidOwner — caller is not the ATA owner.
  • Token account balance is non-zero.

Where to go next