use std::collections::BTreeMap;
pub use anchor_lang::prelude::*;
use mpl_core::types::PluginAuthorityPair;
pub use crate::{errors::CandyGuardError, state::GuardSet};
use crate::{
instructions::{MintAccounts, Route, RouteContext},
state::CandyGuardData,
};
pub use address_gate::AddressGate;
pub use allocation::Allocation;
pub use allow_list::AllowList;
pub use bot_tax::BotTax;
pub use edition::Edition;
pub use end_date::EndDate;
pub use freeze_sol_payment::{FreezeEscrow, FreezeInstruction, FreezeSolPayment};
pub use freeze_token_payment::FreezeTokenPayment;
pub use gatekeeper::Gatekeeper;
pub use mint_limit::{MintCounter, MintLimit};
pub use nft_burn::NftBurn;
pub use nft_gate::NftGate;
pub use nft_mint_limit::NftMintLimit;
pub use nft_payment::NftPayment;
pub use program_gate::ProgramGate;
pub use redeemed_amount::RedeemedAmount;
pub use sol_fixed_fee::SolFixedFee;
pub use sol_payment::SolPayment;
pub use start_date::StartDate;
pub use third_party_signer::ThirdPartySigner;
pub use token2022_payment::Token2022Payment;
pub use token_burn::TokenBurn;
pub use token_gate::TokenGate;
pub use token_payment::TokenPayment;
mod address_gate;
mod allocation;
mod allow_list;
mod bot_tax;
mod edition;
mod end_date;
mod freeze_sol_payment;
mod freeze_token_payment;
mod gatekeeper;
mod mint_limit;
mod nft_burn;
mod nft_gate;
mod nft_mint_limit;
mod nft_payment;
mod program_gate;
mod redeemed_amount;
mod sol_fixed_fee;
mod sol_payment;
mod start_date;
mod third_party_signer;
mod token2022_payment;
mod token_burn;
mod token_gate;
mod token_payment;
pub trait Condition {
fn validate(
&self,
ctx: &mut EvaluationContext,
guard_set: &GuardSet,
mint_args: &[u8],
) -> Result<()>;
fn pre_actions(
&self,
_ctx: &mut EvaluationContext,
_guard_set: &GuardSet,
_mint_args: &[u8],
) -> Result<()> {
Ok(())
}
fn post_actions(
&self,
_ctx: &mut EvaluationContext,
_guard_set: &GuardSet,
_mint_args: &[u8],
) -> Result<()> {
Ok(())
}
}
pub trait Guard: Condition + AnchorSerialize + AnchorDeserialize {
fn size() -> usize;
fn mask() -> u64;
fn instruction<'info>(
_ctx: &Context<'_, '_, '_, 'info, Route<'info>>,
_route_context: RouteContext<'info>,
_data: Vec<u8>,
) -> Result<()> {
err!(CandyGuardError::InstructionNotFound)
}
fn is_enabled(features: u64) -> bool {
features & Self::mask() > 0
}
fn enable(features: u64) -> u64 {
features | Self::mask()
}
fn disable(features: u64) -> u64 {
features & !Self::mask()
}
fn save(&self, data: &mut [u8], offset: usize) -> Result<()> {
let mut result = Vec::with_capacity(Self::size());
self.serialize(&mut result)?;
data[offset..(result.len() + offset)].copy_from_slice(&result[..]);
Ok(())
}
fn load(data: &[u8], offset: usize) -> Result<Option<Self>> {
if offset <= data.len() {
let mut slice = &data[offset - Self::size()..offset];
let guard = Self::deserialize(&mut slice)?;
Ok(Some(guard))
} else {
Ok(None)
}
}
fn verify(_data: &CandyGuardData) -> Result<()> {
Ok(())
}
}
pub struct EvaluationContext<'b, 'c, 'info> {
pub(crate) accounts: MintAccounts<'b, 'c, 'info>,
pub account_cursor: usize,
pub args_cursor: usize,
pub indices: BTreeMap<&'info str, usize>,
pub plugins: Vec<PluginAuthorityPair>,
}
pub fn try_get_account_info<T>(remaining_accounts: &[T], index: usize) -> Result<&T> {
if index < remaining_accounts.len() {
Ok(&remaining_accounts[index])
} else {
err!(CandyGuardError::MissingRemainingAccount)
}
}
pub fn get_account_info<T>(remaining_accounts: &[T], index: usize) -> Option<&T> {
if index < remaining_accounts.len() {
Some(&remaining_accounts[index])
} else {
None
}
}