use { crate::{MessageBufferError, MESSAGE, WHITELIST}, anchor_lang::prelude::*, }; // Note: purposely not making this zero_copy // otherwise whitelist must always be marked mutable // and majority of operations are read #[account] #[derive(InitSpace)] pub struct Whitelist { pub bump: u8, pub admin: Pubkey, // This is used by the `#[derive(InitSpace)]` // to determine initial account size #[max_len(32)] pub allowed_programs: Vec, } impl Whitelist { pub fn validate_programs(&self, allowed_programs: &[Pubkey]) -> Result<()> { require!( !self.allowed_programs.contains(&Pubkey::default()), MessageBufferError::InvalidAllowedProgram ); require_gte!( 32, allowed_programs.len(), MessageBufferError::MaximumAllowedProgramsExceeded ); Ok(()) } pub fn validate_new_admin(&self, new_admin: Pubkey) -> Result<()> { require_keys_neq!(new_admin, Pubkey::default()); Ok(()) } pub fn is_allowed_program_auth(&self, auth: &Pubkey) -> Result<()> { require!( self.allowed_programs.contains(auth), MessageBufferError::CallerNotAllowed ); Ok(()) } } #[derive(Accounts)] pub struct WhitelistVerifier<'info> { #[account( seeds = [MESSAGE.as_bytes(), WHITELIST.as_bytes()], bump = whitelist.bump, )] // Using a Box to move account from stack to heap pub whitelist: Box>, /// PDA representing authorized cpi caller pub cpi_caller_auth: Signer<'info>, } impl<'info> WhitelistVerifier<'info> { pub fn is_allowed(&self) -> Result<()> { let auth = self.cpi_caller_auth.key(); let whitelist = &self.whitelist; whitelist.is_allowed_program_auth(&auth)?; Ok(()) } }