light_token/instruction/
burn_checked.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 BurnChecked {
27 pub source: Pubkey,
29 pub mint: Pubkey,
31 pub amount: u64,
33 pub decimals: u8,
35 pub authority: Pubkey,
37 pub max_top_up: Option<u16>,
40 pub fee_payer: Option<Pubkey>,
42}
43
44pub struct BurnCheckedCpi<'info> {
66 pub source: AccountInfo<'info>,
67 pub mint: AccountInfo<'info>,
68 pub amount: u64,
69 pub decimals: u8,
70 pub authority: AccountInfo<'info>,
71 pub system_program: AccountInfo<'info>,
72 pub max_top_up: Option<u16>,
74 pub fee_payer: Option<AccountInfo<'info>>,
76}
77
78impl<'info> BurnCheckedCpi<'info> {
79 pub fn instruction(&self) -> Result<Instruction, ProgramError> {
80 BurnChecked::from(self).instruction()
81 }
82
83 pub fn invoke(self) -> Result<(), ProgramError> {
84 let instruction = BurnChecked::from(&self).instruction()?;
85 if let Some(fee_payer) = self.fee_payer {
86 let account_infos = [
87 self.source,
88 self.mint,
89 self.authority,
90 self.system_program,
91 fee_payer,
92 ];
93 invoke(&instruction, &account_infos)
94 } else {
95 let account_infos = [self.source, self.mint, self.authority, self.system_program];
96 invoke(&instruction, &account_infos)
97 }
98 }
99
100 pub fn invoke_signed(self, signer_seeds: &[&[&[u8]]]) -> Result<(), ProgramError> {
101 let instruction = BurnChecked::from(&self).instruction()?;
102 if let Some(fee_payer) = self.fee_payer {
103 let account_infos = [
104 self.source,
105 self.mint,
106 self.authority,
107 self.system_program,
108 fee_payer,
109 ];
110 invoke_signed(&instruction, &account_infos, signer_seeds)
111 } else {
112 let account_infos = [self.source, self.mint, self.authority, self.system_program];
113 invoke_signed(&instruction, &account_infos, signer_seeds)
114 }
115 }
116}
117
118impl<'info> From<&BurnCheckedCpi<'info>> for BurnChecked {
119 fn from(cpi: &BurnCheckedCpi<'info>) -> Self {
120 Self {
121 source: *cpi.source.key,
122 mint: *cpi.mint.key,
123 amount: cpi.amount,
124 decimals: cpi.decimals,
125 authority: *cpi.authority.key,
126 max_top_up: cpi.max_top_up,
127 fee_payer: cpi.fee_payer.as_ref().map(|a| *a.key),
128 }
129 }
130}
131
132impl BurnChecked {
133 pub fn instruction(self) -> Result<Instruction, ProgramError> {
134 let authority_meta = if self.max_top_up.is_some() && self.fee_payer.is_none() {
137 AccountMeta::new(self.authority, true)
138 } else {
139 AccountMeta::new_readonly(self.authority, true)
140 };
141
142 let mut accounts = vec![
143 AccountMeta::new(self.source, false),
144 AccountMeta::new(self.mint, false),
145 authority_meta,
146 AccountMeta::new_readonly(Pubkey::default(), false),
148 ];
149
150 if let Some(fee_payer) = self.fee_payer {
152 accounts.push(AccountMeta::new(fee_payer, true));
153 }
154
155 Ok(Instruction {
156 program_id: Pubkey::from(LIGHT_TOKEN_PROGRAM_ID),
157 accounts,
158 data: {
159 let mut data = vec![15u8]; data.extend_from_slice(&self.amount.to_le_bytes());
161 data.push(self.decimals);
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}