From 46ad5572d2bf44e0fe2c6ffe5cf8ce88c92952cb Mon Sep 17 00:00:00 2001 From: Blockiosaurus Date: Wed, 11 Sep 2024 22:31:50 -0400 Subject: [PATCH] Fixing outstanding size issues with CM. --- .../processor/collection/remove_collection.rs | 16 +++++++----- .../processor/collection/set_collection.rs | 18 +++++++------ .../collection/set_collection_during_mint.rs | 10 ++++--- candy-machine/program/src/utils.rs | 26 +++++++++++++++++++ .../program/tests/utils/candy_manager.rs | 2 +- 5 files changed, 54 insertions(+), 18 deletions(-) diff --git a/candy-machine/program/src/processor/collection/remove_collection.rs b/candy-machine/program/src/processor/collection/remove_collection.rs index 138fc64835..a5cd7d0443 100644 --- a/candy-machine/program/src/processor/collection/remove_collection.rs +++ b/candy-machine/program/src/processor/collection/remove_collection.rs @@ -1,5 +1,7 @@ use anchor_lang::prelude::*; -use mpl_token_metadata::{instruction::revoke_collection_authority, state::Metadata}; +use mpl_token_metadata::{ + assertions::metadata, instruction::revoke_collection_authority, state::Metadata, +}; use solana_program::program::invoke; use crate::{ @@ -32,11 +34,13 @@ pub fn handle_remove_collection(ctx: Context) -> Result<()> { let candy_machine = &mut ctx.accounts.candy_machine; candy_machine.assert_not_minted(error!(CandyError::NoChangingCollectionDuringMint))?; - let data = &ctx.accounts.metadata.data.borrow_mut(); - if data.is_empty() || data[0] != mpl_token_metadata::state::Key::MetadataV1 as u8 { - return Err(CandyError::InvalidMetadataAccount.into()); - } - let metadata = Metadata::deserialize(&mut data.as_ref())?; + let metadata = { + let data = &ctx.accounts.metadata.data.borrow_mut(); + if data.is_empty() || data[0] != mpl_token_metadata::state::Key::MetadataV1 as u8 { + return Err(CandyError::InvalidMetadataAccount.into()); + } + Metadata::deserialize(&mut data.as_ref())? + }; if !cmp_pubkeys(&metadata.update_authority, &ctx.accounts.authority.key()) { return err!(CandyError::IncorrectCollectionAuthority); }; diff --git a/candy-machine/program/src/processor/collection/set_collection.rs b/candy-machine/program/src/processor/collection/set_collection.rs index 59675a1a4f..a533e3af2f 100644 --- a/candy-machine/program/src/processor/collection/set_collection.rs +++ b/candy-machine/program/src/processor/collection/set_collection.rs @@ -1,12 +1,12 @@ use anchor_lang::prelude::*; use mpl_token_metadata::{ - assertions::collection::assert_master_edition, instruction::approve_collection_authority, - state::Metadata, utils::create_or_allocate_account_raw, + instruction::approve_collection_authority, state::Metadata, + utils::create_or_allocate_account_raw, }; use solana_program::program::invoke; use crate::{ - cmp_pubkeys, + assert_master_edition, cmp_pubkeys, constants::{COLLECTIONS_FEATURE_INDEX, COLLECTION_PDA_SIZE}, set_feature_flag, CandyError, CandyMachine, CollectionPDA, }; @@ -40,11 +40,13 @@ pub struct SetCollection<'info> { pub fn handle_set_collection(ctx: Context) -> Result<()> { let mint = ctx.accounts.mint.to_account_info(); - let data = &ctx.accounts.metadata.data.borrow_mut(); - if data.is_empty() || data[0] != mpl_token_metadata::state::Key::MetadataV1 as u8 { - return Err(CandyError::InvalidMetadataAccount.into()); - } - let metadata = Metadata::deserialize(&mut data.as_ref())?; + let metadata = { + let data = &ctx.accounts.metadata.data.borrow_mut(); + if data.is_empty() || data[0] != mpl_token_metadata::state::Key::MetadataV1 as u8 { + return Err(CandyError::InvalidMetadataAccount.into()); + } + Metadata::deserialize(&mut data.as_ref())? + }; if !cmp_pubkeys(&metadata.update_authority, &ctx.accounts.authority.key()) { return err!(CandyError::IncorrectCollectionAuthority); } diff --git a/candy-machine/program/src/processor/collection/set_collection_during_mint.rs b/candy-machine/program/src/processor/collection/set_collection_during_mint.rs index 0d311d0fe3..4a670b69be 100644 --- a/candy-machine/program/src/processor/collection/set_collection_during_mint.rs +++ b/candy-machine/program/src/processor/collection/set_collection_during_mint.rs @@ -108,9 +108,13 @@ pub fn handle_set_collection_during_mint(ctx: Context) return Ok(()); } - let collection_metadata: Metadata = - Metadata::safe_deserialize(&ctx.accounts.collection_metadata.data.borrow_mut())?; - + let collection_metadata: Metadata = { + let data = ctx.accounts.collection_metadata.data.borrow_mut(); + if data.is_empty() || data[0] != mpl_token_metadata::state::Key::MetadataV1 as u8 { + return err!(CandyError::InvalidMetadataAccount); + } + Metadata::deserialize(&mut data.as_ref())? + }; let collection_instruction = if collection_metadata.collection_details.is_some() { if !ctx.accounts.collection_metadata.is_writable { return err!(CandyError::SizedCollectionMetadataMustBeMutable); diff --git a/candy-machine/program/src/utils.rs b/candy-machine/program/src/utils.rs index 4e08827983..a14ecc6c2d 100644 --- a/candy-machine/program/src/utils.rs +++ b/candy-machine/program/src/utils.rs @@ -1,4 +1,8 @@ use anchor_lang::prelude::*; +use mpl_token_metadata::{ + error::MetadataError, + state::{MasterEditionV2, Metadata, TokenStandard}, +}; use solana_program::{ account_info::AccountInfo, clock::Clock, @@ -234,6 +238,28 @@ pub fn punish_bots<'a>( Ok(()) } +pub fn assert_master_edition( + collection_data: &Metadata, + edition_account_info: &AccountInfo, +) -> core::result::Result<(), ProgramError> { + let data = edition_account_info.try_borrow_data()?; + if data.is_empty() || data[0] != mpl_token_metadata::state::Key::MasterEditionV2 as u8 { + return Err(MetadataError::DataTypeMismatch.into()); + } + let edition = MasterEditionV2::deserialize(&mut data.as_ref()) + .map_err(|_err: std::io::Error| MetadataError::CollectionMustBeAUniqueMasterEdition)?; + + match collection_data.token_standard { + Some(TokenStandard::NonFungible) | Some(TokenStandard::ProgrammableNonFungible) => (), + _ => return Err(MetadataError::CollectionMustBeAUniqueMasterEdition.into()), + } + + if edition.max_supply != Some(0) { + return Err(MetadataError::CollectionMustBeAUniqueMasterEdition.into()); + } + Ok(()) +} + #[cfg(test)] pub mod tests { use std::{assert_eq, println}; diff --git a/candy-machine/program/tests/utils/candy_manager.rs b/candy-machine/program/tests/utils/candy_manager.rs index b819821318..ab6da87f4d 100644 --- a/candy-machine/program/tests/utils/candy_manager.rs +++ b/candy-machine/program/tests/utils/candy_manager.rs @@ -1028,7 +1028,7 @@ impl CandyManager { } let sol_fees = { - let mut fees = 5000 + 5616720 + 2853600 + 10000000; + let mut fees = 5000 + 5115600 + 1030080 + 10000000; if self.freeze_info.set { let freeze_pda = self.get_freeze_pda(context).await; fees += freeze_pda.freeze_fee;