Mollusk
Mollusk è un framework di test leggero per testare i programmi Solana. Fornisce un'interfaccia semplice per testare le istruzioni dei programmi Solana in un ambiente Solana Virtual Machine (SVM) minimizzato. Tutti gli account di test devono essere definiti esplicitamente, garantendo test deterministici e ripetibili.
Installazione
Aggiungi mollusk-svm come dipendenza nel file Cargo.toml:
Terminal
$cargo add mollusk-svm --dev
Cargo.toml
[dev-dependencies]mollusk-svm = "0.7"
Per valutare l'utilizzo delle unità di calcolo, aggiungi mollusk-svm-bencher
come dipendenza nel Cargo.toml:
Terminal
$cargo add mollusk-svm-bencher --dev
Cargo.toml
[dev-dependencies]mollusk-svm-bencher = "0.7"
Per utilizzare il Token Program, il token2022 program (Token Extensions) e
l'Associated Token Program per i test con Mollusk, aggiungi
mollusk-svm-programs-token come dipendenza nel Cargo.toml:
Terminal
$cargo add mollusk-svm-programs-token --dev
Cargo.toml
[dev-dependencies]mollusk-svm-programs-token = "0.7"
Mollusk SVM
L'esempio seguente mostra una configurazione minima per testare un programma Solana di base utilizzando Mollusk.
Programma Hello World
Questo esempio dimostra come testare un programma Solana di base utilizzando Mollusk. Il programma stampa semplicemente "Hello, world!" nei log del programma quando viene invocato.
L'esecuzione di cargo build-sbf genera il programma compilato in
/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()]);}}
Per testare un programma Solana con Mollusk:
- Crea un'istanza di
Mollusk- Inizializza Mollusk con un program ID e il percorso del programma compilato (file.so) - Costruisci un'istruzione - Crea un'istruzione per invocare il programma
- Elabora e valida - Elabora l'istruzione utilizzando Mollusk e valida il risultato
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()]);}}
Per eseguire il test, esegui cargo test.
Quando il test viene eseguito con successo, vedrai un output simile al seguente:
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
La struct
Mollusk
fornisce un'interfaccia semplice per testare i programmi Solana. Tutti i campi
possono essere manipolati attraverso una manciata di metodi di supporto, ma gli
utenti possono anche accedere e modificarli direttamente se desiderano un
maggiore controllo.
Per inizializzare Mollusk con un'istanza predefinita, utilizza il metodo
Mollusk::default.
Example
// Default instance with no custom programslet mollusk = Mollusk::default();
Per inizializzare Mollusk con un programma specifico, utilizza il metodo
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");
Per aggiungere un programma a Mollusk, utilizza il metodo
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(),);
Quando fornisci il percorso del file, non includere l'estensione .so. Per
esempio, "path/to/my_program" è corretto, ma "path/to/my_program.so" non
lo è.
Elaborazione delle istruzioni
Mollusk fornisce quattro metodi principali per elaborare le istruzioni:
| Metodo | Descrizione |
|---|---|
process_instruction | Elabora un'istruzione e restituisce il risultato. |
process_and_validate_instruction | Elabora un'istruzione ed esegue una serie di controlli sul risultato, generando un panic se qualsiasi controllo fallisce. |
process_instruction_chain | Elabora più istruzioni e restituisce il risultato. |
process_and_validate_instruction_chain | Elabora più istruzioni ed esegue una serie di controlli su ciascun risultato, generando un panic se qualsiasi controllo fallisce. |
La
InstructionResult
contiene i dettagli di un'istruzione elaborata.
Istruzione singola
Utilizza il metodo process_instruction per elaborare una singola istruzione
senza controlli sul risultato. Puoi convalidare manualmente i risultati dopo
l'elaborazione.
Method Signature
pub fn process_instruction(&self,instruction: &Instruction,accounts: &[(Pubkey, Account)],) -> InstructionResult
L'esempio seguente elabora un'istruzione di trasferimento di SOL senza controlli di validazione.
Gli esempi seguenti eseguono Mollusk nella funzione main a scopo dimostrativo.
In pratica, tipicamente utilizzerai Mollusk in un modulo di test annotato con
l'attributo #[test].
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.
Istruzione singola con controlli
Utilizza il metodo process_and_validate_instruction per elaborare una singola
istruzione con controlli di validazione. Questo metodo genererà un panic se
qualsiasi controllo fallisce.
Method Signature
pub fn process_and_validate_instruction(&self,instruction: &Instruction,accounts: &[(Pubkey, Account)],checks: &[Check],) -> InstructionResult
L'esempio seguente elabora un'istruzione di trasferimento SOL con controlli di validazione.
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.
Istruzioni multiple
Utilizza il metodo process_instruction_chain per elaborare più istruzioni in
sequenza senza controlli di validazione.
Method Signature
pub fn process_instruction_chain(&self,instructions: &[Instruction],accounts: &[(Pubkey, Account)],) -> InstructionResult
L'esempio seguente elabora due istruzioni di trasferimento SOL senza controlli di validazione.
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.
Istruzioni multiple con controlli
Utilizza il metodo process_and_validate_instruction_chain per elaborare più
istruzioni con controlli di validazione dopo ogni istruzione. Ogni istruzione ha
il proprio set di controlli che devono essere superati.
Method Signature
pub fn process_and_validate_instruction_chain(&self,instructions: &[(&Instruction, &[Check])],accounts: &[(Pubkey, Account)],) -> InstructionResult
L'esempio seguente elabora una catena di due istruzioni di trasferimento SOL con controlli di validazione dopo ogni istruzione.
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.
Controlli di validazione
Mollusk fornisce un insieme di metodi di supporto per verificare i risultati di un'istruzione elaborata.
Example
use mollusk_svm::result::Check;
Utilizza i seguenti metodi per validare i risultati delle istruzioni:
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])
Utilizza i seguenti per validare gli stati degli Account:
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()
Stato persistente dell'account
Il
MolluskContext
è un wrapper attorno a Mollusk che mantiene lo stato dell'account attraverso
più chiamata di istruzioni tramite il suo account_store. I metodi per
elaborare le istruzioni sono identici a Mollusk.
A differenza di Mollusk, che richiede di passare accounts a ciascun metodo
(ad es. process_instruction), MolluskContext gestisce gli account
internamente attraverso il suo account_store. Questo elimina la necessità del
parametro accounts durante l'elaborazione delle istruzioni.
Crea un account_store utilizzando il metodo with_context:
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);
Il seguente esempio elabora due istruzioni separate di trasferimento di SOL con
stato dell'account persistente tra le istruzioni attraverso il account_store.
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.
Sysvars di Mollusk
Mollusk fornisce una struttura personalizzata
Sysvars
per modificare i suoi valori per i test.
Utilizza il metodo warp_to_slot per aggiornare il clock sysvar per simulare lo
spostamento avanti o indietro nel tempo fino a uno slot specifico.
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.
Il seguente esempio mostra come modificare direttamente il sysvar di Mollusk
accedendo al campo sysvars per cambiare i parametri di rent. Puoi modificare
altri valori sysvar allo stesso modo.
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.
Benchmarking delle unità di calcolo
MolluskComputeUnitBencher
tiene traccia dell'utilizzo delle unità di calcolo delle istruzioni di un
programma. I risultati vengono scritti in un file markdown.
Richiede
mollusk-svm-bencher
come dipendenza.
Il seguente esempio esegue il benchmarking dell'utilizzo delle unità di calcolo di un'istruzione di trasferimento 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();}
I risultati del benchmark vengono scritti nel out_dir specificato come file
markdown denominato 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 - |
Test del Token Program
Utilizza il crate
mollusk-svm-programs-token
per aggiungere il Token Program, il token2022 program (Token Extensions) e
l'Associated Token Program a Mollusk per i test.
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);
Il seguente esempio dimostra come testare un trasferimento di token utilizzando Mollusk.
L'esempio seguente definisce manualmente gli account di test a scopo
dimostrativo. Il mollusk-svm-programs-token include anche funzioni di
supporto per creare gli account mint e token.
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?