Skip to main content
CPI (“cross-program invocation”) is the mechanism by which one Solana program calls another. Raydium’s Anchor programs ship CPI wrapper crates that make the call site look like a typed function call — account structs with validated field names and cpi::<ix>() helpers. This page documents the general pattern; for product-specific snippets see the code-demos page of each product chapter.

Cargo dependencies

The cpi feature flag makes the crates compile to just the CPI surface (account structs + invokers) rather than the full program, so your binary stays small. For working CPI examples that wire up the account structs end-to-end, see raydium-io/raydium-cpi-example (covers AMM v4, CPMM, and CLMM).

Account list construction

Every Raydium CPI requires an Accounts struct in the calling program. Fields match the program’s instruction account order 1-for-1, with field-level validators:
Most of the Raydium-side accounts are UncheckedAccount because the callee (Raydium) owns the validation. Your calling program only strictly validates accounts you own — user ATAs, your own PDAs. The /// CHECK: doc-comment suppresses Anchor’s warning about missing checks.

Building the CPI call

Anchor generates one helper per instruction:
cpi::swap_base_input is generated from the IDL; its argument list mirrors the Anchor instruction’s argument list.

Signer seeds (PDA-signed CPI)

When your program signs the CPI on behalf of a PDA (common for vaults, escrows, etc.), use CpiContext::new_with_signer:
The signer seeds must match the PDA’s derivation. For any account passed as authority (or similar signer role), the Solana runtime checks that the PDA signs via these seeds.

Remaining accounts

Some Raydium instructions take remaining accounts — a variable-length list appended after the fixed accounts. The canonical examples:
  • CLMM SwapV2: appends 1–8 TickArrayState accounts corresponding to the tick arrays the swap might traverse.
  • Farm v6 Deposit: appends (reward_vault, user_reward_ata) pairs for each live reward stream.
Anchor’s CPI helpers do not type-check remaining accounts. Pass them via .with_remaining_accounts(...):
Order matters: the receiver program iterates the remaining accounts in the order you pass them. For CLMM, tick arrays must be ordered directionally (first array in swap direction first). For farm v6, reward slots go in slot index order.

Error propagation

Raydium’s programs return their own error enums. Anchor wraps them; your calling program sees them as Err(ProgramError::Custom(code)). To handle specific errors:
The error code number is stable per the IDL policy (sdk-api/anchor-idl). You can test against specific codes by comparing against the numeric value.

Compute budget in composed CPIs

Each CPI frame has overhead (~1,500 CU for the call itself), and the callee’s own CU consumption stacks on top of yours. A transaction that calls CPMM swap from inside your program spends:
For stacked routing (your program → aggregator → CPMM + CLMM + farm harvest), budget ≥500k CU. Always set an explicit ComputeBudgetProgram::set_compute_unit_limit(...) instruction in the transaction — the default 200k CU limit will silently exhaust.

AMM v4 — manual Instruction construction

AMM v4 has no Anchor crate. Build the Instruction by hand:
See products/amm-v4/code-demos for the full account list.

Farm v6 — reward-pair remaining accounts

Farm v6’s Deposit / Withdraw / Harvest use the (reward_vault_i, user_reward_ata_i) pair pattern in remaining accounts. Exact sequence:
One pair per live (running or ended-but-unclaimed) reward slot. Omit unused slots; the program dispatches off farm_state.reward_infos[i].reward_state.

Testing a CPI flow

Local dev requires the Raydium programs to be available in your test validator. Options:
  1. anchor test with program clone — in Anchor.toml:
    This pulls the deployed bytecode from mainnet into your local validator.
  2. Devnet — Raydium deploys all programs to devnet with the same program IDs as mainnet. Run anchor test --provider.cluster devnet to hit live code.
  3. Local deploy — clone the Raydium repos and anchor deploy to a local validator. Adds test cycle overhead but lets you modify the callee for debugging.

Pointers

Sources: