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.
Recipe
invoke(&ix, accounts)?; // wallet signers only
invoke_signed(&ix, accounts, seeds)?; // + PDA signersWhen to reach for this:
- Debiting a vault PDA.
- Minting with PDA mint authority.
- Creating accounts owned by your program.
Working Example
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:
- PDA vault signs system transfer.
- Single seed group with bump byte.
- Without invoke_signed CPI fails missing signature.
Deep Dive
Comparison
| invoke | invoke_signed | |
|---|---|---|
| PDA sign | No | Yes |
| CU | Lower | Slightly higher |
| Risk | Lower if no custody | Seed bugs critical |
Rust Notes
// seeds: &[&[u8]] - array of seed slicesGotchas
- invoke for PDA authority - MissingRequiredSignature.. Fix: Use invoke_signed.
- Wrong seeds - Silent failure or error.. Fix: Centralize seed builder.
- Wallet could sign PDA? - No private key exists.. Fix: Program only.
- Delegate confusion - Token delegate is not PDA program sign.. Fix: Read token rules.
- Multiple seed groups - Order matters for multi-PDA CPI.. Fix: Test each path.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
| Client co-sign | User pays directly | Autonomous vault |
| Nonce account pattern | Durable keys | PDA custody |
FAQs
Can invoke_signed add wallet sig?
No - only PDA program signatures.
Depth limit?
4 including nested CPIs.
Token mint CPI?
Often invoke_signed.
System create account?
invoke_signed for PDA payer.
Simulate?
Same rules in LiteSVM.
Anchor CpiContext
Wraps invoke_signed with seeds.
Failed seed error?
InvalidSeeds or missing signature.
Cross-program PDA?
Owning program must CPI.
Audit?
Every invoke_signed line.
Seeds lifetime?
Borrow checker enforces.
Optional signer meta?
PDA meta signer true.
invoke from Anchor?
Macro selects based on seeds.
Related
- Signing with PDAs - PDA signing
- CPI to the System Program - SOL transfers
- Passing Accounts to CPIs - Account metas
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.