Mollusk는 Solana 프로그램 테스트를 위한 경량 테스트 하네스입니다. 최소화된 Solana Virtual Machine(SVM) 환경에서 Solana 프로그램 명령어를 테스트하기 위한 간단한 인터페이스를 제공합니다. 모든 테스트 계정은 명시적으로 정의되어야 하며, 이를 통해 결정론적이고 반복 가능한 테스트를 보장합니다.
설치
Cargo.toml에 mollusk-svm를 의존성으로 추가합니다:
$cargo add mollusk-svm --dev
[dev-dependencies]mollusk-svm = "0.7"
컴퓨트 유닛 사용량을 벤치마크하려면 Cargo.toml에 mollusk-svm-bencher를
의존성으로 추가합니다:
$cargo add mollusk-svm-bencher --dev
[dev-dependencies]mollusk-svm-bencher = "0.7"
Mollusk를 사용한 테스트를 위해 Token Program, Token2022 Program(Token
Extensions) 및 Associated Token Program을 사용하려면 Cargo.toml에
mollusk-svm-programs-token를 의존성으로 추가합니다:
$cargo add mollusk-svm-programs-token --dev
[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에 생성됩니다.
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를 사용하여 명령어를 처리하고 결과를 검증합니다
#[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를 실행하세요.
테스트가 성공적으로 실행되면 다음과 유사한 출력이 표시됩니다:
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 메서드를 사용하세요.
// Default instance with no custom programslet mollusk = Mollusk::default();
특정 프로그램으로 Mollusk를 초기화하려면 Mollusk::new 메서드를 사용하세요.
// 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 메서드를 사용하세요.
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 메서드를 사용하여 결과에 대한 검사 없이 단일 명령어를
처리합니다. 처리 후 수동으로 결과를 검증할 수 있습니다.
pub fn process_instruction(&self,instruction: &Instruction,accounts: &[(Pubkey, Account)],) -> InstructionResult
다음 예제는 검증 확인 없이 SOL 전송 명령어를 처리합니다.
아래 예제는 데모 목적으로 main 함수에서 Mollusk를 실행합니다. 실제로는
일반적으로 #[test] 속성으로 주석 처리된 테스트 모듈에서 Mollusk를 사용합니다.
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);}
검사가 포함된 단일 명령어
process_and_validate_instruction 메서드를 사용하여 검증 확인과 함께 단일
명령어를 처리합니다. 이 메서드는 검사가 실패하면 패닉을 발생시킵니다.
pub fn process_and_validate_instruction(&self,instruction: &Instruction,accounts: &[(Pubkey, Account)],checks: &[Check],) -> InstructionResult
다음 예제는 검증 확인과 함께 SOL 전송 명령어를 처리합니다.
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);}
다중 명령어
process_instruction_chain 메서드를 사용하여 검증 확인 없이 여러 명령어를
순차적으로 처리합니다.
pub fn process_instruction_chain(&self,instructions: &[Instruction],accounts: &[(Pubkey, Account)],) -> InstructionResult
다음 예제는 검증 확인 없이 두 개의 SOL 전송 명령어를 처리합니다.
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);}
검사가 포함된 다중 명령어
process_and_validate_instruction_chain 메서드를 사용하여 각 명령어 후 검증
검사와 함께 여러 명령어를 처리합니다. 각 명령어에는 통과해야 하는 자체 검사
세트가 있습니다.
pub fn process_and_validate_instruction_chain(&self,instructions: &[(&Instruction, &[Check])],accounts: &[(Pubkey, Account)],) -> InstructionResult
다음 예제는 각 명령어 후 검증 검사와 함께 두 개의 SOL 전송 명령어 체인을 처리합니다.
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);}
검증 검사
Mollusk는 처리된 명령어의 결과를 확인하기 위한 헬퍼 메서드 세트를 제공합니다.
use mollusk_svm::result::Check;
명령어 결과를 검증하려면 다음 메서드를 사용하세요:
// 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])
계정 상태를 검증하려면 다음을 사용하세요:
// 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를 생성합니다:
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 전송 명령어를 처리합니다.
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);}
Mollusk Sysvars
Mollusk는 테스트를 위해 값을 수정할 수 있는 커스텀
Sysvars
구조체를 제공합니다.
warp_to_slot 메서드를 사용하여 sysvar 클록을 업데이트하고 특정 슬롯으로 시간을
앞뒤로 이동하는 것을 시뮬레이션합니다.
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);}
다음 예제는 sysvars 필드에 직접 접근하여 Mollusk sysvar를 수정하고 rent
매개변수를 변경하는 방법을 보여줍니다. 동일한 방식으로 다른 sysvar 값도 수정할
수 있습니다.
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));}
컴퓨트 유닛 벤치마킹
MolluskComputeUnitBencher는
프로그램 명령어의 컴퓨트 유닛 사용량을 추적합니다. 결과는 마크다운 파일로
작성됩니다.
의존성으로
mollusk-svm-bencher가
필요합니다.
다음 예제는 SOL 전송 명령어의 컴퓨트 유닛 사용량을 벤치마킹합니다.
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라는 이름의 마크다운 파일로
작성됩니다.
#### 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에 추가합니다.
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에는 민트 및 토큰 계정을 생성하는 헬퍼 함수도
포함되어 있습니다.
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);}
Is this page helpful?