litesvm_token/
transfer_checked.rs1use {
2 super::{
3 get_multisig_signers, get_spl_account,
4 spl_token::{instruction::transfer_checked, state::Mint},
5 TOKEN_ID,
6 },
7 litesvm::{types::FailedTransactionMetadata, LiteSVM},
8 smallvec::{smallvec, SmallVec},
9 solana_keypair::Keypair,
10 solana_pubkey::Pubkey,
11 solana_signer::{signers::Signers, Signer},
12 solana_transaction::Transaction,
13};
14
15pub struct TransferChecked<'a> {
24 svm: &'a mut LiteSVM,
25 payer: &'a Keypair,
26 mint: &'a Pubkey,
27 source: Option<&'a Pubkey>,
28 destination: &'a Pubkey,
29 token_program_id: Option<&'a Pubkey>,
30 amount: u64,
31 decimals: Option<u8>,
32 signers: SmallVec<[&'a Keypair; 1]>,
33 owner: Option<Pubkey>,
34}
35
36impl<'a> TransferChecked<'a> {
37 pub fn new(
39 svm: &'a mut LiteSVM,
40 payer: &'a Keypair,
41 mint: &'a Pubkey,
42 destination: &'a Pubkey,
43 amount: u64,
44 ) -> Self {
45 TransferChecked {
46 svm,
47 payer,
48 mint,
49 source: None,
50 destination,
51 token_program_id: None,
52 amount,
53 decimals: None,
54 owner: None,
55 signers: smallvec![payer],
56 }
57 }
58
59 pub fn token_program_id(mut self, program_id: &'a Pubkey) -> Self {
61 self.token_program_id = Some(program_id);
62 self
63 }
64
65 pub fn decimals(mut self, value: u8) -> Self {
67 self.decimals = Some(value);
68 self
69 }
70
71 pub fn source(mut self, source: &'a Pubkey) -> Self {
73 self.source = Some(source);
74 self
75 }
76
77 pub fn owner(mut self, owner: &'a Keypair) -> Self {
79 self.owner = Some(owner.pubkey());
80 self.signers = smallvec![owner];
81 self
82 }
83
84 pub fn multisig(mut self, multisig: &'a Pubkey, signers: &'a [&'a Keypair]) -> Self {
86 self.owner = Some(*multisig);
87 self.signers = SmallVec::from(signers);
88 self
89 }
90
91 pub fn send(self) -> Result<(), FailedTransactionMetadata> {
93 let payer_pk = self.payer.pubkey();
94 let token_program_id = self.token_program_id.unwrap_or(&TOKEN_ID);
95
96 let authority = self.owner.unwrap_or(payer_pk);
97 let signing_keys = self.signers.pubkeys();
98 let signer_keys = get_multisig_signers(&authority, &signing_keys);
99
100 let source_pk = if let Some(source) = self.source {
101 *source
102 } else {
103 spl_associated_token_account_interface::address::get_associated_token_address_with_program_id(
104 &authority,
105 self.mint,
106 token_program_id,
107 )
108 };
109
110 let mint: Mint = get_spl_account(self.svm, self.mint)?;
111 let ix = transfer_checked(
112 token_program_id,
113 &source_pk,
114 self.mint,
115 self.destination,
116 &authority,
117 &signer_keys,
118 self.amount,
119 self.decimals.unwrap_or(mint.decimals),
120 )?;
121
122 let block_hash = self.svm.latest_blockhash();
123 let mut tx = Transaction::new_with_payer(&[ix], Some(&payer_pk));
124 tx.partial_sign(&[self.payer], block_hash);
125 tx.partial_sign(self.signers.as_ref(), block_hash);
126
127 self.svm.send_transaction(tx)?;
128
129 Ok(())
130 }
131}