anchor-litesvm

Crates.ioanchor-litesvm
lib.rsanchor-litesvm
version0.3.0
created_at2025-09-20 00:18:23.235787+00
updated_at2026-01-12 22:58:49.18224+00
descriptionSimplified Anchor testing with LiteSVM - similar syntax to anchor-client, 78% less code
homepage
repositoryhttps://github.com/brimigs/anchor-litesvm
max_upload_size
id1847287
size164,741
(brimigs)

documentation

https://docs.rs/anchor-litesvm

README

anchor-litesvm

Simplified Anchor testing with LiteSVM - Similar syntax to anchor-client, 78% less code, no mock RPC needed.

Crates.io Documentation License: MIT

Overview

anchor-litesvm provides a streamlined testing experience for Anchor programs. It combines the familiar syntax of anchor-client with the speed of LiteSVM, plus comprehensive testing utilities.

Key Benefits:

  • 78% less code compared to raw LiteSVM
  • 40% faster compilation than anchor-client (no network dependencies)
  • No mock RPC - zero configuration needed
  • Familiar syntax - similar to anchor-client, transferable knowledge

Installation

[dev-dependencies]
anchor-litesvm = "0.3"

Quick Start

use anchor_litesvm::AnchorLiteSVM;
use litesvm_utils::{AssertionHelpers, TestHelpers};
use solana_sdk::signature::Signer;

// Generate client types from your program
anchor_lang::declare_program!(my_program);

#[test]
fn test_my_anchor_program() {
    // 1. One-line setup - no mock RPC needed
    let mut ctx = AnchorLiteSVM::build_with_program(
        my_program::ID,
        include_bytes!("../target/deploy/my_program.so"),
    );

    // 2. Create accounts with built-in helpers
    let user = ctx.svm.create_funded_account(10_000_000_000).unwrap();
    let mint = ctx.svm.create_token_mint(&user, 9).unwrap();

    // 3. Build instruction with simplified syntax (similar to anchor-client)
    let ix = ctx.program()
        .accounts(my_program::client::accounts::Initialize {
            user: user.pubkey(),
            mint: mint.pubkey(),
            system_program: solana_sdk::system_program::id(),
        })
        .args(my_program::client::args::Initialize { amount: 1_000_000 })
        .instruction()
        .unwrap();

    // 4. Execute and verify
    ctx.execute_instruction(ix, &[&user])
        .unwrap()
        .assert_success();

    // 5. Deserialize Anchor accounts
    let account_data: MyAccount = ctx.get_account(&pda).unwrap();
}

Why anchor-litesvm?

Feature anchor-client + LiteSVM anchor-litesvm
Lines of Code 279 lines 106 lines
Compilation Slow (network deps) 40% faster
Setup Mock RPC needed No config
Token Operations Manual (30+ lines) 1 line
Syntax anchor-client Similar

No More Account Ordering Bugs

The #1 pain point in Solana testing - eliminated:

// Raw LiteSVM - order matters, easy to get wrong
let instruction = Instruction {
    accounts: vec![
        AccountMeta::new(maker.pubkey(), true),   // Must be position 0
        AccountMeta::new(escrow_pda, false),       // Must be position 1
        // Wrong order = silent failure or wrong accounts
    ],
    ..
};

// anchor-litesvm - named fields, order doesn't matter
let ix = ctx.program()
    .accounts(my_program::client::accounts::Make {
        escrow: escrow_pda,  // Any order works
        maker: maker.pubkey(),
        // Compiler ensures all fields present
    })
    .args(...)
    .instruction()?;

Features

Simplified Instruction Building

let ix = ctx.program()
    .accounts(my_program::client::accounts::Transfer {
        from: from_account,
        to: to_account,
        authority: user.pubkey(),
    })
    .args(my_program::client::args::Transfer { amount: 100 })
    .instruction()?;

ctx.execute_instruction(ix, &[&user])?.assert_success();

Anchor Account Deserialization

// Deserialize with discriminator check
let account: MyAccount = ctx.get_account(&pda)?;

// Deserialize without check (for PDAs with custom layouts)
let account: MyAccount = ctx.get_account_unchecked(&pda)?;

Event Parsing

use anchor_litesvm::EventHelpers;

let result = ctx.execute_instruction(ix, &[&user])?;

// Parse all events of a type
let events: Vec<TransferEvent> = result.parse_events()?;

// Parse first event
let event: TransferEvent = result.parse_event()?;

// Check if event was emitted
assert!(result.has_event::<TransferEvent>());
result.assert_event_emitted::<TransferEvent>();

All litesvm-utils Features Included

Since anchor-litesvm builds on litesvm-utils, you get all utilities:

// Account creation
let user = ctx.svm.create_funded_account(10_000_000_000)?;

// Token operations
let mint = ctx.svm.create_token_mint(&user, 9)?;
let ata = ctx.svm.create_associated_token_account(&mint.pubkey(), &user)?;
ctx.svm.mint_to(&mint.pubkey(), &ata, &user, 1_000_000)?;

// Assertions
ctx.svm.assert_token_balance(&ata, 1_000_000);
ctx.svm.assert_account_exists(&pda);

// PDA derivation
let (pda, bump) = ctx.svm.get_pda_with_bump(&[b"seed"], &program_id);

// Transaction analysis
result.print_logs();
let cu = result.compute_units();

Common Patterns

Token Testing

let mint = ctx.svm.create_token_mint(&authority, 9)?;
let token_account = ctx.svm.create_associated_token_account(&mint.pubkey(), &owner)?;
ctx.svm.mint_to(&mint.pubkey(), &token_account, &authority, 1_000_000)?;

// After your instruction
ctx.svm.assert_token_balance(&token_account, expected_balance);

PDA Usage

let (pda, bump) = ctx.svm.get_pda_with_bump(
    &[b"escrow", maker.pubkey().as_ref(), &seed.to_le_bytes()],
    &my_program::ID,
);

let ix = ctx.program()
    .accounts(my_program::client::accounts::Initialize {
        escrow: pda,
        // ...
    })
    .args(my_program::client::args::Initialize { seed, bump })
    .instruction()?;

Error Testing

let result = ctx.execute_instruction(ix, &[&user])?;

if !result.is_success() {
    result.print_logs();
    println!("Error: {:?}", result.error());
}

// Or assert specific errors
result.assert_error("InsufficientFunds");
result.assert_anchor_error(MyError::InvalidAmount);

Testing

cargo test -p anchor-litesvm    # 11 tests

Related Crates

License

MIT License - see LICENSE for details.

Commit count: 15

cargo fmt