diff --git a/Cargo.lock b/Cargo.lock index 4eed851..1f59716 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -325,6 +325,7 @@ dependencies = [ "flatbuffers", "lazy_static", "mpl-bubblegum", + "mpl-candy-guard", "mpl-candy-machine-core", "mpl-token-metadata", "plerkle_serialization", @@ -942,6 +943,32 @@ dependencies = [ "spl-token", ] +[[package]] +name = "mpl-candy-guard" +version = "0.0.1" +source = "git+https://github.com/metaplex-foundation/candy-guard?branch=danenbm/expose-mint-counter#360f82db68a5433703f3a8deca7ff5afaecf7abe" +dependencies = [ + "anchor-lang", + "anchor-spl", + "arrayref", + "mpl-candy-guard-derive", + "mpl-candy-machine-core", + "mpl-token-metadata", + "solana-gateway", + "solana-program", + "spl-associated-token-account", + "spl-token", +] + +[[package]] +name = "mpl-candy-guard-derive" +version = "0.0.1" +source = "git+https://github.com/metaplex-foundation/candy-guard?branch=danenbm/expose-mint-counter#360f82db68a5433703f3a8deca7ff5afaecf7abe" +dependencies = [ + "quote", + "syn", +] + [[package]] name = "mpl-candy-machine-core" version = "0.0.2" @@ -1467,6 +1494,19 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" +[[package]] +name = "sol-did" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2546d424d6898908c205d99d3af07ad42e2e8aec8f0d459235dc0bd4e9866fe" +dependencies = [ + "borsh", + "num-derive", + "num-traits", + "solana-program", + "thiserror", +] + [[package]] name = "solana-frozen-abi" version = "1.10.38" @@ -1501,6 +1541,21 @@ dependencies = [ "syn", ] +[[package]] +name = "solana-gateway" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "243daaf437dff89891d520c3e9be7b4a6940c30a1bda2ac094e621046f303eda" +dependencies = [ + "bitflags", + "borsh", + "num-derive", + "num-traits", + "sol-did", + "solana-program", + "thiserror", +] + [[package]] name = "solana-logger" version = "1.10.38" diff --git a/blockbuster/Cargo.toml b/blockbuster/Cargo.toml index 6f60106..67d6573 100644 --- a/blockbuster/Cargo.toml +++ b/blockbuster/Cargo.toml @@ -11,6 +11,7 @@ readme = "../README.md" [dependencies] spl-account-compression = { version = "0.1.0", features = ["no-entrypoint"] } spl-noop = { version = "0.1.0", features = ["no-entrypoint"] } +mpl-candy-guard = { git = "https://github.com/metaplex-foundation/candy-guard", branch = "danenbm/expose-mint-counter", features = ["no-entrypoint"] } mpl-candy-machine-core = { git = "https://github.com/metaplex-foundation/metaplex-program-library", branch = "febo/candy-machine-core", features = ["no-entrypoint"] } mpl-bubblegum = { version = "0.1.0", features = ["no-entrypoint"] } mpl-token-metadata = { version = "1.3.6", features = ["no-entrypoint"] } diff --git a/blockbuster/src/error.rs b/blockbuster/src/error.rs index d13009f..765efb9 100644 --- a/blockbuster/src/error.rs +++ b/blockbuster/src/error.rs @@ -19,6 +19,8 @@ pub enum BlockbusterError { FailedToDeserializeToMasterEdition, #[error("Uninitialized account type")] UninitializedAccount, + #[error("Could not custom deserialize candy guards")] + CandyGuardDataCustomDeserError, } impl From for BlockbusterError { diff --git a/blockbuster/src/programs/candy_guard/mod.rs b/blockbuster/src/programs/candy_guard/mod.rs new file mode 100644 index 0000000..48e2511 --- /dev/null +++ b/blockbuster/src/programs/candy_guard/mod.rs @@ -0,0 +1,82 @@ +use crate::{ + error::BlockbusterError, + instruction::InstructionBundle, + program_handler::{NotUsed, ParseResult, ProgramParser}, + programs::ProgramParseResult, +}; +use borsh::BorshDeserialize; +use mpl_candy_guard::{ + guards::MintCounter, + state::{CandyGuard, CandyGuardData, DATA_OFFSET}, +}; +use plerkle_serialization::AccountInfo; +use solana_sdk::{pubkey::Pubkey, pubkeys}; +use std::convert::TryInto; + +pubkeys!( + candy_guard_id, + "CnDYGRdU51FsSyLnVgSd19MCFxA4YHT5h3nacvCKMPUJ" +); + +// Anchor account discriminators. +const CANDY_GUARD_DISCRIMINATOR: [u8; 8] = [44, 207, 199, 184, 112, 103, 34, 181]; +const MINT_COUNTER_DISCRIMINATOR: [u8; 8] = [29, 59, 15, 69, 46, 22, 227, 173]; + +pub enum CandyGuardAccountData { + CandyGuard(CandyGuard, CandyGuardData), + MintCounter(MintCounter), +} + +impl ParseResult for CandyGuardAccountData { + fn result_type(&self) -> ProgramParseResult { + ProgramParseResult::CandyGuard(self) + } +} + +pub struct CandyGuardParser; + +impl ProgramParser for CandyGuardParser { + fn key(&self) -> Pubkey { + candy_guard_id() + } + + fn key_match(&self, key: &Pubkey) -> bool { + key == &candy_guard_id() + } + + fn handle_account( + &self, + account_info: &AccountInfo, + ) -> Result, BlockbusterError> { + let account_data = if let Some(account_info) = account_info.data() { + account_info + } else { + return Err(BlockbusterError::DeserializationError); + }; + + let discriminator: [u8; 8] = account_data[0..8].try_into().unwrap(); + + let account_type = match discriminator { + CANDY_GUARD_DISCRIMINATOR => { + let candy_guard = CandyGuard::try_from_slice(&account_data[8..])?; + let candy_guard_data = CandyGuardData::load(&account_data[DATA_OFFSET..]) + .map_err(|_| BlockbusterError::CandyGuardDataCustomDeserError)?; + CandyGuardAccountData::CandyGuard(candy_guard, candy_guard_data) + } + MINT_COUNTER_DISCRIMINATOR => { + let mint_counter = MintCounter::try_from_slice(&account_data[8..])?; + CandyGuardAccountData::MintCounter(mint_counter) + } + _ => return Err(BlockbusterError::UnknownAccountDiscriminator), + }; + + Ok(Box::new(account_type)) + } + + fn handle_instruction( + &self, + _bundle: &InstructionBundle, + ) -> Result, BlockbusterError> { + Ok(Box::new(NotUsed::new())) + } +} diff --git a/blockbuster/src/programs/mod.rs b/blockbuster/src/programs/mod.rs index 9aea3fa..16e8bc1 100644 --- a/blockbuster/src/programs/mod.rs +++ b/blockbuster/src/programs/mod.rs @@ -1,10 +1,12 @@ use bubblegum::BubblegumInstruction; +use candy_guard::CandyGuardAccountData; use candy_machine::CandyMachineAccountData; use candy_machine_core::CandyMachineCoreAccountData; use token_account::TokenProgramAccount; use token_metadata::TokenMetadataAccountState; pub mod bubblegum; +pub mod candy_guard; pub mod candy_machine; pub mod candy_machine_core; pub mod token_account; @@ -15,6 +17,7 @@ pub enum ProgramParseResult<'a> { Bubblegum(&'a BubblegumInstruction), TokenMetadata(&'a TokenMetadataAccountState), TokenProgramAccount(&'a TokenProgramAccount), + CandyGuard(&'a CandyGuardAccountData), CandyMachine(&'a CandyMachineAccountData), CandyMachineCore(&'a CandyMachineCoreAccountData), Unknown,