litesvm_token/
transfer.rs

1#[cfg_attr(feature = "token-2022", allow(deprecated))]
2use super::{spl_token::instruction::transfer, TOKEN_ID};
3use {
4    super::get_multisig_signers,
5    litesvm::{types::FailedTransactionMetadata, LiteSVM},
6    smallvec::{smallvec, SmallVec},
7    solana_keypair::Keypair,
8    solana_pubkey::Pubkey,
9    solana_signer::{signers::Signers, Signer},
10    solana_transaction::Transaction,
11};
12
13/// ### Description
14/// Builder for the [`transfer`] instruction.
15///
16/// ### Optional fields
17/// - `source`: associated token account of the `owner` by default.
18/// - `owner`: `payer` by default.
19/// - `token_program_id`: [`TOKEN_ID`] by default.
20pub struct Transfer<'a> {
21    svm: &'a mut LiteSVM,
22    payer: &'a Keypair,
23    mint: &'a Pubkey,
24    source: Option<&'a Pubkey>,
25    destination: &'a Pubkey,
26    token_program_id: Option<&'a Pubkey>,
27    amount: u64,
28    signers: SmallVec<[&'a Keypair; 1]>,
29    owner: Option<Pubkey>,
30}
31
32impl<'a> Transfer<'a> {
33    /// Creates a new instance of [`transfer`] instruction.
34    pub fn new(
35        svm: &'a mut LiteSVM,
36        payer: &'a Keypair,
37        mint: &'a Pubkey,
38        destination: &'a Pubkey,
39        amount: u64,
40    ) -> Self {
41        Transfer {
42            svm,
43            payer,
44            source: None,
45            destination,
46            token_program_id: None,
47            amount,
48            mint,
49            owner: None,
50            signers: smallvec![payer],
51        }
52    }
53
54    /// Sets the token program id for the instruction.
55    pub fn token_program_id(mut self, program_id: &'a Pubkey) -> Self {
56        self.token_program_id = Some(program_id);
57        self
58    }
59
60    /// Sets the token account source.
61    pub fn source(mut self, source: &'a Pubkey) -> Self {
62        self.source = Some(source);
63        self
64    }
65
66    /// Sets the owner of the account with single owner.
67    pub fn owner(mut self, owner: &'a Keypair) -> Self {
68        self.owner = Some(owner.pubkey());
69        self.signers = smallvec![owner];
70        self
71    }
72
73    /// Sets the owner of the account with multisig owner.
74    pub fn multisig(mut self, multisig: &'a Pubkey, signers: &'a [&'a Keypair]) -> Self {
75        self.owner = Some(*multisig);
76        self.signers = SmallVec::from(signers);
77        self
78    }
79
80    /// Sends the transaction.
81    pub fn send(self) -> Result<(), FailedTransactionMetadata> {
82        let payer_pk = self.payer.pubkey();
83        let token_program_id = self.token_program_id.unwrap_or(&TOKEN_ID);
84
85        let authority = self.owner.unwrap_or(payer_pk);
86        let signing_keys = self.signers.pubkeys();
87        let signer_keys = get_multisig_signers(&authority, &signing_keys);
88
89        let source_pk = if let Some(source) = self.source {
90            *source
91        } else {
92            spl_associated_token_account_interface::address::get_associated_token_address_with_program_id(
93                &authority,
94                self.mint,
95                token_program_id,
96            )
97        };
98
99        #[cfg_attr(feature = "token-2022", allow(deprecated))]
100        let ix = transfer(
101            token_program_id,
102            &source_pk,
103            self.destination,
104            &authority,
105            &signer_keys,
106            self.amount,
107        )?;
108
109        let block_hash = self.svm.latest_blockhash();
110        let mut tx = Transaction::new_with_payer(&[ix], Some(&payer_pk));
111        tx.partial_sign(&[self.payer], block_hash);
112        tx.partial_sign(self.signers.as_ref(), block_hash);
113
114        self.svm.send_transaction(tx)?;
115
116        Ok(())
117    }
118}