Documentación de SolanaLiteSVMRustCajas adicionalesanchor-litesvm

Programa y Contexto

Generación de Tipos de Cliente con declare_program!

Anchor 1.0 introduce declare_program!, que lee el IDL de tu programa en tiempo de compilación y genera módulos client::accounts::* e client::args::* tipo-seguros. Esta es la forma recomendada de construir instrucciones en pruebas.

// At the top of your test file, generate client modules from the IDL
anchor_lang::declare_program!(my_program);
// Now use the generated types:
// my_program::client::accounts::Initialize { ... }
// my_program::client::args::Initialize { ... }
// my_program::MyAccount (for account deserialization)

Ejecuta anchor build primero para generar target/idl/my_program.json. declare_program! lee este archivo en tiempo de compilación. El nombre de la macro debe coincidir con el nombre del crate de tu programa (snake_case).

Configuración del Entorno de Prueba

El constructor AnchorLiteSVM proporciona una API fluida para configurar tu entorno de prueba.

Configuración Básica

use anchor_litesvm::AnchorLiteSVM;
use solana_sdk::signature::{read_keypair_file, Signer};
anchor_lang::declare_program!(my_program);
#[test]
fn test_basic_setup() {
// Read the program keypair to get the correct program ID
let program_keypair = read_keypair_file("target/deploy/my_program-keypair.json").unwrap();
let mut ctx = AnchorLiteSVM::new()
.deploy_program(
program_keypair.pubkey(),
include_bytes!("../target/deploy/my_program.so"),
)
.build();
println!("Program deployed: {}", ctx.program().id());
}

Forma Abreviada para un Solo Programa

use anchor_litesvm::AnchorLiteSVM;
use solana_sdk::signature::{read_keypair_file, Signer};
#[test]
fn test_single_program() {
let program_keypair = read_keypair_file("target/deploy/my_program-keypair.json").unwrap();
// Convenience method for single-program setups
let mut ctx = AnchorLiteSVM::build_with_program(
program_keypair.pubkey(),
include_bytes!("../target/deploy/my_program.so"),
);
}

Múltiples Programas

use anchor_litesvm::AnchorLiteSVM;
use solana_sdk::signature::{read_keypair_file, Signer};
#[test]
fn test_multiple_programs() {
let program_a_kp = read_keypair_file("target/deploy/program_a-keypair.json").unwrap();
let program_b_kp = read_keypair_file("target/deploy/program_b-keypair.json").unwrap();
// Deploy multiple programs — first one becomes the primary (ctx.program_id)
let mut ctx = AnchorLiteSVM::build_with_programs(&[
(program_a_kp.pubkey(), include_bytes!("../target/deploy/program_a.so") as &[u8]),
(program_b_kp.pubkey(), include_bytes!("../target/deploy/program_b.so") as &[u8]),
]);
// Primary program is program_a
assert_eq!(ctx.program().id(), program_a_kp.pubkey());
}

Pagador Personalizado

use anchor_litesvm::AnchorLiteSVM;
use solana_keypair::Keypair;
use solana_signer::Signer;
#[test]
fn test_custom_payer() {
let custom_payer = Keypair::new();
let mut ctx = AnchorLiteSVM::new()
.with_payer(custom_payer)
.deploy_program(PROGRAM_ID, include_bytes!("../target/deploy/your_program.so"))
.build();
println!("Payer: {}", ctx.payer().pubkey());
}

Si no especificas un pagador, AnchorLiteSVM crea y financia uno automáticamente.

El AnchorContext

AnchorContext es la interfaz principal para interactuar con tu entorno de prueba.

Propiedades Principales

use anchor_litesvm::AnchorLiteSVM;
use solana_signer::Signer;
#[test]
fn test_context_properties() {
let mut ctx = AnchorLiteSVM::build_with_program(
PROGRAM_ID,
include_bytes!("../target/deploy/your_program.so"),
);
// ctx.svm — direct access to the underlying LiteSVM instance (public field)
let balance = ctx.svm.get_balance(&some_pubkey);
// ctx.payer() — the payer keypair
let payer = ctx.payer();
println!("Payer pubkey: {}", payer.pubkey());
// ctx.program() — Program instance for instruction building
let program = ctx.program();
println!("Program ID: {}", program.id());
// ctx.latest_blockhash()
let blockhash = ctx.latest_blockhash();
}

Creación de Cuentas con Fondos

