Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Quickstart

Deploy an Anchor program, deposit into it, and print the structured logs: that’s the fastest path to a passing test.

See the Vault chapter for the same program driven in depth.

Get the code

The programs and tests live in one repo, whose workspace already wires up anchor-litesvm and the litesvm fork it builds on. Until those land upstream, clone the fork and work from inside it:

git clone -b feat/buildable-ix https://github.com/cds-rs/anchor-litesvm
cd anchor-litesvm
cargo test -p anchor-litesvm --test book_vault

There is nothing to add to a Cargo.toml: the workspace resolves every dependency. That command runs the vault chapter’s test against the committed vault.so fixture, and the rest of this page is the code it runs.

The test

Three things below are worth naming before you hit them, since the code leans on all three without pausing to explain itself.

ctx.cast_actor("Alice") casts an actor: a funded, named keypair standing in for a real signer. From here on, the test (and the printed logs) refer to her as Alice instead of a 44-character pubkey.

The comment about PDAs refers to Program Derived Addresses: account addresses derived deterministically from seeds instead of from a keypair, which is how a program can own and sign for vault_state and vault below without anyone holding a private key for them.

And InitializeBundle / DepositBundle are bundles: generated structs that hold exactly the accounts a given instruction’s caller needs to supply, PDAs already derived, so you only fill in what actually varies per call (here, just user).

#![allow(unused)]
#![allow(unexpected_cfgs)]

fn main() {
use anchor_lang::{self};
use anchor_litesvm::AnchorLiteSVM;
use solana_signer::Signer;

anchor_lang::declare_program!(vault);
anchor_litesvm::bundles_from_idl!(vault);

#[test]
fn deposit_happy_path() {
    // vault.so is the committed fixture; book_vault.rs loads the same bytes
    // with common::fixture_bytes("vault").
    let mut ctx = AnchorLiteSVM::build_with_program(
        vault::ID,
        "vault",
        include_bytes!("fixtures/vault.so"),
    );
    let alice = ctx.cast_actor("Alice");

    // initialize creates the vault_state + vault PDAs for Alice.
    ctx.tx(&[&alice])
        .build(
            InitializeBundle {
                user: alice.pubkey(),
            },
            vault::client::args::Initialize {},
        )
        .send_ok();

    // deposit 1 SOL.
    ctx.tx(&[&alice])
        .build(
            DepositBundle {
                user: alice.pubkey(),
            },
            vault::client::args::Deposit {
                amount: 1_000_000_000,
            },
        )
        .send_ok()
        .print_logs();
}
}

declare_program! (from anchor_lang) is the macro that generates the typed client from the vault IDL. bundles_from_idl! (from anchor_litesvm) is the one that generates the bundles you just met above, one per instruction.

print_logs() renders the transaction as a CPI tree, program logs and all: the same format introduced above, printed instead of just returned.

Next: the Vault chapter drives the same program deeper (events, the escape hatch, a rejected transaction).

Concepts covers aliases, the World, and structured logs from here, in more depth than a quickstart has room for.