Passing Accounts to CPIs
CPI account lists must mirror the callee's expected order, signer flags, and writability. Your program is responsible for not elevating privileges beyond what the outer transaction intended.
Search across all documentation pages
CPI account lists must mirror the callee's expected order, signer flags, and writability. Your program is responsible for not elevating privileges beyond what the outer transaction intended.
let metas = vec![
AccountMeta::new(source, false),
AccountMeta::new(dest, false),
AccountMeta::new_readonly(authority, true),
];When to reach for this:
// Validate source writable only if caller intended mutation
if !source.is_writable { return Err(ProgramError::InvalidAccountData); }
let ix = spl_token::instruction::transfer(...)?;
invoke(&ix, &[source.clone(), dest.clone(), authority.clone(), token_program.clone()])?;What this demonstrates:
Passing writable + signer to callee when outer tx did not authorize is a critical bug.
Follow callee source definitions (spl-token, system).
// AccountMeta::new_readonly(key, is_signer)| Alternative | Use When | Don't Use When |
|---|---|---|
| spl instruction builders | Correct metas | Custom programs |
| Anchor cpi module | Generated | Manual |
| Codama clients | Off-chain only | On-chain still manual |
Callee program re-validates.
Outer tx signers + invoke_signed only.
Callee errors.
Resolved before runtime.
Use remaining accounts pattern in Anchor.
Reentrancy considerations.
Usually readonly program account.
If callee requires.
Extra signer accounts.
Show callee program id.
Cheap.
LiteSVM negative tests.
Stack versions: This page was written for Agave 4.1.1, Solana CLI 3.0.10, Anchor 0.32.1, anchor-lang 0.32.1, Rust 1.91.1, @solana/kit 7.0.0, Surfpool 0.12.0, and LiteSVM 0.6.x.
Reviewed by Chris St. John·Last updated Jul 19, 2026