Skip to main content

light_token/instruction/
transfer_checked.rs

1use light_sdk_types::LIGHT_TOKEN_PROGRAM_ID;
2use solana_account_info::AccountInfo;
3use solana_cpi::{invoke, invoke_signed};
4use solana_instruction::{AccountMeta, Instruction};
5use solana_program_error::ProgramError;
6use solana_pubkey::Pubkey;
7
8/// # Create a transfer ctoken checked instruction:
9/// ```rust
10/// # use solana_pubkey::Pubkey;
11/// # use light_token::instruction::TransferChecked;
12/// # let source = Pubkey::new_unique();
13/// # let mint = Pubkey::new_unique();
14/// # let destination = Pubkey::new_unique();
15/// # let authority = Pubkey::new_unique();
16/// # let fee_payer = Pubkey::new_unique();
17/// let instruction = TransferChecked {
18///     source,
19///     mint,
20///     destination,
21///     amount: 100,
22///     decimals: 9,
23///     authority,
24///     fee_payer,
25/// }.instruction()?;
26/// # Ok::<(), solana_program_error::ProgramError>(())
27/// ```
28pub struct TransferChecked {
29    pub source: Pubkey,
30    pub mint: Pubkey,
31    pub destination: Pubkey,
32    pub amount: u64,
33    pub decimals: u8,
34    pub authority: Pubkey,
35    /// Fee payer for rent top-ups.
36    pub fee_payer: Pubkey,
37}
38
39/// # Transfer ctoken checked via CPI:
40/// ```rust,no_run
41/// # use light_token::instruction::TransferCheckedCpi;
42/// # use solana_account_info::AccountInfo;
43/// # let source: AccountInfo = todo!();
44/// # let mint: AccountInfo = todo!();
45/// # let destination: AccountInfo = todo!();
46/// # let authority: AccountInfo = todo!();
47/// # let system_program: AccountInfo = todo!();
48/// # let fee_payer: AccountInfo = todo!();
49/// TransferCheckedCpi {
50///     source,
51///     mint,
52///     destination,
53///     amount: 100,
54///     decimals: 9,
55///     authority,
56///     system_program,
57///     fee_payer,
58/// }
59/// .invoke()?;
60/// # Ok::<(), solana_program_error::ProgramError>(())
61/// ```
62pub struct TransferCheckedCpi<'info> {
63    pub source: AccountInfo<'info>,
64    pub mint: AccountInfo<'info>,
65    pub destination: AccountInfo<'info>,
66    pub amount: u64,
67    pub decimals: u8,
68    pub authority: AccountInfo<'info>,
69    pub system_program: AccountInfo<'info>,
70    /// Fee payer for rent top-ups.
71    pub fee_payer: AccountInfo<'info>,
72}
73
74impl<'info> TransferCheckedCpi<'info> {
75    pub fn instruction(&self) -> Result<Instruction, ProgramError> {
76        TransferChecked::from(self).instruction()
77    }
78
79    pub fn invoke(self) -> Result<(), ProgramError> {
80        let instruction = TransferChecked::from(&self).instruction()?;
81        let account_infos = [
82            self.source,
83            self.mint,
84            self.destination,
85            self.authority,
86            self.system_program,
87            self.fee_payer,
88        ];
89        invoke(&instruction, &account_infos)
90    }
91
92    pub fn invoke_signed(self, signer_seeds: &[&[&[u8]]]) -> Result<(), ProgramError> {
93        let instruction = TransferChecked::from(&self).instruction()?;
94        let account_infos = [
95            self.source,
96            self.mint,
97            self.destination,
98            self.authority,
99            self.system_program,
100            self.fee_payer,
101        ];
102        invoke_signed(&instruction, &account_infos, signer_seeds)
103    }
104}
105
106impl<'info> From<&TransferCheckedCpi<'info>> for TransferChecked {
107    fn from(account_infos: &TransferCheckedCpi<'info>) -> Self {
108        Self {
109            source: *account_infos.source.key,
110            mint: *account_infos.mint.key,
111            destination: *account_infos.destination.key,
112            amount: account_infos.amount,
113            decimals: account_infos.decimals,
114            authority: *account_infos.authority.key,
115            fee_payer: *account_infos.fee_payer.key,
116        }
117    }
118}
119
120impl_with_top_up!(TransferChecked, TransferCheckedWithTopUp);
121
122impl TransferChecked {
123    fn build_instruction(self, max_top_up: Option<u16>) -> Result<Instruction, ProgramError> {
124        let accounts = vec![
125            AccountMeta::new(self.source, false),
126            AccountMeta::new_readonly(self.mint, false),
127            AccountMeta::new(self.destination, false),
128            AccountMeta::new_readonly(self.authority, true),
129            AccountMeta::new_readonly(Pubkey::default(), false),
130            AccountMeta::new(self.fee_payer, true),
131        ];
132
133        let mut data = vec![12u8];
134        data.extend_from_slice(&self.amount.to_le_bytes());
135        data.push(self.decimals);
136        if let Some(max_top_up) = max_top_up {
137            data.extend_from_slice(&max_top_up.to_le_bytes());
138        }
139
140        Ok(Instruction {
141            program_id: Pubkey::from(LIGHT_TOKEN_PROGRAM_ID),
142            accounts,
143            data,
144        })
145    }
146}