LiteSVM Docs
Additional Cratesanchor-litesvm

Program & Context

Setting up test environments and building instructions with AnchorContext and Program

Setting Up the Test Environment

The AnchorLiteSVM builder provides a fluent API for configuring your test environment.

Basic Setup

use anchor_litesvm::{AnchorLiteSVM, AnchorContext};
use solana_sdk::pubkey::Pubkey;

// Define your program ID
const PROGRAM_ID: Pubkey = solana_sdk::pubkey!("YourProgram11111111111111111111111111111111");

#[test]
fn test_basic_setup() {
    // Build context with your program
    let ctx: AnchorContext = AnchorLiteSVM::new()
        .deploy_program(PROGRAM_ID, include_bytes!("../target/deploy/your_program.so"))
        .build();

    // Context is ready to use
    println!("Program deployed: {}", ctx.program().id());
}

Single Program Shorthand

use anchor_litesvm::AnchorLiteSVM;

#[test]
fn test_single_program() {
    // Convenience method for single-program setups
    let ctx = AnchorLiteSVM::build_with_program(
        PROGRAM_ID,
        include_bytes!("../target/deploy/your_program.so"),
    );
}

Multiple Programs

use anchor_litesvm::AnchorLiteSVM;
use solana_sdk::pubkey::Pubkey;

const PROGRAM_A: Pubkey = solana_sdk::pubkey!("ProgramA1111111111111111111111111111111111");
const PROGRAM_B: Pubkey = solana_sdk::pubkey!("ProgramB1111111111111111111111111111111111");

#[test]
fn test_multiple_programs() {
    // Deploy multiple programs - first one becomes primary
    let ctx = AnchorLiteSVM::build_with_programs(&[
        (PROGRAM_A, include_bytes!("../target/deploy/program_a.so")),
        (PROGRAM_B, include_bytes!("../target/deploy/program_b.so")),
    ]);

    // Primary program is PROGRAM_A
    assert_eq!(ctx.program().id(), PROGRAM_A);
}

Custom Payer

use anchor_litesvm::AnchorLiteSVM;
use solana_sdk::signature::Keypair;

#[test]
fn test_custom_payer() {
    let custom_payer = Keypair::new();

    let ctx = AnchorLiteSVM::new()
        .with_payer(custom_payer)
        .deploy_program(PROGRAM_ID, include_bytes!("../target/deploy/your_program.so"))
        .build();

    // Use the custom payer
    println!("Payer: {}", ctx.payer().pubkey());
}

If you don't specify a payer, AnchorLiteSVM automatically creates and funds one for you.

The AnchorContext

AnchorContext is the main interface for interacting with your test environment.

Core Properties

use anchor_litesvm::AnchorLiteSVM;
use solana_sdk::signature::Signer;

#[test]
fn test_context_properties() {
    let ctx = AnchorLiteSVM::build_with_program(PROGRAM_ID, include_bytes!("../target/deploy/your_program.so"));

    // Access the underlying LiteSVM instance
    let svm = &ctx.svm;

    // Get the payer keypair
    let payer = ctx.payer();
    println!("Payer pubkey: {}", payer.pubkey());

    // Get the Program instance
    let program = ctx.program();
    println!("Program ID: {}", program.id());

    // Get the latest blockhash
    let blockhash = ctx.latest_blockhash();
}

Creating Funded Accounts

use anchor_litesvm::AnchorLiteSVM;
use solana_sdk::native_token::LAMPORTS_PER_SOL;

#[test]
fn test_create_accounts() {
    let mut ctx = AnchorLiteSVM::build_with_program(PROGRAM_ID, include_bytes!("../target/deploy/your_program.so"));

    // Create a funded account
    let user = ctx.create_funded_account(10 * LAMPORTS_PER_SOL);

    // Or airdrop to an existing address
    let another_user = solana_sdk::signature::Keypair::new();
    ctx.airdrop(&another_user.pubkey(), 5 * LAMPORTS_PER_SOL);
}

Checking Account Existence

use anchor_litesvm::AnchorLiteSVM;
use solana_sdk::pubkey::Pubkey;

#[test]
fn test_account_exists() {
    let ctx = AnchorLiteSVM::build_with_program(PROGRAM_ID, include_bytes!("../target/deploy/your_program.so"));

    let some_pda = Pubkey::new_unique();

    if ctx.account_exists(&some_pda) {
        println!("Account exists!");
    } else {
        println!("Account not found");
    }
}

Building Instructions with Program

The Program struct provides a fluent API for building instructions that mirrors anchor-client.

Basic Instruction Building

use anchor_litesvm::AnchorLiteSVM;
use anchor_lang::prelude::*;
use solana_sdk::signature::Signer;

// Your instruction accounts struct (from your Anchor program)
#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(mut)]
    pub user: Signer<'info>,
    pub system_program: Program<'info, System>,
}

// Your instruction data (from your Anchor program)
#[derive(AnchorSerialize, AnchorDeserialize)]
pub struct InitializeArgs {
    pub name: String,
}

