Mollusk
Mollusk는 Solana 프로그램을 테스트하기 위한 경량 테스트 하네스입니다. 간소화된 Solana 가상 머신(SVM) 환경에서 Solana 프로그램 명령어를 테스트하기 위한 간단한 인터페이스를 제공합니다. 모든 테스트 계정은 명시적으로 정의되어야 하므로 결정적이고 반복 가능한 테스트를 보장합니다.
설치
mollusk-svm를 Cargo.toml에 의존성으로 추가하세요:
Terminal
$cargo add mollusk-svm --dev
Cargo.toml
[dev-dependencies]mollusk-svm = "0.7"
컴퓨팅 유닛 사용량을 벤치마크하려면 mollusk-svm-bencher를 Cargo.toml에
의존성으로 추가하세요:
Terminal
$cargo add mollusk-svm-bencher --dev
Cargo.toml
[dev-dependencies]mollusk-svm-bencher = "0.7"
Mollusk로 테스트할 때 Token Program, Token2022 Program(Token Extensions) 및
Associated Token Program을 사용하려면 mollusk-svm-programs-token를
Cargo.toml에 의존성으로 추가하세요:
Terminal
$cargo add mollusk-svm-programs-token --dev
Cargo.toml
[dev-dependencies]mollusk-svm-programs-token = "0.7"
Mollusk SVM
다음 예제는 Mollusk를 사용하여 기본 Solana 프로그램을 테스트하기 위한 최소한의 설정을 보여줍니다.
Hello World 프로그램
이 예제는 Mollusk를 사용하여 기본 Solana 프로그램을 테스트하는 방법을 보여줍니다. 이 프로그램은 호출될 때 프로그램 로그에 "Hello, world!"를 출력합니다.
cargo build-sbf를 실행하면 /target/deploy/<program_name>.so에 컴파일된
프로그램이 생성됩니다.
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(())}#[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()]);}}
Mollusk로 Solana 프로그램을 테스트하려면:
Mollusk인스턴스 생성 - 프로그램 ID와 컴파일된 프로그램 경로(.so파일)로 Mollusk 초기화- 명령어 구성 - 프로그램을 호출하기 위한 명령어 생성
- 처리 및 검증 - Mollusk를 사용하여 명령어를 처리하고 결과 검증
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();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()]);}}
테스트를 실행하려면 cargo test를 실행하세요.
테스트가 성공적으로 실행되면 다음과 유사한 출력이 표시됩니다:
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 successtest tests::test_hello_world ... oktest result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02sDoc-tests hello_world
Mollusk
구조체는 Solana 프로그램을 테스트하기 위한 간단한 인터페이스를 제공합니다. 모든
필드는 몇 가지 헬퍼 메서드를 통해 조작할 수 있지만, 사용자가 더 많은 제어를 원할
경우 직접 접근하고 수정할 수도 있습니다.
기본 인스턴스로 Mollusk를 초기화하려면 Mollusk::default 메서드를 사용하세요.
Example
// Default instance with no custom programslet mollusk = Mollusk::default();
특정 프로그램으로 Mollusk를 초기화하려면 Mollusk::new 메서드를 사용하세요.
Example
// Initialize Mollusk with a specific program from a file pathlet program_id = Pubkey::new_unique();let mollusk = Mollusk::new(&program_id, "target/deploy/my_program");
Mollusk에 프로그램을 추가하려면 Mollusk::add_program 메서드를 사용하세요.
Example
let mollusk = Mollusk::default();let program_id = Pubkey::new_unique();// Add a program to Molluskmollusk.add_program(&program_id,"target/deploy/my_program",&bpf_loader_upgradeable::id(),);
파일 경로를 제공할 때 .so 확장자를 포함하지 마세요. 예를 들어,
"path/to/my_program"는 올바르지만 "path/to/my_program.so"는 올바르지
않습니다.
명령어 처리하기
Mollusk는 명령어를 처리하기 위한 네 가지 주요 메서드를 제공합니다:
| 메서드 | 설명 |
|---|---|
process_instruction | 명령어를 처리하고 결과를 반환합니다. |
process_and_validate_instruction | 명령어를 처리하고 결과에 대해 일련의 검사를 수행하며, 검사가 실패하면 패닉이 발생합니다. |
process_instruction_chain | 여러 명령어를 처리하고 결과를 반환합니다. |
process_and_validate_instruction_chain | 여러 명령어를 처리하고 각 결과에 대해 일련의 검사를 수행하며, 검사가 실패하면 패닉이 발생합니다. |
InstructionResult에는
처리된 명령어의 세부 정보가 포함되어 있습니다.
단일 명령어
결과에 대한 검사 없이 단일 명령어를 처리하려면 process_instruction 메서드를
사용하세요. 처리 후 수동으로 결과를 검증할 수 있습니다.
Method Signature
pub fn process_instruction(&self,instruction: &Instruction,accounts: &[(Pubkey, Account)],) -> InstructionResult
다음 예제는 검증 검사 없이 SOL 전송 명령어를 처리합니다.
아래 예제는 시연 목적으로 main 함수에서 Mollusk를 실행합니다. 실제로는
일반적으로 #[test] 속성으로 주석이 달린 테스트 모듈에서 Mollusk를 사용하게
됩니다.
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 Mollusklet mollusk = Mollusk::default();// Set up accountslet sender = Pubkey::new_unique();let recipient = Pubkey::new_unique();let initial_lamports = 1_000_000;let transfer_amount = 250_000;// Create transfer instructionlet instruction = transfer(&sender, &recipient, transfer_amount);// Define initial account stateslet 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 instructionlet result = mollusk.process_instruction(&instruction, &accounts);println!("{:#?}", result);// Check the resultassert!(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);}
Console
Click to execute the code.
검증이 포함된 단일 명령어
process_and_validate_instruction 메서드를 사용하여 검증 확인이 포함된 단일
명령어를 처리합니다. 이 메서드는 검증에 실패하면 패닉을 발생시킵니다.
Method Signature
pub fn process_and_validate_instruction(&self,instruction: &Instruction,accounts: &[(Pubkey, Account)],checks: &[Check],) -> InstructionResult
다음 예제는 검증 확인이 포함된 SOL 전송 명령어를 처리합니다.
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 checkslet 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);}
Console
Click to execute the code.
다중 명령어
process_instruction_chain 메서드를 사용하여 검증 확인 없이 여러 명령어를
순차적으로 처리합니다.
Method Signature
pub fn process_instruction_chain(&self,instructions: &[Instruction],accounts: &[(Pubkey, Account)],) -> InstructionResult
다음 예제는 검증 확인 없이 두 개의 SOL 전송 명령어를 처리합니다.
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 accountslet alice = Pubkey::new_unique();let bob = Pubkey::new_unique();let charlie = Pubkey::new_unique();let initial_lamports = 1_000_000;// Create chain of transferslet instructions = vec![transfer(&alice, &bob, 300_000), // Alice -> Bobtransfer(&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 chainlet result = mollusk.process_instruction_chain(&instructions, &accounts);println!("{:#?}", result);// Final balances: Alice=700K, Bob=200K, Charlie=100Kassert_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);}
Console
Click to execute the code.
검증이 포함된 다중 명령어
process_and_validate_instruction_chain 메서드를 사용하여 각 명령어 후 검증
확인이 포함된 여러 명령어를 처리합니다. 각 명령어에는 통과해야 하는 자체 검증
세트가 있습니다.
Method Signature
pub fn process_and_validate_instruction_chain(&self,instructions: &[(&Instruction, &[Check])],accounts: &[(Pubkey, Account)],) -> InstructionResult
다음 예제는 각 명령어 후 검증 확인이 포함된 두 개의 SOL 전송 명령어 체인을 처리합니다.
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 accountslet alice = Pubkey::new_unique();let bob = Pubkey::new_unique();let charlie = Pubkey::new_unique();let initial_lamports = 1_000_000;// Create transfer instructionslet transfer1 = transfer(&alice, &bob, 300_000);let transfer2 = transfer(&bob, &charlie, 100_000);// Initial accountslet 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 instructionlet 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 steplet 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);}
Console
Click to execute the code.
유효성 검사
Mollusk는 처리된 명령어의 결과를 확인하기 위한 헬퍼 메소드 세트를 제공합니다.
Example
use mollusk_svm::result::Check;
다음 메소드를 사용하여 명령어 결과의 유효성을 검사하세요:
Example
// Program execution succeededCheck::success()// Program returned specific errorCheck::err(ProgramError::InvalidArgument)// Instruction level errorCheck::instruction_err(InstructionError::InsufficientFunds)// Check with specific program resultCheck::program_result(ProgramResult::Success)// Compute units consumedCheck::compute_units(1000)// Execution timeCheck::time(100)// Return data from instruction executionCheck::return_data(&[1, 2, 3, 4])
다음을 사용하여 계정 상태의 유효성을 검사하세요:
Example
// Single account validationCheck::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 exemptCheck::all_rent_exempt()
영구적인 계정 상태
MolluskContext는
Mollusk를 감싸는 래퍼로, account_store를 통해 여러 명령어 호출 간에 계정
상태를 유지합니다. 명령어를 처리하는 메소드는 Mollusk와 동일합니다.
각 메소드에 accounts를 전달해야 하는 Mollusk(예: process_instruction)와
달리, MolluskContext는 account_store를 통해 내부적으로 계정을 관리합니다.
이로 인해 명령어를 처리할 때 accounts 매개변수가 필요하지 않습니다.
with_context 메소드를 사용하여 account_store를 생성하세요:
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();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,},);let context = mollusk.with_context(account_store);
다음 예제는 account_store를 통해 명령어 간에 영구적인 계정 상태를 유지하면서
두 개의 별도 SOL 전송 명령어를 처리합니다.
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 Mollusklet mollusk = Mollusk::default();// Create accountslet sender = Pubkey::new_unique();let recipient = Pubkey::new_unique();// Create account store with initial balanceslet 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 contextlet context = mollusk.with_context(account_store);// First transfer: 200,000 lamportslet 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 balanceslet 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);}
Console
Click to execute the code.
Mollusk 시스템 변수
Mollusk는 테스트를 위해 값을 수정할 수 있는 사용자 정의
Sysvars
구조체를 제공합니다.
warp_to_slot 메소드를 사용하여 시스템 변수 시계를 업데이트하여 특정 slot으로
시간을 앞으로 또는 뒤로 이동하는 시뮬레이션을 할 수 있습니다.
Warp to Slot
use mollusk_svm::Mollusk;fn main() {// Initialize Mollusklet mut mollusk = Mollusk::default();// Show initial slotprintln!("Initial slot: {}", mollusk.sysvars.clock.slot);// Warp to slot 1000mollusk.warp_to_slot(100);println!("After warp: {}", mollusk.sysvars.clock.slot);// Warp to slot 10mollusk.warp_to_slot(10);println!("After second warp: {}", mollusk.sysvars.clock.slot);}
Console
Click to execute the code.
다음 예제는 sysvars 필드에 접근하여 rent 매개변수를 변경하기 위해 Mollusk
시스템 변수를 직접 수정하는 방법을 보여줍니다. 다른 시스템 변수 값도 같은
방식으로 수정할 수 있습니다.
Modify Sysvars
use {mollusk_svm::Mollusk, solana_sdk::rent::Rent};fn main() {let mut mollusk = Mollusk::default();// Show default rentprintln!("Default rent exemption for 1000 bytes: {} lamports",mollusk.sysvars.rent.minimum_balance(1000));// Customize rent parametersmollusk.sysvars.rent = Rent {lamports_per_byte_year: 1,exemption_threshold: 1.0,burn_percent: 0,};// Show custom rentprintln!("Custom rent exemption for 1000 bytes: {} lamports",mollusk.sysvars.rent.minimum_balance(1000));}
Console
Click to execute the code.
컴퓨트 유닛 벤치마킹
MolluskComputeUnitBencher
프로그램 명령어의 컴퓨트 유닛 사용량을 추적합니다. 결과는 마크다운 파일로
작성됩니다.
의존성으로
mollusk-svm-bencher가
필요합니다.
다음 예제는 SOL 전송 명령어의 컴퓨트 유닛 사용량을 벤치마킹합니다.
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 Mollusklet mollusk = Mollusk::default();// Create test accountslet sender = Pubkey::new_unique();let receiver = Pubkey::new_unique();// Transfer instructionlet 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 benchmarkMolluskComputeUnitBencher::new(mollusk).bench(("transfer", &transfer, &accounts)).must_pass(true).out_dir("./target/benches").execute();}
벤치마크 결과는 지정된 out_dir에 compute_units.md라는 이름의 마크다운 파일로
작성됩니다.
comput_units.md
#### 2025-09-19 22:28:53.691839 UTCSolana CLI Version: solana-cli 2.2.20 (src:dabc99a5; feat:3073396398,client:Agave)| Name | CUs | Delta || -------- | --- | ------- || transfer | 150 | - new - |
Token Program 테스팅
mollusk-svm-programs-token
크레이트를 사용하여 Token Program, Token2022 Program(Token Extensions) 및
Associated Token Program을 테스트를 위해 Mollusk에 추가합니다.
Example
use {mollusk_svm::Mollusk,mollusk_svm_programs_token::{associated_token, token, token2022},};let mut mollusk = Mollusk::default();// Add SPL Token Programtoken::add_program(&mut mollusk);// Add SPL Token-2022 Programtoken2022::add_program(&mut mollusk);// Add Associated Token Account Programassociated_token::add_program(&mut mollusk);
다음 예제는 Mollusk를 사용한 토큰 전송 테스트를 보여줍니다.
아래 예제는 설명을 위해 테스트 계정을 수동으로 정의합니다.
mollusk-svm-programs-token에는 민트와 token account를 생성하는 헬퍼 함수도
포함되어 있습니다.
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 programlet mut mollusk = Mollusk::default();token::add_program(&mut mollusk);// Create account keyslet mint = Pubkey::new_unique();let source = Pubkey::new_unique();let destination = Pubkey::new_unique();let authority = Pubkey::new_unique();// Token configurationlet decimals = 6;let transfer_amount = 1_000_000; // 1 token with 6 decimalslet initial_balance = 10_000_000; // 10 tokens// Calculate rent-exempt minimumslet mint_rent = mollusk.sysvars.rent.minimum_balance(Mint::LEN);let account_rent = mollusk.sysvars.rent.minimum_balance(TokenAccount::LEN);// Create mint accountlet 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 accountlet 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 accountlet 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_checkedlet 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 instructionlet instruction = transfer_checked(&token::ID,&source,&mint,&destination,&authority,&[],transfer_amount,decimals,).unwrap();// Expected balances after transferlet expected_source_balance = (initial_balance - transfer_amount).to_le_bytes();let expected_dest_balance = transfer_amount.to_le_bytes();// Define validation checkslet 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 instructionlet result = mollusk.process_and_validate_instruction(&instruction, &accounts, &checks);println!("{:#?}", result);// Deserialize token account datalet 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);}
Console
Click to execute the code.
Is this page helpful?