use anchor_litesvm::AnchorLiteSVM;
use anchor_litesvm::TestHelpers;
use solana_keypair::Keypair;
use solana_signer::Signer;
#[test]
fn test_create_accounts() {
let mut ctx = AnchorLiteSVM::build_with_program(
PROGRAM_ID,
include_bytes!("../target/deploy/your_program.so"),
);
// Option 1: via AnchorContext (returns Result<Keypair>)
let user = ctx.create_funded_account(10_000_000_000).unwrap();
// Option 2: via ctx.svm with TestHelpers (same result)
let user2 = ctx.svm.create_funded_account(10_000_000_000).unwrap();
// Airdrop to an existing address
let another_user = Keypair::new();
ctx.airdrop(&another_user.pubkey(), 5_000_000_000).unwrap();
}

Verificación de Existencia de Cuenta

use anchor_litesvm::AnchorLiteSVM;
#[test]
fn test_account_exists() {
let mut ctx = AnchorLiteSVM::build_with_program(
PROGRAM_ID,
include_bytes!("../target/deploy/your_program.so"),
);
let some_pda = ctx.svm.get_pda(&[b"vault"], &PROGRAM_ID);
if ctx.account_exists(&some_pda) {
println!("Account exists!");
} else {
println!("Account not found");
}
}

Construcción de instrucciones con Program

La estructura Program proporciona una API fluida para construir instrucciones que refleja anchor-client. Utiliza los tipos generados por declare_program! para mayor seguridad de tipos.

Construcción básica de instrucciones

use anchor_litesvm::AnchorLiteSVM;
use anchor_lang::system_program;
use solana_signer::Signer;
anchor_lang::declare_program!(my_program);
#[test]
fn test_build_instruction() {
let mut ctx = AnchorLiteSVM::build_with_program(
PROGRAM_ID,
include_bytes!("../target/deploy/my_program.so"),
);
let user = ctx.svm.create_funded_account(10_000_000_000).unwrap();
let user_pda = ctx.svm.get_pda(&[b"user", user.pubkey().as_ref()], &PROGRAM_ID);
// Build instruction using types generated by declare_program!
let ix = ctx.program()
.accounts(my_program::client::accounts::Initialize {
user: user.pubkey(),
user_account: user_pda,
system_program: system_program::ID,
})
.args(my_program::client::args::Initialize {
name: "test".to_string(),
})
.instruction()
.unwrap();
println!("Instruction built successfully!");
}

El método .accounts() acepta cualquier tipo que implemente ToAccountMetas, lo cual todos los structs de cuentas de Anchor hacen automáticamente. De igual manera, .args() acepta cualquier tipo que implemente InstructionData.

Ejecución de instrucciones

use anchor_litesvm::AnchorLiteSVM;
use anchor_lang::system_program;
use solana_signer::Signer;
anchor_lang::declare_program!(my_program);
#[test]
fn test_execute_instruction() {
let mut ctx = AnchorLiteSVM::build_with_program(
PROGRAM_ID,
include_bytes!("../target/deploy/my_program.so"),
);
let user = ctx.svm.create_funded_account(10_000_000_000).unwrap();
let user_pda = ctx.svm.get_pda(&[b"user", user.pubkey().as_ref()], &PROGRAM_ID);
let ix = ctx.program()
.accounts(my_program::client::accounts::Initialize {
user: user.pubkey(),
user_account: user_pda,
system_program: system_program::ID,
})
.args(my_program::client::args::Initialize { name: "test".to_string() })
.instruction()
.unwrap();
// Execute — returns TransactionResult
ctx.execute_instruction(ix, &[&user])
.unwrap()
.assert_success();
}

Ejecución de múltiples instrucciones

use anchor_litesvm::AnchorLiteSVM;
use solana_signer::Signer;
anchor_lang::declare_program!(my_program);
#[test]
fn test_execute_multiple_instructions() {
let mut ctx = AnchorLiteSVM::build_with_program(
PROGRAM_ID,
include_bytes!("../target/deploy/my_program.so"),
);
let user = ctx.svm.create_funded_account(10_000_000_000).unwrap();
let ix1 = ctx.program()
.accounts(my_program::client::accounts::Initialize { /* ... */ })
.args(my_program::client::args::Initialize { name: "first".to_string() })
.instruction()
.unwrap();
let ix2 = ctx.program()
.accounts(my_program::client::accounts::Update { /* ... */ })
.args(my_program::client::args::Update { name: "second".to_string() })
.instruction()
.unwrap();
// Execute multiple instructions in one transaction
ctx.execute_instructions(vec![ix1, ix2], &[&user])
.unwrap()
.assert_success();
}

Uso de send_and_confirm_transaction

