light_token/instruction/
burn.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:
9/// ```rust
10/// # use solana_pubkey::Pubkey;
11/// # use light_token::instruction::Burn;
12/// # let source = Pubkey::new_unique();
13/// # let mint = Pubkey::new_unique();
14/// # let authority = Pubkey::new_unique();
15/// let instruction = Burn {
16///     source,
17///     mint,
18///     amount: 100,
19///     authority,
20///     max_top_up: None,
21/// }.instruction()?;
22/// # Ok::<(), solana_program_error::ProgramError>(())
23/// ```
24pub struct Burn {
25    /// Light Token account to burn from
26    pub source: Pubkey,
27    /// Mint account (supply tracking)
28    pub mint: Pubkey,
29    /// Amount of tokens to burn
30    pub amount: u64,
31    /// Owner of the Light Token account
32    pub authority: Pubkey,
33    /// Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (0 = no limit)
34    /// When set to a non-zero value, includes max_top_up in instruction data
35    pub max_top_up: Option<u16>,
36}
37
38/// # Burn ctoken via CPI:
39/// ```rust,no_run
40/// # use light_token::instruction::BurnCpi;
41/// # use solana_account_info::AccountInfo;
42/// # let source: AccountInfo = todo!();
43/// # let mint: AccountInfo = todo!();
44/// # let authority: AccountInfo = todo!();
45/// BurnCpi {
46///     source,
47///     mint,
48///     amount: 100,
49///     authority,
50///     max_top_up: None,
51/// }
52/// .invoke()?;
53/// # Ok::<(), solana_program_error::ProgramError>(())
54/// ```
55pub struct BurnCpi<'info> {
56    pub source: AccountInfo<'info>,
57    pub mint: AccountInfo<'info>,
58    pub amount: u64,
59    pub authority: AccountInfo<'info>,
60    /// Maximum lamports for rent and top-up combined. Transaction fails if exceeded. (0 = no limit)
61    pub max_top_up: Option<u16>,
62}
63
64impl<'info> BurnCpi<'info> {
65    pub fn instruction(&self) -> Result<Instruction, ProgramError> {
66        Burn::from(self).instruction()
67    }
68
69    pub fn invoke(self) -> Result<(), ProgramError> {
70        let instruction = Burn::from(&self).instruction()?;
71        let account_infos = [self.source, self.mint, self.authority];
72        invoke(&instruction, &account_infos)
73    }
74
75    pub fn invoke_signed(self, signer_seeds: &[&[&[u8]]]) -> Result<(), ProgramError> {
76        let instruction = Burn::from(&self).instruction()?;
77        let account_infos = [self.source, self.mint, self.authority];
78        invoke_signed(&instruction, &account_infos, signer_seeds)
79    }
80}
81
82impl<'info> From<&BurnCpi<'info>> for Burn {
83    fn from(cpi: &BurnCpi<'info>) -> Self {
84        Self {
85            source: *cpi.source.key,
86            mint: *cpi.mint.key,
87            amount: cpi.amount,
88            authority: *cpi.authority.key,
89            max_top_up: cpi.max_top_up,
90        }
91    }
92}
93
94impl Burn {
95    pub fn instruction(self) -> Result<Instruction, ProgramError> {
96        Ok(Instruction {
97            program_id: Pubkey::from(LIGHT_TOKEN_PROGRAM_ID),
98            accounts: vec![
99                AccountMeta::new(self.source, false),
100                AccountMeta::new(self.mint, false),
101                AccountMeta::new_readonly(self.authority, true),
102            ],
103            data: {
104                let mut data = vec![8u8]; // CTokenBurn discriminator
105                data.extend_from_slice(&self.amount.to_le_bytes());
106                // Include max_top_up if set (10-byte format)
107                if let Some(max_top_up) = self.max_top_up {
108                    data.extend_from_slice(&max_top_up.to_le_bytes());
109                }
110                data
111            },
112        })
113    }
114}