---
title: Mollusk
description: Comprehensive guide to testing Solana programs using Mollusk
---

[Mollusk](https://github.com/anza-xyz/mollusk/tree/main) is a lightweight test
harness for testing Solana programs. It provides a simple interface for testing
Solana program instructions in a minified Solana Virtual Machine (SVM)
environment. All test accounts must be explicitly defined, ensuring
deterministic and repeatable tests.

- [Mollusk SVM Documentation](https://docs.rs/mollusk-svm/latest/mollusk_svm/)
- [Mollusk Test Usage Examples](https://github.com/anza-xyz/mollusk/tree/0.5.0/harness/tests)

## Installation

Add `mollusk-svm` as a dependency in `Cargo.toml`:

```terminal
$ cargo add mollusk-svm --dev
```

```toml title="Cargo.toml"
[dev-dependencies]
mollusk-svm = "0.7"
```

To benchmark compute unit usage, add `mollusk-svm-bencher` as dependency in
`Cargo.toml`:

```terminal
$ cargo add mollusk-svm-bencher --dev
```

```toml title="Cargo.toml"
[dev-dependencies]
mollusk-svm-bencher = "0.7"
```

To use the token program, token2022 program (token extensions), and associated
token program for testing with Mollusk, add `mollusk-svm-programs-token` as
dependency in `Cargo.toml`:

```terminal
$ cargo add mollusk-svm-programs-token --dev
```

```toml title="Cargo.toml"
[dev-dependencies]
mollusk-svm-programs-token = "0.7"
```

## Mollusk SVM

The following example shows a minimal setup for testing a basic Solana program
using Mollusk.

<ScrollyCoding>

## !!steps Hello World Program

This example demonstrates how to test a basic Solana program using Mollusk. The
program simply prints "Hello, world!" to the program logs when invoked.

Running `cargo build-sbf` generates the compiled program at
`/target/deploy/<program_name>.so`.

<CodePlaceholder title="src/lib.rs" />

<WithMentions>

To test a Solana program with Mollusk:

1. [Create a `Mollusk` instance](mention:mollusk) - Initialize Mollusk with a
   program ID and the path to the compiled program (`.so` file)
2. [Build an instruction](mention:instruction) - Create an instruction to invoke
   the program
3. [Process and validate](mention:process) - Process the instruction using
   Mollusk and validate the result

```rs title="src/lib.rs"
#[cfg(test)]
mod tests {
    use mollusk_svm::{result::Check, Mollusk};
    use solana_sdk::{instruction::Instruction, pubkey::Pubkey};

    #[test]
    fn test_hello_world() {
        let program_id = Pubkey::new_unique();
        // !mention mollusk
        let mollusk = Mollusk::new(&program_id, "target/deploy/hello_world");

        // !mention instruction
        let instruction = Instruction::new_with_bytes(program_id, &[], vec![]);

        // !mention process
        mollusk.process_and_validate_instruction(&instruction, &[], &[Check::success()]);
    }
}
```

</WithMentions>

To execute the test, run `cargo test`.

When the test runs successfully, you'll see output similar to the following:

```txt title="Terminal"
running 1 test
[2025-09-22T19:25:50.427685000Z DEBUG solana_runtime::message_processor::stable_log] Program 11157t3sqMV725NVRLrVQbAu98Jjfk1uCKehJnXXQs invoke [1]
[2025-09-22T19:25:50.429669000Z DEBUG solana_runtime::message_processor::stable_log] Program log: Hello, world!
[2025-09-22T19:25:50.429690000Z DEBUG solana_runtime::message_processor::stable_log] Program 11157t3sqMV725NVRLrVQbAu98Jjfk1uCKehJnXXQs consumed 211 of 1400000 compute units
[2025-09-22T19:25:50.429726000Z DEBUG solana_runtime::message_processor::stable_log] Program 11157t3sqMV725NVRLrVQbAu98Jjfk1uCKehJnXXQs success
test tests::test_hello_world ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s

   Doc-tests hello_world
```

```rs !! title="src/lib.rs"
use solana_program::{
    account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, msg, pubkey::Pubkey,
};

entrypoint!(process_instruction);

pub fn process_instruction(
    _program_id: &Pubkey,
    _accounts: &[AccountInfo],
    _instruction_data: &[u8],
) -> ProgramResult {
    msg!("Hello, world!");
    Ok(())
}

// !focus(1:15)
#[cfg(test)]
mod tests {
    use mollusk_svm::{result::Check, Mollusk};
    use solana_sdk::{instruction::Instruction, pubkey::Pubkey};

    #[test]
    fn test_hello_world() {
        let program_id = Pubkey::new_unique();
        let mollusk = Mollusk::new(&program_id, "target/deploy/hello_world");

        let instruction = Instruction::new_with_bytes(program_id, &[], vec![]);

        mollusk.process_and_validate_instruction(&instruction, &[], &[Check::success()]);
    }
}
```

```toml !! title="Cargo.toml"
[package]
name = "hello_world"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib", "lib"]

[dependencies]
solana-program = "2.2.0"

[dev-dependencies]
mollusk-svm = "0.5.0"
solana-sdk = "2.2.0"
```

```txt !! title="target/deploy/hello_world.so"
[binary]
```

</ScrollyCoding>

The
[`Mollusk`](https://docs.rs/mollusk-svm/0.5.0/mollusk_svm/struct.Mollusk.html)
struct provides a simple interface for testing Solana programs. All fields can
be manipulated through a handful of helper methods, but users can also directly
access and modify them if they desire more control.

To initialize Mollusk with a default instance use the `Mollusk::default` method.

```rust title="Example"
// Default instance with no custom programs
let mollusk = Mollusk::default();
```

To initialize Mollusk with a specific program use the `Mollusk::new` method.

```rust title="Example"
// Initialize Mollusk with a specific program from a file path
let program_id = Pubkey::new_unique();
let mollusk = Mollusk::new(&program_id, "target/deploy/my_program");
```

To add a program to Mollusk use the `Mollusk::add_program` method.

```rust title="Example"
let mollusk = Mollusk::default();
let program_id = Pubkey::new_unique();

// Add a program to Mollusk
mollusk.add_program(
    &program_id,
    "target/deploy/my_program",
    &bpf_loader_upgradeable::id(),
);
```

<Callout type="info">
  When providing the file path, do not include the `.so` extension. For example,
  `"path/to/my_program"` is correct, but `"path/to/my_program.so"` is not.
</Callout>

### Processing Instructions

Mollusk provides four main methods for processing instructions:

| Method                                                                         | Description                                                                                                |
| ------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------- |
| [`process_instruction`](#single-instruction)                                   | Process an instruction and return the result.                                                              |
| [`process_and_validate_instruction`](#single-instruction-with-checks)          | Process an instruction and perform a series of checks on the result, panicking if any checks fail.         |
| [`process_instruction_chain`](#multiple-instructions)                          | Process multiple instructions and return the result.                                                       |
| [`process_and_validate_instruction_chain`](#multiple-instructions-with-checks) | Process multiple instructions and perform a series of checks on each result, panicking if any checks fail. |

The
[`InstructionResult`](https://docs.rs/mollusk-svm-result/0.5.0/mollusk_svm_result/types/struct.InstructionResult.html)
contains the details of a processed instruction.

#### Single Instruction

Use the `process_instruction` method to process a single instruction without
checks on the result. You can manually validate the results after processing.

```rust title="Method Signature"
pub fn process_instruction(
    &self,
    instruction: &Instruction,
    accounts: &[(Pubkey, Account)],
) -> InstructionResult
```

The following example processes a SOL transfer instruction without validation
checks.

<Callout type="info">

The examples below run Mollusk in the `main` function for demonstration
purposes. In practice, you'll typically use Mollusk in a test module annotated
with the `#[test]` attribute.

</Callout>

<CodeTabs flags="r">

```rs !! title="Single Instruction"
use mollusk_svm::Mollusk;
use solana_sdk::{account::Account, pubkey::Pubkey};
use solana_system_interface::{instruction::transfer, program::ID as SYSTEM_PROGRAM_ID};

fn main() {
    // Initialize Mollusk
    let mollusk = Mollusk::default();

    // Set up accounts
    let sender = Pubkey::new_unique();
    let recipient = Pubkey::new_unique();

    let initial_lamports = 1_000_000;
    let transfer_amount = 250_000;

    // Create transfer instruction
    let instruction = transfer(&sender, &recipient, transfer_amount);

    // Define initial account states
    let accounts = vec![
        (
            sender,
            Account {
                lamports: initial_lamports,
                data: vec![],
                owner: SYSTEM_PROGRAM_ID,
                executable: false,
                rent_epoch: 0,
            },
        ),
        (
            recipient,
            Account {
                lamports: 0,
                data: vec![],
                owner: SYSTEM_PROGRAM_ID,
                executable: false,
                rent_epoch: 0,
            },
        ),
    ];

    // Process the instruction
    let result = mollusk.process_instruction(&instruction, &accounts);
    println!("{:#?}", result);

    // Check the result
    assert!(result.program_result.is_ok());
    assert_eq!(result.get_account(&sender).unwrap().lamports, 750_000);
    assert_eq!(result.get_account(&recipient).unwrap().lamports, 250_000);
}
```

</CodeTabs>

#### Single Instruction with Checks

Use the `process_and_validate_instruction` method to process a single
instruction with validation checks. This method will panic if any check fails.

```rust title="Method Signature"
pub fn process_and_validate_instruction(
    &self,
    instruction: &Instruction,
    accounts: &[(Pubkey, Account)],
    checks: &[Check],
) -> InstructionResult
```

The following example processes a SOL transfer instruction with validation
checks.

<CodeTabs flags="r">

```rs !! title="With Validation"
use {
    mollusk_svm::{result::Check, Mollusk},
    solana_sdk::{account::Account, pubkey::Pubkey},
    solana_system_interface::{instruction::transfer, program::ID as SYSTEM_PROGRAM_ID},
};

fn main() {
    let mollusk = Mollusk::default();

    let sender = Pubkey::new_unique();
    let recipient = Pubkey::new_unique();

    let initial_lamports = 1_000_000;
    let transfer_amount = 250_000;

    let instruction = transfer(&sender, &recipient, transfer_amount);

    let accounts = vec![
        (
            sender,
            Account {
                lamports: initial_lamports,
                data: vec![],
                owner: SYSTEM_PROGRAM_ID,
                executable: false,
                rent_epoch: 0,
            },
        ),
        (
            recipient,
            Account {
                lamports: 0,
                data: vec![],
                owner: SYSTEM_PROGRAM_ID,
                executable: false,
                rent_epoch: 0,
            },
        ),
    ];

    // Define validation checks
    let checks = vec![
        Check::success(),
        Check::account(&sender).lamports(750_000).build(),
        Check::account(&recipient).lamports(250_000).build(),
    ];

    // Process and validate (will panic if any check fails)
    let result = mollusk.process_and_validate_instruction(&instruction, &accounts, &checks);
    println!("{:#?}", result);
}
```

</CodeTabs>

#### Multiple Instructions

Use the `process_instruction_chain` method to process multiple instructions
sequentially without validation checks.

```rust title="Method Signature"
pub fn process_instruction_chain(
    &self,
    instructions: &[Instruction],
    accounts: &[(Pubkey, Account)],
) -> InstructionResult
```

The following example processes two SOL transfer instructions without validation
checks.

<CodeTabs flags="r">

```rs !! title="Multiple Instructions"
use {
    mollusk_svm::Mollusk,
    solana_sdk::{account::Account, pubkey::Pubkey},
    solana_system_interface::{instruction::transfer, program::ID as SYSTEM_PROGRAM_ID},
};

fn main() {
    let mollusk = Mollusk::default();

    // Set up accounts
    let alice = Pubkey::new_unique();
    let bob = Pubkey::new_unique();
    let charlie = Pubkey::new_unique();

    let initial_lamports = 1_000_000;

    // Create chain of transfers
    let instructions = vec![
        transfer(&alice, &bob, 300_000),   // Alice -> Bob
        transfer(&bob, &charlie, 100_000), // Bob -> Charlie
    ];

    let accounts = vec![
        (
            alice,
            Account {
                lamports: initial_lamports,
                data: vec![],
                owner: SYSTEM_PROGRAM_ID,
                executable: false,
                rent_epoch: 0,
            },
        ),
        (
            bob,
            Account {
                lamports: 0,
                data: vec![],
                owner: SYSTEM_PROGRAM_ID,
                executable: false,
                rent_epoch: 0,
            },
        ),
        (
            charlie,
            Account {
                lamports: 0,
                data: vec![],
                owner: SYSTEM_PROGRAM_ID,
                executable: false,
                rent_epoch: 0,
            },
        ),
    ];

    // Process the instruction chain
    let result = mollusk.process_instruction_chain(&instructions, &accounts);
    println!("{:#?}", result);

    // Final balances: Alice=700K, Bob=200K, Charlie=100K
    assert_eq!(result.get_account(&alice).unwrap().lamports, 700_000);
    assert_eq!(result.get_account(&bob).unwrap().lamports, 200_000);
    assert_eq!(result.get_account(&charlie).unwrap().lamports, 100_000);
}
```

</CodeTabs>

#### Multiple Instructions with Checks

Use the `process_and_validate_instruction_chain` method to process multiple
instructions with validation checks after each instruction. Each instruction has
its own set of checks that must pass.

```rust title="Method Signature"
pub fn process_and_validate_instruction_chain(
    &self,
    instructions: &[(&Instruction, &[Check])],
    accounts: &[(Pubkey, Account)],
) -> InstructionResult
```

The following example processes a chain of two SOL transfer instructions with
validation checks after each instruction.

<CodeTabs flags="r">

```rs !! title="With Validation"
use {
    mollusk_svm::{result::Check, Mollusk},
    solana_sdk::{account::Account, pubkey::Pubkey},
    solana_system_interface::{instruction::transfer, program::ID as SYSTEM_PROGRAM_ID},
};

fn main() {
    let mollusk = Mollusk::default();

    // Create accounts
    let alice = Pubkey::new_unique();
    let bob = Pubkey::new_unique();
    let charlie = Pubkey::new_unique();

    let initial_lamports = 1_000_000;

    // Create transfer instructions
    let transfer1 = transfer(&alice, &bob, 300_000);
    let transfer2 = transfer(&bob, &charlie, 100_000);

    // Initial accounts
    let accounts = vec![
        (
            alice,
            Account {
                lamports: initial_lamports,
                data: vec![],
                owner: SYSTEM_PROGRAM_ID,
                executable: false,
                rent_epoch: 0,
            },
        ),
        (
            bob,
            Account {
                lamports: 0,
                data: vec![],
                owner: SYSTEM_PROGRAM_ID,
                executable: false,
                rent_epoch: 0,
            },
        ),
        (
            charlie,
            Account {
                lamports: 0,
                data: vec![],
                owner: SYSTEM_PROGRAM_ID,
                executable: false,
                rent_epoch: 0,
            },
        ),
    ];

    // Define checks for each instruction
    let checks_after_transfer1 = vec![
        Check::success(),
        Check::account(&alice)
            .lamports(700_000) // 1M - 300K
            .build(),
        Check::account(&bob)
            .lamports(300_000) // 0 + 300K
            .build(),
        Check::account(&charlie)
            .lamports(0) // Unchanged
            .build(),
    ];

    let checks_after_transfer2 = vec![
        Check::success(),
        Check::account(&alice)
            .lamports(700_000) // Unchanged from previous
            .build(),
        Check::account(&bob)
            .lamports(200_000) // 300K - 100K
            .build(),
        Check::account(&charlie)
            .lamports(100_000) // 0 + 100K
            .build(),
    ];

    // Process with validation at each step
    let instruction_and_checks = [
        (&transfer1, checks_after_transfer1.as_slice()),
        (&transfer2, checks_after_transfer2.as_slice()),
    ];

    // Execute chain (panics if any check fails)
    let result = mollusk.process_and_validate_instruction_chain(&instruction_and_checks, &accounts);

    println!("{:#?}", result);
}
```

</CodeTabs>

### Validation Checks

Mollusk provides a set of
[helper methods](https://docs.rs/mollusk-svm-result/0.5.0/mollusk_svm_result/check/struct.Check.html)
to check the results of a processed instruction.

```rust title="Example"
use mollusk_svm::result::Check;
```

Use the following methods to validate instruction results:

```rust title="Example"
// Program execution succeeded
Check::success()

// Program returned specific error
Check::err(ProgramError::InvalidArgument)

// Instruction level error
Check::instruction_err(InstructionError::InsufficientFunds)

// Check with specific program result
Check::program_result(ProgramResult::Success)

// Compute units consumed
Check::compute_units(1000)

// Execution time
Check::time(100)

// Return data from instruction execution
Check::return_data(&[1, 2, 3, 4])
```

Use the following to validate Account states:

```rust title="Example"
// Single account validation
Check::account(&pubkey)
    .lamports(1_000_000)           // Exact lamports
    .owner(&program_id)            // Account owner
    .data(&expected_data)          // Exact data match
    .data_slice(8, &[1, 2, 3])     // Partial data match at offset
    .executable(false)             // Executable flag
    .space(100)                    // Account data size
    .closed()                      // Account is closed (0 lamports)
    .rent_exempt()                 // Account is rent-exempt
    .build()

// Check all accounts are rent exempt
Check::all_rent_exempt()
```

### Persistent Account State

The
[`MolluskContext`](https://docs.rs/mollusk-svm/0.5.0/mollusk_svm/struct.MolluskContext.html)
is a wrapper around `Mollusk` that maintains account state across multiple
instruction calls through its `account_store`. The methods for processing
instructions are identical to `Mollusk`.

Unlike `Mollusk`, which requires passing `accounts` to each method (e.g.
`process_instruction`), `MolluskContext` manages accounts internally through its
`account_store`. This eliminates the need for the `accounts` parameter when
processing instructions.

Create an `account_store` using the `with_context` method:

```rust title="Example"
use std::collections::HashMap;
use solana_sdk::{account::Account, pubkey::Pubkey};
use solana_system_interface::program::ID as SYSTEM_PROGRAM_ID;
use mollusk_svm::Mollusk;

let mollusk = Mollusk::default();
let account_address = Pubkey::new_unique();

// !focus(1:11)
let mut account_store = HashMap::new();
account_store.insert(
    account_address,
    Account {
        lamports: 1_000_000,
        data: vec![],
        owner: SYSTEM_PROGRAM_ID,
        executable: false,
        rent_epoch: 0,
    },
);

// !focus
// !mark
let context = mollusk.with_context(account_store);
```

The following example processes two separate SOL transfer instructions with
persistent account state between the instructions through the `account_store`.

<CodeTabs flags="r">

```rs !! title="Stateful Testing"
use {
    mollusk_svm::Mollusk,
    solana_sdk::{account::Account, pubkey::Pubkey},
    solana_system_interface::{instruction::transfer, program::ID as SYSTEM_PROGRAM_ID},
    std::collections::HashMap,
};

fn main() {
    // Initialize Mollusk
    let mollusk = Mollusk::default();

    // Create accounts
    let sender = Pubkey::new_unique();
    let recipient = Pubkey::new_unique();

    // Create account store with initial balances
    let mut account_store = HashMap::new();
    account_store.insert(
        sender,
        Account {
            lamports: 1_000_000,
            data: vec![],
            owner: SYSTEM_PROGRAM_ID,
            executable: false,
            rent_epoch: 0,
        },
    );
    account_store.insert(
        recipient,
        Account {
            lamports: 0,
            data: vec![],
            owner: SYSTEM_PROGRAM_ID,
            executable: false,
            rent_epoch: 0,
        },
    );

    // Create a stateful context
    let context = mollusk.with_context(account_store);

    // First transfer: 200,000 lamports
    let instruction1 = transfer(&sender, &recipient, 200_000);
    context.process_instruction(&instruction1);

    // Second transfer: 100,000 lamports (state persists from first transfer)
    let instruction2 = transfer(&sender, &recipient, 100_000);
    context.process_instruction(&instruction2);

    // Check final balances
    let store = context.account_store.borrow();
    let sender_account = store.get(&sender).unwrap();
    let recipient_account = store.get(&recipient).unwrap();
    println!("Sender: {:#?}", sender_account);
    println!("Recipient: {:#?}", recipient_account);
}
```

</CodeTabs>

### Mollusk Sysvars

Mollusk provides a custom
[`Sysvars`](https://docs.rs/mollusk-svm/0.5.0/mollusk_svm/sysvar/struct.Sysvars.html)
struct for modifying its values for testing.

Use the `warp_to_slot` method to update the sysvar clock to simulate moving
forward or backward in time to a specific slot.

<CodeTabs flags="r">

```rust !! title="Warp to Slot"
use mollusk_svm::Mollusk;

fn main() {
    // Initialize Mollusk
    let mut mollusk = Mollusk::default();

    // Show initial slot
    println!("Initial slot: {}", mollusk.sysvars.clock.slot);

    // Warp to slot 1000
    mollusk.warp_to_slot(100);
    println!("After warp: {}", mollusk.sysvars.clock.slot);

    // Warp to slot 10
    mollusk.warp_to_slot(10);
    println!("After second warp: {}", mollusk.sysvars.clock.slot);
}
```

</CodeTabs>

The following example shows how to modify the Mollusk sysvar directly by
accessing the `sysvars` field to change the rent parameters. You can modify
other sysvar values the same way.

<CodeTabs flags="r">

```rust !! title="Modify Sysvars"
use {mollusk_svm::Mollusk, solana_sdk::rent::Rent};

fn main() {
    let mut mollusk = Mollusk::default();

    // Show default rent
    println!(
        "Default rent exemption for 1000 bytes: {} lamports",
        mollusk.sysvars.rent.minimum_balance(1000)
    );

    // Customize rent parameters
    mollusk.sysvars.rent = Rent {
        lamports_per_byte_year: 1,
        exemption_threshold: 1.0,
        burn_percent: 0,
    };

    // Show custom rent
    println!(
        "Custom rent exemption for 1000 bytes: {} lamports",
        mollusk.sysvars.rent.minimum_balance(1000)
    );
}
```

</CodeTabs>

## Compute Unit Benchmarking

[`MolluskComputeUnitBencher`](https://docs.rs/mollusk-svm-bencher/0.5.0/mollusk_svm_bencher/struct.MolluskComputeUnitBencher.html)
tracks compute unit usage of a program's instructions. Results are written to a
markdown file.

Requires
[`mollusk-svm-bencher`](https://docs.rs/mollusk-svm-bencher/0.5.0/mollusk_svm_bencher/index.html)
as a dependency.

The following example benchmarks the compute unit usage of a SOL transfer
instruction.

<CodeTabs>

```rs !! title="Benchmark Compute Units"
use {
    mollusk_svm::Mollusk,
    mollusk_svm_bencher::MolluskComputeUnitBencher,
    solana_sdk::{account::Account, pubkey::Pubkey},
    solana_system_interface::{instruction::transfer, program::ID as SYSTEM_PROGRAM_ID},
};

fn main() {
    // Initialize Mollusk
    let mollusk = Mollusk::default();

    // Create test accounts
    let sender = Pubkey::new_unique();
    let receiver = Pubkey::new_unique();

    // Transfer instruction
    let transfer = transfer(&sender, &receiver, 100_000);
    let accounts = vec![
        (
            sender,
            Account {
                lamports: 1_000_000,
                data: vec![],
                owner: SYSTEM_PROGRAM_ID,
                executable: false,
                rent_epoch: 0,
            },
        ),
        (
            receiver,
            Account {
                lamports: 0,
                data: vec![],
                owner: SYSTEM_PROGRAM_ID,
                executable: false,
                rent_epoch: 0,
            },
        ),
    ];

    // Run benchmark
    // !focus(1:5)
    // !mark(1:5)
    MolluskComputeUnitBencher::new(mollusk)
        .bench(("transfer", &transfer, &accounts))
        .must_pass(true)
        .out_dir("./target/benches")
        .execute();
}
```

</CodeTabs>

The benchmark results are written to the specified `out_dir` as a markdown file
named `compute_units.md`.

```md title="comput_units.md"
#### 2025-09-19 22:28:53.691839 UTC

Solana CLI Version: solana-cli 2.2.20 (src:dabc99a5; feat:3073396398,
client:Agave)

| Name     | CUs | Delta   |
| -------- | --- | ------- |
| transfer | 150 | - new - |
```

## Token Program Testing

Use the
[`mollusk-svm-programs-token`](https://docs.rs/mollusk-svm-programs-token/0.5.0/mollusk_svm_programs_token/index.html)
crate add the token program, token2022 program (token extensions), and
associated token program to Mollusk for testing.

```rust title="Example"
use {
    mollusk_svm::Mollusk,
    // !focus
    mollusk_svm_programs_token::{associated_token, token, token2022},
};

let mut mollusk = Mollusk::default();

// !focus(1:6)
// Add SPL Token Program
token::add_program(&mut mollusk);
// Add SPL Token-2022 Program
token2022::add_program(&mut mollusk);
// Add Associated Token Account Program
associated_token::add_program(&mut mollusk);
```

The following example demonstrates testing a token transfer using Mollusk.

<Callout type="info">
  The example below manually defines the test accounts for demonstration
  purposes. The `mollusk-svm-programs-token` also includes helper functions to
  create the mint and token accounts.
</Callout>

<CodeTabs flags="r">

```rs !! title="Token Transfer Example"
use {
    mollusk_svm::{result::Check, Mollusk},
    mollusk_svm_programs_token::token,
    solana_sdk::{account::Account, program_pack::Pack, pubkey::Pubkey},
    spl_token_interface::{
        instruction::transfer_checked,
        state::{Account as TokenAccount, AccountState, Mint},
    },
};

fn main() {
    // Initialize Mollusk with Token program
    let mut mollusk = Mollusk::default();
    token::add_program(&mut mollusk);

    // Create account keys
    let mint = Pubkey::new_unique();
    let source = Pubkey::new_unique();
    let destination = Pubkey::new_unique();
    let authority = Pubkey::new_unique();

    // Token configuration
    let decimals = 6;
    let transfer_amount = 1_000_000; // 1 token with 6 decimals
    let initial_balance = 10_000_000; // 10 tokens

    // Calculate rent-exempt minimums
    let mint_rent = mollusk.sysvars.rent.minimum_balance(Mint::LEN);
    let account_rent = mollusk.sysvars.rent.minimum_balance(TokenAccount::LEN);

    // Create mint account
    let mut mint_data = vec![0u8; Mint::LEN];
    Mint::pack(
        Mint {
            mint_authority: Some(authority).into(),
            supply: initial_balance,
            decimals,
            is_initialized: true,
            freeze_authority: None.into(),
        },
        &mut mint_data,
    )
    .unwrap();

    // Create source token account
    let mut source_data = vec![0u8; TokenAccount::LEN];
    TokenAccount::pack(
        TokenAccount {
            mint,
            owner: authority,
            amount: initial_balance,
            delegate: None.into(),
            state: AccountState::Initialized,
            is_native: None.into(),
            delegated_amount: 0,
            close_authority: None.into(),
        },
        &mut source_data,
    )
    .unwrap();

    // Create destination token account
    let mut destination_data = vec![0u8; TokenAccount::LEN];
    TokenAccount::pack(
        TokenAccount {
            mint,
            owner: Pubkey::new_unique(),
            amount: 0,
            delegate: None.into(),
            state: AccountState::Initialized,
            is_native: None.into(),
            delegated_amount: 0,
            close_authority: None.into(),
        },
        &mut destination_data,
    )
    .unwrap();

    // Setup accounts for transfer_checked
    let accounts = vec![
        (
            source,
            Account {
                lamports: account_rent,
                data: source_data,
                owner: token::ID,
                executable: false,
                rent_epoch: 0,
            },
        ),
        (
            mint,
            Account {
                lamports: mint_rent,
                data: mint_data,
                owner: token::ID,
                executable: false,
                rent_epoch: 0,
            },
        ),
        (
            destination,
            Account {
                lamports: account_rent,
                data: destination_data,
                owner: token::ID,
                executable: false,
                rent_epoch: 0,
            },
        ),
        (
            authority,
            Account {
                lamports: 1_000_000,
                data: vec![],
                owner: Pubkey::default(),
                executable: false,
                rent_epoch: 0,
            },
        ),
    ];

    // Create transfer_checked instruction
    let instruction = transfer_checked(
        &token::ID,
        &source,
        &mint,
        &destination,
        &authority,
        &[],
        transfer_amount,
        decimals,
    )
    .unwrap();

    // Expected balances after transfer
    let expected_source_balance = (initial_balance - transfer_amount).to_le_bytes();
    let expected_dest_balance = transfer_amount.to_le_bytes();

    // Define validation checks
    let checks = vec![
        Check::success(),
        Check::account(&source)
            .data_slice(64, &expected_source_balance) // Token amount is at offset 64
            .build(),
        Check::account(&destination)
            .data_slice(64, &expected_dest_balance)
            .build(),
    ];

    // Process and validate the instruction
    let result = mollusk.process_and_validate_instruction(&instruction, &accounts, &checks);
    println!("{:#?}", result);

    // Deserialize token account data
    let source_account = result.get_account(&source).unwrap();
    let source_token = TokenAccount::unpack(&source_account.data).unwrap();
    println!("Source Token Account: {:#?}", source_token);

    let destination_account = result.get_account(&destination).unwrap();
    let dest_token = TokenAccount::unpack(&destination_account.data).unwrap();
    println!("Destination Token Account: {:#?}", dest_token);
}
```

</CodeTabs>
