diff --git a/clients/js/src/generated/instructions/setAndVerifySizedCollectionItem.ts b/clients/js/src/generated/instructions/setAndVerifySizedCollectionItem.ts index 7486a1d2..e29d0430 100644 --- a/clients/js/src/generated/instructions/setAndVerifySizedCollectionItem.ts +++ b/clients/js/src/generated/instructions/setAndVerifySizedCollectionItem.ts @@ -106,7 +106,7 @@ export function setAndVerifySizedCollectionItem( collection: { index: 5, isWritable: true, value: input.collection ?? null }, collectionMasterEditionAccount: { index: 6, - isWritable: true, + isWritable: false, value: input.collectionMasterEditionAccount ?? null, }, collectionAuthorityRecord: { diff --git a/clients/rust/src/generated/instructions/set_and_verify_sized_collection_item.rs b/clients/rust/src/generated/instructions/set_and_verify_sized_collection_item.rs index 30fbac6e..59d7857b 100644 --- a/clients/rust/src/generated/instructions/set_and_verify_sized_collection_item.rs +++ b/clients/rust/src/generated/instructions/set_and_verify_sized_collection_item.rs @@ -61,7 +61,7 @@ impl SetAndVerifySizedCollectionItem { self.collection, false, )); - accounts.push(solana_program::instruction::AccountMeta::new( + accounts.push(solana_program::instruction::AccountMeta::new_readonly( self.collection_master_edition_account, false, )); @@ -333,7 +333,7 @@ impl<'a, 'b> SetAndVerifySizedCollectionItemCpi<'a, 'b> { *self.collection.key, false, )); - accounts.push(solana_program::instruction::AccountMeta::new( + accounts.push(solana_program::instruction::AccountMeta::new_readonly( *self.collection_master_edition_account.key, false, )); diff --git a/clients/rust/src/utils.rs b/clients/rust/src/utils.rs index 27ef0a5b..7d727ed2 100644 --- a/clients/rust/src/utils.rs +++ b/clients/rust/src/utils.rs @@ -1,4 +1,43 @@ +use borsh::BorshDeserialize; + +use crate::{ + errors::MplTokenMetadataError, + types::{Key, TokenStandard}, +}; + +/// The offset of the token standard byte in the master edition +/// from the end of the account data. +const TOKEN_STANDARD_OFFSET: usize = 1; + /// Removes all null bytes from a string. pub fn clean(value: String) -> String { value.replace('\0', "") } + +/// Checks that the `master_edition` is Programmable NFT master edition. +pub fn assert_edition_is_programmable(edition_data: &[u8]) -> Result<(), MplTokenMetadataError> { + if edition_data.len() > TOKEN_STANDARD_OFFSET { + // the first byte is the account key + let key = Key::deserialize(&mut &edition_data[0..1]) + .map_err(|_error| MplTokenMetadataError::InvalidEditionKey)?; + + return match key { + Key::MasterEditionV1 | Key::MasterEditionV2 => { + // the last byte is the token standard + let standard = TokenStandard::deserialize( + &mut &edition_data[edition_data.len() - TOKEN_STANDARD_OFFSET..], + ) + .map_err(|_error| MplTokenMetadataError::InvalidTokenStandard)?; + + return match standard { + TokenStandard::ProgrammableNonFungible + | TokenStandard::ProgrammableNonFungibleEdition => Ok(()), + _ => Err(MplTokenMetadataError::InvalidTokenStandard), + }; + } + _ => Err(MplTokenMetadataError::InvalidEditionKey), + }; + } + + Err(MplTokenMetadataError::InvalidMasterEditionAccountLength) +} diff --git a/idls/token_metadata.json b/idls/token_metadata.json index 00dff659..8ce75658 100644 --- a/idls/token_metadata.json +++ b/idls/token_metadata.json @@ -2288,7 +2288,7 @@ }, { "name": "collectionMasterEditionAccount", - "isMut": true, + "isMut": false, "isSigner": false, "docs": [ "MasterEdition2 Account of the Collection Token" diff --git a/programs/token-metadata/program/src/instruction/mod.rs b/programs/token-metadata/program/src/instruction/mod.rs index 63f65a0d..413f8ba2 100644 --- a/programs/token-metadata/program/src/instruction/mod.rs +++ b/programs/token-metadata/program/src/instruction/mod.rs @@ -431,7 +431,7 @@ pub enum MetadataInstruction { #[account(3, name="update_authority", desc="Update Authority of Collection NFT and NFT")] #[account(4, name="collection_mint", desc="Mint of the Collection")] #[account(5, writable, name="collection", desc="Metadata Account of the Collection")] - #[account(6, writable, name="collection_master_edition_account", desc="MasterEdition2 Account of the Collection Token")] + #[account(6, name="collection_master_edition_account", desc="MasterEdition2 Account of the Collection Token")] #[account(7, optional, name="collection_authority_record", desc="Collection Authority Record PDA")] #[legacy_optional_accounts_strategy] SetAndVerifySizedCollectionItem,