mpl_candy_guard/guards/
token_burn.rs

1use super::*;
2
3use crate::{state::GuardType, utils::*};
4
5/// Guard that requires addresses that hold an amount of a specified spl-token
6/// and burns them.
7///
8/// List of accounts required:
9///
10///   0. `[writable]` Token account holding the required amount.
11///   1. `[writable]` Token mint account.
12#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)]
13pub struct TokenBurn {
14    pub amount: u64,
15    pub mint: Pubkey,
16}
17
18impl Guard for TokenBurn {
19    fn size() -> usize {
20        8    // amount
21        + 32 // mint
22    }
23
24    fn mask() -> u64 {
25        GuardType::as_mask(GuardType::TokenBurn)
26    }
27}
28
29impl Condition for TokenBurn {
30    fn validate<'info>(
31        &self,
32        ctx: &mut EvaluationContext,
33        _guard_set: &GuardSet,
34        _mint_args: &[u8],
35    ) -> Result<()> {
36        // retrieves the (potential) token gate account
37        let token_gate_index = ctx.account_cursor;
38        let token_gate_account = try_get_account_info(ctx.accounts.remaining, token_gate_index)?;
39        // consumes the gate token account
40        ctx.account_cursor += 1;
41
42        let account = assert_is_ata(token_gate_account, &ctx.accounts.minter.key(), &self.mint)?;
43
44        if account.amount >= self.amount {
45            let token_gate_mint =
46                try_get_account_info(ctx.accounts.remaining, token_gate_index + 1)?;
47            // consumes the remaning account
48            ctx.account_cursor += 1;
49
50            // is the mint account the one expected?
51            assert_keys_equal(&token_gate_mint.key(), &self.mint)?;
52        } else {
53            return err!(CandyGuardError::NotEnoughTokens);
54        }
55
56        ctx.indices.insert("token_burn_index", token_gate_index);
57
58        Ok(())
59    }
60
61    fn pre_actions<'info>(
62        &self,
63        ctx: &mut EvaluationContext,
64        _guard_set: &GuardSet,
65        _mint_args: &[u8],
66    ) -> Result<()> {
67        let token_gate_index = ctx.indices["token_burn_index"];
68        // the accounts have already being validated
69        let token_gate_account = try_get_account_info(ctx.accounts.remaining, token_gate_index)?;
70        let token_gate_mint = try_get_account_info(ctx.accounts.remaining, token_gate_index + 1)?;
71
72        spl_token_burn(TokenBurnParams {
73            mint: token_gate_mint.to_account_info(),
74            source: token_gate_account.to_account_info(),
75            amount: self.amount,
76            authority: ctx.accounts.minter.to_account_info(),
77            authority_signer_seeds: None,
78            token_program: ctx.accounts.spl_token_program.to_account_info(),
79        })?;
80
81        Ok(())
82    }
83}