light_token/instruction/
transfer.rs1use 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
8pub struct Transfer {
26 pub source: Pubkey,
27 pub destination: Pubkey,
28 pub amount: u64,
29 pub authority: Pubkey,
30 pub max_top_up: Option<u16>,
33 pub fee_payer: Option<Pubkey>,
36}
37
38pub struct TransferCpi<'info> {
59 pub source: AccountInfo<'info>,
60 pub destination: AccountInfo<'info>,
61 pub amount: u64,
62 pub authority: AccountInfo<'info>,
63 pub system_program: AccountInfo<'info>,
64 pub max_top_up: Option<u16>,
66 pub fee_payer: Option<AccountInfo<'info>>,
68}
69
70impl<'info> TransferCpi<'info> {
71 pub fn instruction(&self) -> Result<Instruction, ProgramError> {
72 Transfer::from(self).instruction()
73 }
74
75 pub fn invoke(self) -> Result<(), ProgramError> {
76 let instruction = Transfer::from(&self).instruction()?;
77 if let Some(fee_payer) = self.fee_payer {
78 let account_infos = [
79 self.source,
80 self.destination,
81 self.authority,
82 self.system_program,
83 fee_payer,
84 ];
85 invoke(&instruction, &account_infos)
86 } else {
87 let account_infos = [
88 self.source,
89 self.destination,
90 self.authority,
91 self.system_program,
92 ];
93 invoke(&instruction, &account_infos)
94 }
95 }
96
97 pub fn invoke_signed(self, signer_seeds: &[&[&[u8]]]) -> Result<(), ProgramError> {
98 let instruction = Transfer::from(&self).instruction()?;
99 if let Some(fee_payer) = self.fee_payer {
100 let account_infos = [
101 self.source,
102 self.destination,
103 self.authority,
104 self.system_program,
105 fee_payer,
106 ];
107 invoke_signed(&instruction, &account_infos, signer_seeds)
108 } else {
109 let account_infos = [
110 self.source,
111 self.destination,
112 self.authority,
113 self.system_program,
114 ];
115 invoke_signed(&instruction, &account_infos, signer_seeds)
116 }
117 }
118}
119
120impl<'info> From<&TransferCpi<'info>> for Transfer {
121 fn from(account_infos: &TransferCpi<'info>) -> Self {
122 Self {
123 source: *account_infos.source.key,
124 destination: *account_infos.destination.key,
125 amount: account_infos.amount,
126 authority: *account_infos.authority.key,
127 max_top_up: account_infos.max_top_up,
128 fee_payer: account_infos.fee_payer.as_ref().map(|a| *a.key),
129 }
130 }
131}
132
133impl Transfer {
134 pub fn instruction(self) -> Result<Instruction, ProgramError> {
135 let authority_meta = if self.max_top_up.is_some() && self.fee_payer.is_none() {
138 AccountMeta::new(self.authority, true)
139 } else {
140 AccountMeta::new_readonly(self.authority, true)
141 };
142
143 let mut accounts = vec![
144 AccountMeta::new(self.source, false),
145 AccountMeta::new(self.destination, false),
146 authority_meta,
147 AccountMeta::new_readonly(Pubkey::default(), false),
149 ];
150
151 if let Some(fee_payer) = self.fee_payer {
153 accounts.push(AccountMeta::new(fee_payer, true));
154 }
155
156 Ok(Instruction {
157 program_id: Pubkey::from(LIGHT_TOKEN_PROGRAM_ID),
158 accounts,
159 data: {
160 let mut data = vec![3u8];
161 data.extend_from_slice(&self.amount.to_le_bytes());
162 if let Some(max_top_up) = self.max_top_up {
164 data.extend_from_slice(&max_top_up.to_le_bytes());
165 }
166 data
167 },
168 })
169 }
170}