Skip to main content
Use CPI when your Solana program must call DAMM v2 directly, for example to swap, add or remove liquidity, claim fees or rewards, or manage a DAMM v2 position as part of a larger protocol instruction.
The stable integration contract is the public cp-amm program, the published IDL, and the official SDK behavior. This page is cross-checked against the cp-amm source so account ordering and remaining-account notes match the on-chain handlers.

Program ID

The public program ID is the same for mainnet and devnet.

Generated Bindings

Prefer generated CPI bindings from the cp-amm IDL. The handlers use Anchor accounts, optional accounts, generated instruction args, #[event_cpi], and a custom optimized swap entrypoint with Anchor fallback.
Do not hand-type account order from memory. Generate bindings or compare against SDK-built instructions. Most CPI failures come from one misplaced optional account, event authority account, position NFT account, token program, or rate-limiter remaining account.
The public integration contract is: You can generate a client from the IDL or depend on the public cp-amm crate from the DAMM v2 workspace when your build setup allows it. If you depend on the Rust crate for CPI, enable the CPI-compatible features from the workspace:
When importing from the public workspace, keep the crate revision aligned with the IDL and SDK version you test against.

CPI Instruction Scope

For the full cp-amm instruction-family map, see DAMM v2 Program Instructions. This page focuses on CPI implementation details for the user instructions most integrations call: swap2, add_liquidity, remove_liquidity, claim_position_fee, claim_reward, and position lock flows. For off-chain apps, bots, and launch scripts, the TypeScript SDK is usually simpler and safer.

Account Planning

Read token mint and vault addresses from pool state whenever possible. Avoid reconstructing token A/B assumptions from user input alone.

Event CPI Accounts

Most cp-amm account structs use #[event_cpi]. Generated clients include event CPI accounts after the instruction’s primary accounts: Keep these accounts in the generated order. They are part of Anchor’s account validation even though they are not business-state accounts.

Remaining Accounts

Rate-limiter pools reject swaps that do not include the instructions sysvar because the program validates single-swap behavior for that pool in the transaction. This remaining-account requirement applies to existing rate-limiter pools. New configs and new pools cannot use BaseFeeMode::RateLimiter.
For swap and swap2, the optimized swap path expects the fixed swap account list plus remaining accounts. For existing rate-limiter pools, if the rate limiter is active, put the instructions sysvar as the first remaining account. Normal non-rate-limiter swaps do not need remaining accounts. Token 2022 transfer-hook accounts are not a general DAMM v2 CPI surface. DAMM v2 accepts Transfer Hook permissionlessly only when both the hook program ID and authority are unset. Mints outside that allowlist need a token badge to pass mint validation, but DAMM v2 still does not forward transfer-hook extra accounts on transfers. See Token 2022 support.
initialize_pool and initialize_pool_with_dynamic_config skip permissionless-mint and token-badge checks when the private config has CreatePoolWithoutMintValidation. initialize_customizable_pool always validates mints (skip=false) and still expects token badge remaining accounts at index 0 (token A) and index 1 (token B) when a mint is not permissionless-supported. Token-2022 wrapped SOL is still rejected.

Swap CPI Shape

For generated Anchor CPI, the account set mirrors SwapCtx: swap2 parameters use the same semantics as the SDK:

Common CPI Failures

Best Practices