1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
use super::*;

use crate::{state::GuardType, utils::*};

/// Guard that restricts access to addresses that hold the specified spl-token.
///
/// List of accounts required:
///
///   0. `[]` Token account holding the required amount.
#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)]
pub struct TokenGate {
    pub amount: u64,
    pub mint: Pubkey,
}

impl Guard for TokenGate {
    fn size() -> usize {
        8    // amount
        + 32 // mint
    }

    fn mask() -> u64 {
        GuardType::as_mask(GuardType::TokenGate)
    }
}

impl Condition for TokenGate {
    fn validate<'info>(
        &self,
        ctx: &mut EvaluationContext,
        _guard_set: &GuardSet,
        _mint_args: &[u8],
    ) -> Result<()> {
        // retrieves the (potential) token gate account
        let token_gate_index = ctx.account_cursor;
        let token_gate_account = try_get_account_info(ctx.accounts.remaining, token_gate_index)?;
        // consumes the gate token account
        ctx.account_cursor += 1;

        let account = assert_is_ata(token_gate_account, &ctx.accounts.minter.key(), &self.mint)?;

        if account.amount < self.amount {
            return err!(CandyGuardError::NotEnoughTokens);
        }

        Ok(())
    }
}