use anchor_litesvm::AnchorLiteSVM;
use solana_signer::Signer;
use solana_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.svm.create_funded_account(10_000_000_000).unwrap();
let ix = ctx.program()
.accounts(/* ... */)
.args(/* ... */)
.instruction()
.unwrap();
// Build transaction manually if needed
let tx = Transaction::new_signed_with_payer(
&[ix],
Some(&ctx.payer().pubkey()),
&[ctx.payer(), &user],
ctx.latest_blockhash(),
);
// Note: takes &Transaction (reference)
ctx.send_and_confirm_transaction(&tx).unwrap();
}

Ejemplo completo

Aquí hay un ejemplo completo utilizando el patrón de custodia (escrow) con declare_program!:

use anchor_litesvm::AnchorLiteSVM;
use anchor_litesvm::{AssertionHelpers, TestHelpers};
use anchor_lang::system_program;
use solana_sdk::signature::{read_keypair_file, Signer};
use spl_associated_token_account::get_associated_token_address;
use litesvm_token::spl_token;
anchor_lang::declare_program!(anchor_escrow);
#[test]
fn test_make_and_take() {
// 1. One-line setup
let program_keypair = read_keypair_file("target/deploy/anchor_escrow-keypair.json").unwrap();
let program_id = program_keypair.pubkey();
let mut ctx = AnchorLiteSVM::build_with_program(
program_id,
include_bytes!("../target/deploy/anchor_escrow.so"),
);
// 2. Create test accounts using TestHelpers on ctx.svm
let maker = ctx.svm.create_funded_account(10_000_000_000).unwrap();
let taker = ctx.svm.create_funded_account(10_000_000_000).unwrap();
// 3. Create token mints and funded ATAs
let mint_a = ctx.svm.create_token_mint(&maker, 9).unwrap();
let mint_b = ctx.svm.create_token_mint(&maker, 9).unwrap();
let maker_ata_a = ctx.svm
.create_associated_token_account(&mint_a.pubkey(), &maker)
.unwrap();
ctx.svm.mint_to(&mint_a.pubkey(), &maker_ata_a, &maker, 1_000_000_000).unwrap();
let taker_ata_b = ctx.svm
.create_associated_token_account(&mint_b.pubkey(), &taker)
.unwrap();
ctx.svm.mint_to(&mint_b.pubkey(), &taker_ata_b, &maker, 500_000_000).unwrap();
// 4. Derive PDAs
let seed: u64 = 42;
let escrow_pda = ctx.svm.get_pda(
&[b"escrow", maker.pubkey().as_ref(), &seed.to_le_bytes()],
&program_id,
);
let vault = get_associated_token_address(&escrow_pda, &mint_a.pubkey());
// 5. Build and execute Make instruction using generated client types
let make_ix = ctx.program()
.accounts(anchor_escrow::client::accounts::Make {
maker: maker.pubkey(),
escrow: escrow_pda,
mint_a: mint_a.pubkey(),
mint_b: mint_b.pubkey(),
maker_ata_a,
vault,
associated_token_program: spl_associated_token_account::id(),
token_program: spl_token::id(),
system_program: system_program::ID,
})
.args(anchor_escrow::client::args::Make {
seed,
receive: 500_000_000,
amount: 1_000_000_000,
})
.instruction()
.unwrap();
ctx.execute_instruction(make_ix, &[&maker])
.unwrap()
.assert_success();
// 6. Assert state using AssertionHelpers on ctx.svm
assert!(ctx.account_exists(&escrow_pda));
ctx.svm.assert_token_balance(&vault, 1_000_000_000);
ctx.svm.assert_token_balance(&maker_ata_a, 0);
// 7. Execute Take
let taker_ata_a = get_associated_token_address(&taker.pubkey(), &mint_a.pubkey());
let maker_ata_b = get_associated_token_address(&maker.pubkey(), &mint_b.pubkey());
let take_ix = ctx.program()
.accounts(anchor_escrow::client::accounts::Take {
taker: taker.pubkey(),
maker: maker.pubkey(),
escrow: escrow_pda,
mint_a: mint_a.pubkey(),
mint_b: mint_b.pubkey(),
vault,
taker_ata_a,
taker_ata_b,
maker_ata_b,
associated_token_program: spl_associated_token_account::id(),
token_program: spl_token::id(),
system_program: system_program::ID,
})
.args(anchor_escrow::client::args::Take {})
.instruction()
.unwrap();
ctx.execute_instruction(take_ix, &[&taker])
.unwrap()
.assert_success();
// 8. Final assertions
ctx.svm.assert_account_closed(&escrow_pda);
ctx.svm.assert_account_closed(&vault);
ctx.svm.assert_token_balance(&taker_ata_a, 1_000_000_000);
ctx.svm.assert_token_balance(&maker_ata_b, 500_000_000);
}

Is this page helpful?