Week 3 • Cpi Cross Program
Cross-Program Invocations (CPI)
Learn CPI in Anchor by calling other Solana programs safely: CPI contexts, signer seeds, authority delegation, and failure-path testing.
CPI is how your program composes with the rest of Solana.
Think of it as: "My program asks another trusted program to perform a specific action."
When You Need CPI
- Transfer tokens with Token or Token-2022
- Interact with system program (
create_account,transfer) - Integrate with external protocols (DEX, lending, staking)
CPI Anatomy
A CPI call in Anchor needs:
- Target program account
- CPI account struct (
MintTo,TransferChecked, etc.) - Signer seeds if a PDA must sign
Example: PDA-Signed Token Transfer
pub fn release_from_vault(ctx: Context<ReleaseFromVault>, amount: u64, decimals: u8) -> Result<()> {
let escrow_key = ctx.accounts.escrow.key();
let signer_seeds: &[&[&[u8]]] = &[&[
b"vault-authority",
escrow_key.as_ref(),
&[ctx.bumps.vault_authority],
]];
let cpi_accounts = anchor_spl::token_interface::TransferChecked {
mint: ctx.accounts.mint.to_account_info(),
from: ctx.accounts.vault_ata.to_account_info(),
to: ctx.accounts.receiver_ata.to_account_info(),
authority: ctx.accounts.vault_authority.to_account_info(),
};
let cpi_ctx = CpiContext::new_with_signer(
ctx.accounts.token_program.to_account_info(),
cpi_accounts,
signer_seeds,
);
anchor_spl::token_interface::transfer_checked(cpi_ctx, amount, decimals)?;
Ok(())
}CPI Safety Checklist
- Validate every account before CPI call
- Ensure signer PDA seeds are exactly what you expect
- Confirm token mint and decimals assumptions
- Prevent privilege escalation by checking authorities
Most CPI bugs are validation bugs, not CPI API bugs.
Testing CPI Flows
- Success path with valid accounts
- Wrong target program id fails
- Wrong PDA seeds fail
- Wrong authority fails
- Wrong mint account fails
Solana-Dev Integration Note
For off-chain integration tests and service scripts, prefer @solana/kit transaction flows. If your current Anchor test stack uses web3 types, isolate those conversions in one compatibility module.
Try This Next
- Add CPI event logging before and after call for observability.
- Add compute-budget instruction when CPI stack grows.
- Prototype a CPI wrapper module to keep handlers small and testable.