mpl_candy_guard/guards/
program_gate.rs1use solana_program::{
2 pubkey,
3 serialize_utils::{read_pubkey, read_u16},
4 system_program,
5};
6
7use super::*;
8use crate::{errors::CandyGuardError, state::GuardType, utils::cmp_pubkeys};
9
10pub static DEFAULT_PROGRAMS: &[Pubkey] = &[
12 crate::ID,
13 mpl_candy_machine_core::ID,
14 system_program::ID,
15 spl_token::ID,
16 spl_associated_token_account::ID,
17 pubkey!("ComputeBudget111111111111111111111111111111"),
18 pubkey!("SysExL2WDyJi9aRZrXorrjHJut3JwHQ7R9bTyctbNNG"),
19];
20
21const MAXIMUM_SIZE: usize = 5;
23
24#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)]
27pub struct ProgramGate {
28 pub additional: Vec<Pubkey>,
29}
30
31impl Guard for ProgramGate {
32 fn size() -> usize {
33 4 + (MAXIMUM_SIZE * 32) }
35
36 fn mask() -> u64 {
37 GuardType::as_mask(GuardType::ProgramGate)
38 }
39
40 fn verify(data: &CandyGuardData) -> Result<()> {
41 if let Some(program_gate) = &data.default.program_gate {
42 if program_gate.additional.len() > MAXIMUM_SIZE {
43 return err!(CandyGuardError::ExceededProgramListSize);
44 }
45 }
46
47 if let Some(groups) = &data.groups {
48 for group in groups {
49 if let Some(program_gate) = &group.guards.program_gate {
50 if program_gate.additional.len() > MAXIMUM_SIZE {
51 return err!(CandyGuardError::ExceededProgramListSize);
52 }
53 }
54 }
55 }
56
57 Ok(())
58 }
59}
60
61impl Condition for ProgramGate {
62 fn validate<'info>(
63 &self,
64 ctx: &mut EvaluationContext,
65 _guard_set: &GuardSet,
66 _mint_args: &[u8],
67 ) -> Result<()> {
68 let ix_sysvar_account = &ctx.accounts.sysvar_instructions;
69 let ix_sysvar_account_info = ix_sysvar_account.to_account_info();
70
71 let mut programs: Vec<Pubkey> =
72 Vec::with_capacity(DEFAULT_PROGRAMS.len() + self.additional.len());
73 programs.extend(DEFAULT_PROGRAMS);
74 programs.extend(&self.additional);
75
76 verify_programs(&ix_sysvar_account_info, &programs)
77 }
78}
79
80pub fn verify_programs(sysvar: &AccountInfo, programs: &[Pubkey]) -> Result<()> {
81 let sysvar_data = sysvar.data.borrow();
82
83 let mut index = 0;
84 let num_instructions =
86 read_u16(&mut index, &sysvar_data).map_err(|_| ProgramError::InvalidAccountData)?;
87
88 'outer: for index in 0..num_instructions {
89 let mut offset = 2 + (index * 2) as usize;
90
91 offset = read_u16(&mut offset, &sysvar_data).unwrap() as usize;
93 let num_accounts = read_u16(&mut offset, &sysvar_data).unwrap();
94
95 offset += (num_accounts as usize) * (1 + 32);
97 let program_id = read_pubkey(&mut offset, &sysvar_data).unwrap();
98
99 for program in programs {
100 if cmp_pubkeys(&program_id, program) {
101 continue 'outer;
102 }
103 }
104
105 msg!("Transaction had ix with program id {}", program_id);
106 return err!(CandyGuardError::UnauthorizedProgramFound);
109 }
110
111 Ok(())
112}