Skip to main content

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