sss_token/instructions/
burn.rs1use anchor_lang::prelude::*;
2use anchor_spl::{
3 token_2022::{self, Burn, Token2022},
4 token_interface::TokenAccount,
5};
6
7use crate::errors::SssError;
8use crate::events::TokensBurned;
9use crate::state::*;
10use crate::utils::require_not_paused;
11
12#[derive(Accounts)]
13pub struct BurnTokens<'info> {
14 #[account(mut)]
15 pub burner: Signer<'info>,
16
17 #[account(
18 mut,
19 seeds = [StablecoinConfig::SEED_PREFIX, config.mint.as_ref()],
20 bump = config.bump,
21 )]
22 pub config: Account<'info, StablecoinConfig>,
23
24 #[account(
26 mut,
27 address = config.mint,
28 constraint = mint.owner == &token_program.key() @ SssError::InvalidAuthority,
29 )]
30 pub mint: UncheckedAccount<'info>,
31
32 #[account(
36 mut,
37 token::mint = config.mint,
38 token::token_program = token_program,
39 )]
40 pub burn_token_account: InterfaceAccount<'info, TokenAccount>,
41
42 pub token_program: Program<'info, Token2022>,
43}
44
45pub fn handler(ctx: Context<BurnTokens>, amount: u64) -> Result<()> {
46 require!(amount > 0, SssError::BurnAmountZero);
47
48 let config = &ctx.accounts.config;
49 require_not_paused(config)?;
50
51 require!(
52 ctx.accounts.burn_token_account.amount >= amount,
53 SssError::InsufficientBalance
54 );
55
56 let clock = Clock::get()?;
57 let burner_key = ctx.accounts.burner.key();
58 let token_account_owner = ctx.accounts.burn_token_account.owner;
59
60 if burner_key == token_account_owner {
61 token_2022::burn(
63 CpiContext::new(
64 ctx.accounts.token_program.to_account_info(),
65 Burn {
66 mint: ctx.accounts.mint.to_account_info(),
67 from: ctx.accounts.burn_token_account.to_account_info(),
68 authority: ctx.accounts.burner.to_account_info(),
69 },
70 ),
71 amount,
72 )?;
73 } else if burner_key == config.master_authority {
74 require!(
76 config.enable_permanent_delegate,
77 SssError::FeatureNotEnabled
78 );
79
80 let mint_key = config.mint;
81 let signer_seeds: &[&[&[u8]]] = &[&[
82 StablecoinConfig::SEED_PREFIX,
83 mint_key.as_ref(),
84 &[config.bump],
85 ]];
86
87 token_2022::burn(
88 CpiContext::new_with_signer(
89 ctx.accounts.token_program.to_account_info(),
90 Burn {
91 mint: ctx.accounts.mint.to_account_info(),
92 from: ctx.accounts.burn_token_account.to_account_info(),
93 authority: ctx.accounts.config.to_account_info(), },
95 signer_seeds,
96 ),
97 amount,
98 )?;
99 } else {
100 return Err(SssError::InvalidAuthority.into());
101 }
102
103 let config = &mut ctx.accounts.config;
105 config.total_burned = config
106 .total_burned
107 .checked_add(amount)
108 .ok_or(SssError::Overflow)?;
109 config.updated_at = clock.unix_timestamp;
110
111 emit!(TokensBurned {
112 config: config.key(),
113 burner: ctx.accounts.burner.key(),
114 from: ctx.accounts.burn_token_account.key(),
115 amount,
116 total_burned: config.total_burned,
117 timestamp: clock.unix_timestamp,
118 });
119
120 Ok(())
121}