Skip to main content

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