invoke vs invoke_signed
invoke forwards only transaction signatures. invoke_signed adds PDA signatures derived from seed slices, enabling programs to move funds they custody.
Search across all documentation pages
invoke forwards only transaction signatures. invoke_signed adds PDA signatures derived from seed slices, enabling programs to move funds they custody.
invoke(&ix, accounts)?; // wallet signers only
invoke_signed(&ix, accounts, seeds)?; // + PDA signersWhen to reach for this:
pub fn move_from_vault(bump: u8, amount: u64, from: &AccountInfo, to: &AccountInfo, sys: &AccountInfo) -> ProgramResult {
let ix = system_instruction::transfer(from.key, to.key, amount);
invoke_signed(&ix, &[from.clone(), to.clone(), sys.clone()], &[&[b"vault", &[bump]]])
}What this demonstrates:
| invoke | invoke_signed | |
|---|---|---|
| PDA sign | No | Yes |
| CU | Lower | Slightly higher |
| Risk | Lower if no custody | Seed bugs critical |
// signers_seeds: &[&[&[u8]]]
// outer = one entry per PDA signer
// inner = that PDA's seeds + [bump]
&[
&[b"vault", user.key.as_ref(), &[vault_bump]],
&[b"mint_auth", &[mint_bump]],
]| Alternative | Use When | Don't Use When |
|---|---|---|
| Client co-sign | User pays directly | Autonomous vault |
| Nonce account pattern | Durable keys | PDA custody |
No - only PDA program signatures.
4 including nested CPIs.
Often invoke_signed.
invoke_signed for PDA payer.
Same rules in LiteSVM.
Wraps invoke_signed with seeds.
InvalidSeeds or missing signature.
Owning program must CPI.
Every invoke_signed line.
Borrow checker enforces.
PDA meta signer true.
Macro selects based on seeds.
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 16, 2026