DEV Community

Cover image for The Solana CPI Field Guide: Function Calls with a Guest List - Hala Kabir
Hala Kabir
Hala Kabir

Posted on

The Solana CPI Field Guide: Function Calls with a Guest List - Hala Kabir

The Solana CPI Field Guide

Five days ago, CPI (Cross-Program Invocation) felt like a confusing wall of boilerplate code. If you are starting out, here is the exact mental model I wish someone had handed me on Day 71.

🧠 The Mental Model: A Guest List

Think of a CPI as a standard function call, but it requires a strict "guest list". In Solana, programs are completely stateless. When your program wants to call another program, you have to pass three specific components:

  1. The Program ID: The address of the program you are calling so the runtime knows where to route the request.
  2. The Accounts: A list of every account that the target program needs to read from or write to.
  3. The Authority (Signers): If you are invoking on behalf of a PDA, your program must provide the original seeds to prove it has the authority to sign.

💻 The Code

Here is a clean, minimal layout of what a CPI to the System Program looks like in Anchor. This handles a simple lamport transfer:

#[derive(Accounts)]
pub struct ScatterTransfer<'info> {
    #[account(mut)]
    pub from: Signer<'info>,
    #[account(mut)]
    pub to: AccountInfo<'info>,
    pub system_program: Program<'info, System>,
}

pub fn execute_cpi(ctx: Context<ScatterTransfer>, amount: u64) -> Result<()> {
    let cpi_accounts = Transfer {
        from: ctx.accounts.from.to_account_info(),
        to: ctx.accounts.to.to_account_info(),
    };
    let cpi_program = ctx.accounts.system_program.to_account_info();
    let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts);

    anchor_lang::system_program::transfer(cpi_ctx, amount)?;
    Ok(())
}
Enter fullscreen mode Exit fullscreen mode

⚠️ What Tripped Me Up

When working through real implementations, the runtime can feel incredibly vocal. One error that completely stalled progress was custom program error: 0xbbd (AccountNotEnoughKeys).

This error happens at the physical boundary where your client and program interact. It simply means the client file failed to pass all of the required keys defined in your Anchor validation struct. When you see it, top-down validation checks are your best friend: verify that your TypeScript test structure precisely aligns with your Rust layout.

📚 Wrap Up

Mastering CPIs isn't about memorizing syntax; it's about checking your constraints and verifying boundaries. For a deeper look into the low-level mechanics, check out the Solana CPI Docs and the Anchor Framework Reference.

This post documents the journey across Days 71–75 of #100DaysOfSolana.

#HaveACoderfullday
Enter fullscreen mode Exit fullscreen mode

Top comments (0)