CPI (“cross-program invocation”) is the mechanism by which one Solana program calls another. Most of Raydium’s programs ship Anchor CPI wrapper crates that make the call site look like a typed function call, with account structs that have validated field names and
cpi::<ix>() helpers. This page documents the general pattern once, then the per-program differences. For runnable TypeScript, see the code-demos page of each product chapter.Which pattern applies to which program
If you’re integrating CPMM, CLMM, or LaunchLab, read the general pattern first, then jump to your program’s section for the account list and any differences. Farm v6 and AMM v4 are different enough to warrant reading their sections standalone.
Cargo dependencies
branch = "master" tracks the latest published source; pin to a specific rev = "<commit>" if you need a reproducible build. This is recommended once you’re past prototyping, since an upstream account-layout change on master will break your build with no warning otherwise.
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.
anchor-lang / anchor-spl must match what the target crate pins:
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). Its newest branch is anchor-0.31.0 — there is no Anchor 1.x branch yet, so treat that repo as the reference for account-struct wiring, not for the version pins this page mandates.
The general Anchor CPI pattern
This section walks through CPMM end-to-end as the worked example:Accounts struct, CpiContext, cpi::<ix>(). CLMM follows the identical shape, with a different account list and a remaining-accounts requirement. LaunchLab follows the same mechanics but its account list carries several accounts with no CPMM/CLMM equivalent (global_config, platform_config, event_authority, program), so treat it as the same pattern, not the same shape. See each program’s own section rather than assuming this walkthrough’s account list transfers directly.
Account list construction
Every Raydium CPI requires anAccounts struct in the calling program. Its fields are whatever accounts your instruction needs, with field-level validators; their declaration order doesn’t have to match Raydium’s own instruction account order, since your own IDL-generated client addresses them by name, not position:
UncheckedAccount because the callee (Raydium) owns the validation. Your calling program only strictly validates accounts you own, such as user ATAs and your own PDAs. The /// CHECK: doc-comment suppresses Anchor’s warning about missing checks. The one Raydium-side exception is cpmm_program itself: it’s the program being invoked rather than a data account Raydium validates internally, so it’s typed Program<T> and gets Anchor’s automatic address check instead of a manual /// CHECK:. This mostly-UncheckedAccount shape, where Raydium validates its own accounts, is the same for CLMM and LaunchLab. This example assumes both mints are classic SPL Token; if either side can be a Token-2022 mint, add a token_program_2022: Program<'info, anchor_spl::token_2022::Token2022> field and pass it as that side’s input_token_program/output_token_program in the CPI call below instead of token_program.
Building the CPI call
Anchor generates one helper per instruction, together with a CPI-accounts struct (cpi::accounts::Swap, aliased CpmmSwap below). Unlike your own MyProxySwap struct above, this one’s field names and order are fixed by raydium-cp-swap’s own IDL and have to match exactly:
cpi::swap_base_input is generated from the IDL; its argument list mirrors the Anchor instruction’s argument list. Every confirmed Anchor-based Raydium program (CPMM, CLMM, LaunchLab) generates its cpi::<ix>() helpers the same way, with the function name matching the instruction name in snake_case. Whether this extends to Farm v6 is unconfirmed; see its section.
Signer seeds (PDA-signed CPI)
When your program signs the CPI on behalf of a PDA (common for vaults, escrows, etc.), useCpiContext::new_with_signer:
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. Anchor’s CPI helpers do not type-check remaining accounts; pass them via.with_remaining_accounts(...):
- CLMM
SwapV2: tick arrays, ordered directionally. - Farm v6:
(reward_vault, user_reward_ata)pairs, but only from the second reward stream onward; see Farm v6 for what decoding a real transaction shows.
Applying the pattern: CLMM
SwapV2 follows the general pattern above with a different account list and a remaining-accounts requirement for tick arrays. The crate’s #[program] module is named raydium_clmm, which is also its Rust use path.
TickArrayNotFound (see products/clmm/instructions for the full account table and error list). Pass them in the direction of the price walk: first array in swap direction first.
Applying the pattern: LaunchLab
LaunchLab is Anchor-based and IDL-published:raydium_launchpad/raydium_launchpad.json in the public raydium-idl repo. That IDL’s internal metadata identifier is raydium_launchpad, a technical name for the underlying program, not an alternate name for the product. Unlike CPMM and CLMM, though, the program’s own source is not publicly available (see reference/program-addresses). There’s no git = "..." dependency to point Cargo at, and no source to confirm what a real crate’s Rust use-path would be.
Generate bindings from the published IDL using Anchor’s declare_program! macro. Save the IDL JSON as idls/raydium_launchpad.json in your crate (Cargo looks for an idls/ directory relative to CARGO_MANIFEST_DIR), then declare_program!(raydium_launchpad); generates raydium_launchpad::cpi::accounts::<Ix> structs and cpi::<ix>() functions straight from the IDL, no program source required. The generated accounts-struct name is always the instruction name in PascalCase (buy_exact_in → BuyExactIn), and field names match the IDL’s account names exactly, the same account list already used in MyProxyBuy below.
The CPI shape follows the general pattern. The account list and arguments below come from the on-chain IDL’s buy_exact_in instruction, not from products/launchlab/instructions.mdx:
pool_state.migrate_type, which products/launchlab/accounts.mdx says is set at Initialize time. Your CPI account list has to be prepared for either, or you need to read migrate_type off PoolState first and branch.
Error propagation
Each Anchor-based Raydium program returns its own error enum; Anchor wraps them, so your calling program sees them asErr(ProgramError::Custom(code)). To handle specific errors:
raydium_clmm::error::ErrorCode for CLMM, and so on). Error code numbers are stable per the IDL policy (sdk-api/anchor-idl), so you can test against specific codes by comparing against the numeric value. Full error tables: CPMM, CLMM, AMM v4, Farm v6, and LaunchLab.
Compute budget in composed CPIs
Each CPI frame has overhead, and the callee’s own CU consumption stacks on top of yours, so a transaction that calls into Raydium from inside your program needs an explicit compute budget rather than relying on the 200k CU default.Measured, not estimated. A CPMM
swap_base_input on mainnet consumes ~23,000 CU in the CPMM program itself — sampled 2026-09-09 across eight live swaps on a high-volume pool (22,721–23,052), read from the Program CPMMoo8… consumed N of M compute units log line. For comparison: AMM v4 swap ~26,000; CLMM swap ~41,000; CLMM swap_v2 ~48,000 (43,838–52,887), rising with each tick crossing.An earlier revision of this page reported ~47,700 CU for a proxy-swap CPI. That figure was the whole transaction (computeUnitsConsumed), which includes the caller’s own program, the CPI frame and any ATA setup — not the callee’s cost. Both are useful, but they are not the same number, so compare like with like. Measure your own transaction rather than budgeting off either.remaining_accounts, adding CU per array), but only the CPMM figure above is a measured value. Always set an explicit ComputeBudgetProgram::set_compute_unit_limit(...) instruction sized from your own measurement, not a number copied from documentation, since the default 200k CU limit will silently exhaust and per-instruction costs shift as programs are upgraded.
AMM v4: manual Instruction construction
AMM v4 predates Anchor and has no CPI crate, making it the one program in this doc that doesn’t follow the general pattern above. Build theInstruction by hand:
products/amm-v4/code-demos for the full account list.
Farm v6
Use the TS SDK if that’s an option for your integration.raydium.farm.deposit(...) (see products/farm-staking/code-demos) is exercised by real demos and doesn’t depend on whether a Rust Anchor crate exists for this program.
If you need Rust CPI regardless, for example composing from another on-chain program, build the Instruction by hand, the same way as AMM v4: derive the real account list and instruction discriminators independently, for example by decoding the SDK’s TypeScript layouts (raydium-sdk-V2’s farm module), decoding real transactions directly (see below), or dumping and disassembling the deployed program.
For the zero-argument instruction shape consistent with a harvest or claim call, the real account order is a fixed prefix (token_program, the farm’s state account, a vault-authority PDA, that PDA’s first reward vault, a second PDA, the caller, and the caller’s ATA for that first reward mint), followed by (reward_vault_i, user_reward_ata_i) pairs in remaining_accounts for every reward stream after the first. The pairing convention is real, but it only starts at the second reward stream: the first stream’s vault and ATA are fixed accounts, not adjacent to each other, and not part of remaining_accounts at all.
Testing a CPI flow
Local dev requires the Raydium programs to be available in your test validator. Three options:anchor testwith program clone. Pulls deployed mainnet bytecode into your local validator; see Cloning programs into a local validator below for theAnchor.tomlconfig and two things that trip up pool-creation tests specifically.- Devnet. Raydium deploys most programs to devnet, but at different program IDs than mainnet for every program (CPMM, CLMM, AMM v4, Stable AMM, and LaunchLab each have a distinct devnet address; see the Devnet table in
reference/program-addresses). Farm v3/v5/v6 aren’t reliably published on devnet; the live API (https://api-v3-devnet.raydium.io/main/info) has the current picture. If you useraydium_clmm’s bundledDEVNET_PROGRAM_IDconstants (or the equivalent for other crates), don’t assume a mainnet ID also works on devnet. Runanchor test --provider.cluster devnetto hit live code once you have the right addresses. - Local deploy. Clone the Raydium repos (CPMM, CLMM; LaunchLab’s source isn’t available for this option) and
anchor deployto a local validator. Adds test cycle overhead but lets you modify the callee for debugging.
anchor test, or anchor build first and anchor test --skip-build after if you’re iterating on the test file without changing the program.
Cloning programs into a local validator
reference/program-addresses is the source of truth for every address here.
Pointers
products/cpmm/code-demos,products/clmm/code-demos,products/amm-v4/code-demos,products/farm-staking/code-demos,products/launchlab/code-demos: product-specific CPI and TypeScript examples.sdk-api/anchor-idl: IDL retrieval and client regeneration, including the IDL-codegen path for LaunchLab.integration-guides/cpi-integration: higher-level integration patterns like escrows, vaults, and aggregator composition.
- raydium-cp-swap
- raydium-clmm
- raydium-idl: LaunchLab IDL (program source itself is closed)
- Anchor CPI docs

