Skip to main content

hpsvm_token/
transfer.rs

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