#[test]
fn test_build_instruction() {
    let ctx = AnchorLiteSVM::build_with_program(PROGRAM_ID, include_bytes!("../target/deploy/your_program.so"));

    let user = ctx.payer();

    // Build instruction using fluent API
    let ix = ctx.program()
        .accounts(Initialize {
            user: user.pubkey(),
            system_program: solana_sdk::system_program::id(),
        })
        .args(InitializeArgs {
            name: "test".to_string(),
        })
        .instruction()
        .unwrap();

    println!("Instruction built successfully!");
}

The .accounts() method accepts any type that implements ToAccountMetas, which all Anchor account structs do automatically.

Executing Instructions

use anchor_litesvm::AnchorLiteSVM;
use solana_sdk::{native_token::LAMPORTS_PER_SOL, signature::Signer};

#[test]
fn test_execute_instruction() {
    let mut ctx = AnchorLiteSVM::build_with_program(PROGRAM_ID, include_bytes!("../target/deploy/your_program.so"));

    let user = ctx.create_funded_account(10 * LAMPORTS_PER_SOL);

    let ix = ctx.program()
        .accounts(Initialize {
            user: user.pubkey(),
            system_program: solana_sdk::system_program::id(),
        })
        .args(InitializeArgs { name: "test".to_string() })
        .instruction()
        .unwrap();

    // Execute single instruction
    ctx.execute_instruction(ix, &[&user]).unwrap();
}

Executing Multiple Instructions

use anchor_litesvm::AnchorLiteSVM;
use solana_sdk::{native_token::LAMPORTS_PER_SOL, signature::Signer};

#[test]
fn test_execute_multiple_instructions() {
    let mut ctx = AnchorLiteSVM::build_with_program(PROGRAM_ID, include_bytes!("../target/deploy/your_program.so"));

    let user = ctx.create_funded_account(10 * LAMPORTS_PER_SOL);

    let ix1 = ctx.program()
        .accounts(Initialize { /* ... */ })
        .args(InitializeArgs { name: "first".to_string() })
        .instruction()
        .unwrap();

    let ix2 = ctx.program()
        .accounts(Update { /* ... */ })
        .args(UpdateArgs { name: "second".to_string() })
        .instruction()
        .unwrap();

    // Execute multiple instructions in one transaction
    ctx.execute_instructions(vec![ix1, ix2], &[&user]).unwrap();
}

Using send_and_confirm_transaction

use anchor_litesvm::AnchorLiteSVM;
use solana_sdk::{
    message::Message,
    signature::Signer,
    transaction::Transaction,
};

#[test]
fn test_send_transaction() {
    let mut ctx = AnchorLiteSVM::build_with_program(PROGRAM_ID, include_bytes!("../target/deploy/your_program.so"));

    let user = ctx.create_funded_account(10 * LAMPORTS_PER_SOL);

    let ix = ctx.program()
        .accounts(Initialize { /* ... */ })
        .args(InitializeArgs { name: "test".to_string() })
        .instruction()
        .unwrap();

    // Build transaction manually if needed
    let message = Message::new(&[ix], Some(&ctx.payer().pubkey()));
    let tx = Transaction::new(&[ctx.payer(), &user], message, ctx.latest_blockhash());

    // Send and confirm
    ctx.send_and_confirm_transaction(tx).unwrap();
}

Complete Example

Here's a comprehensive example demonstrating the full workflow:

use anchor_litesvm::{AnchorLiteSVM, AnchorContext};
use anchor_lang::prelude::*;
use solana_sdk::{
    native_token::LAMPORTS_PER_SOL,
    signature::Signer,
    pubkey::Pubkey,
};

declare_id!("YourProgram11111111111111111111111111111111");

#[account]
pub struct UserAccount {
    pub name: String,
    pub balance: u64,
}

#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(mut)]
    pub user: Signer<'info>,
    #[account(
        init,
        payer = user,
        space = 8 + 32 + 8,
        seeds = [b"user", user.key().as_ref()],
        bump
    )]
    pub user_account: Account<'info, UserAccount>,
    pub system_program: Program<'info, System>,
}

#[test]
fn test_complete_workflow() {
    // 1. Setup test environment
    let mut ctx = AnchorLiteSVM::new()
        .deploy_program(id(), include_bytes!("../target/deploy/your_program.so"))
        .build();

    // 2. Create test user
    let user = ctx.create_funded_account(10 * LAMPORTS_PER_SOL);

    // 3. Derive PDA
    let (user_pda, _bump) = Pubkey::find_program_address(
        &[b"user", user.pubkey().as_ref()],
        &id(),
    );

    // 4. Build instruction
    let ix = ctx.program()
        .accounts(Initialize {
            user: user.pubkey(),
            user_account: user_pda,
            system_program: solana_sdk::system_program::id(),
        })
        .args(instruction::Initialize {
            name: "Alice".to_string(),
        })
        .instruction()
        .unwrap();

    // 5. Execute
    ctx.execute_instruction(ix, &[&user]).unwrap();

    // 6. Verify
    let account: UserAccount = ctx.get_account(&user_pda).unwrap();
    assert_eq!(account.name, "Alice");

    println!("Test passed!");
}