Skip to main content

hpsvm/token/
mod.rs

1//! Token operations for the HPSVM.
2//!
3//! Provides SPL token helpers (transfer, mint, ATA, freeze, etc.) for tests
4//! built on [`crate::HPSVM`]. Enable via the `token` feature.
5
6/// Account snapshot factories for fast fixture and test setup.
7pub mod accounts;
8pub mod error;
9
10pub use self::error::TokenError;
11mod approve;
12mod approve_checked;
13mod burn;
14mod burn_checked;
15mod close_account;
16mod create_account;
17mod create_ata;
18mod create_ata_idempotent;
19mod create_mint;
20mod create_multisig;
21#[cfg(not(feature = "token-2022"))]
22mod create_native_mint;
23#[cfg(feature = "token-2022")]
24mod create_native_mint_2022;
25mod freeze_account;
26mod mint_to;
27mod mint_to_checked;
28mod revoke;
29mod set_authority;
30mod sync_native;
31mod thaw_account;
32mod transfer;
33mod transfer_checked;
34
35use solana_address::Address;
36use solana_keypair::Keypair;
37use solana_program_pack::{IsInitialized, Pack};
38use solana_signer::Signer;
39use solana_transaction::Transaction;
40#[cfg(feature = "token-2022")]
41pub use spl_token_2022_interface as spl_token;
42#[cfg(not(feature = "token-2022"))]
43pub use spl_token_interface as spl_token;
44
45#[cfg(feature = "token-2022")]
46use self::create_native_mint_2022 as create_native_mint;
47pub use self::{
48    approve::*, approve_checked::*, burn::*, burn_checked::*, close_account::*, create_account::*,
49    create_ata::*, create_ata_idempotent::*, create_mint::*, create_multisig::*,
50    create_native_mint::*, freeze_account::*, mint_to::*, mint_to_checked::*, revoke::*,
51    set_authority::*, sync_native::*, thaw_account::*, transfer::*, transfer_checked::*,
52};
53use crate::{HPSVM, types::FailedTransactionMetadata};
54
55/// SPL Token program ID
56pub const TOKEN_ID: Address = spl_token::ID;
57
58/// Get an SPL account from the SVM
59pub fn get_spl_account<T: Pack + IsInitialized>(
60    svm: &HPSVM,
61    account: &Address,
62) -> Result<T, TokenError> {
63    let account = svm.get_account(account).ok_or(TokenError::AccountNotFound(*account))?;
64    let data = account
65        .data
66        .get(..T::LEN)
67        .ok_or(TokenError::AccountDataTooSmall { expected: T::LEN, actual: account.data.len() })?;
68    let account = T::unpack(data)?;
69
70    Ok(account)
71}
72
73fn get_multisig_signers<'a>(
74    authority: &Address,
75    signing_pubkeys: &'a [Address],
76) -> Vec<&'a Address> {
77    if signing_pubkeys == [*authority] {
78        vec![]
79    } else {
80        signing_pubkeys.iter().collect::<Vec<_>>()
81    }
82}
83
84pub(crate) fn sign_and_send(
85    svm: &mut HPSVM,
86    payer: &Keypair,
87    signers: &[&Keypair],
88    ix: solana_instruction::Instruction,
89) -> Result<(), FailedTransactionMetadata> {
90    let payer_pk = payer.pubkey();
91    let block_hash = svm.latest_blockhash();
92    let mut tx = Transaction::new_with_payer(&[ix], Some(&payer_pk));
93    tx.partial_sign(&[payer], block_hash);
94    tx.partial_sign(signers, block_hash);
95    svm.send_transaction(tx)?;
96    Ok(())
97}