diff --git a/clients/js/test/createCollection.test.ts b/clients/js/test/createCollection.test.ts index ab1385ae..4a0e6567 100644 --- a/clients/js/test/createCollection.test.ts +++ b/clients/js/test/createCollection.test.ts @@ -104,6 +104,7 @@ test('it can create a new asset with a collection', async (t) => { assetAddress, name: 'Test Bread', uri: 'https://example.com/bread', + collection: collectionAddress.publicKey, plugins: [{ __kind: 'Collection', fields: [{ collectionAddress: collectionAddress.publicKey, @@ -145,4 +146,70 @@ test('it can create a new asset with a collection', async (t) => { }, ], }); +}); + +test('it cannot create a new asset with a collection if it is not the collection auth', async (t) => { + // Given a Umi instance and a new signer. + const umi = await createUmi(); + const collectionAddress = generateSigner(umi); + const assetAddress = generateSigner(umi); + const collectionAuth = generateSigner(umi); + + // When we create a new account. + await createCollection(umi, { + collectionAddress, + updateAuthority: collectionAuth.publicKey, + name: 'Test Bread Collection', + uri: 'https://example.com/bread', + plugins: [{ __kind: 'Freeze', fields: [{ frozen: false }] }] + }).sendAndConfirm(umi); + + const collection = await fetchCollectionWithPlugins(umi, collectionAddress.publicKey); + // console.log("Account State:", collection); + t.like(collection, { + publicKey: collectionAddress.publicKey, + updateAuthority: collectionAuth.publicKey, + name: 'Test Bread Collection', + uri: 'https://example.com/bread', + pluginHeader: { + key: 3, + pluginRegistryOffset: BigInt(106), + }, + pluginRegistry: { + key: 4, + registry: [ + { + pluginType: 2, + offset: BigInt(104), + authorities: [{ __kind: 'Owner' }], + }, + ], + }, + plugins: [ + { + authorities: [{ __kind: 'Owner' }], + plugin: { + __kind: 'Freeze', + fields: [{ frozen: false }], + }, + }, + ], + }); + + // When we create a new account. + const result = create(umi, { + dataState: DataState.AccountState, + assetAddress, + name: 'Test Bread', + uri: 'https://example.com/bread', + collection: collectionAddress.publicKey, + plugins: [{ + __kind: 'Collection', fields: [{ + collectionAddress: collectionAddress.publicKey, + managed: true + }] + }], + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: "InvalidAuthority" }); }); \ No newline at end of file diff --git a/programs/mpl-core/src/plugins/collection.rs b/programs/mpl-core/src/plugins/collection.rs index 252d2cf5..7e91fc09 100644 --- a/programs/mpl-core/src/plugins/collection.rs +++ b/programs/mpl-core/src/plugins/collection.rs @@ -1,4 +1,5 @@ use borsh::{BorshDeserialize, BorshSerialize}; +use mpl_utils::assert_signer; use solana_program::pubkey::Pubkey; use crate::{ @@ -44,22 +45,24 @@ impl PluginValidation for Collection { match ctx.collection { Some(collection) => { let collection = CollectionData::load(collection, 0)?; - if ctx.payer.is_signer - || (ctx.update_authority.is_some() && ctx.update_authority.unwrap().is_signer) - { - if collection.update_authority != *ctx.payer.key { - return Ok(ValidationResult::Rejected); - } - } else { + solana_program::msg!("Collection: {:?}", collection); + // Check that the collection update authority is a signer. + let authority = match ctx.update_authority { + Some(authority) => authority, + None => ctx.payer, + }; + + assert_signer(authority)?; + + if authority.key != &collection.update_authority { return Ok(ValidationResult::Rejected); } + Ok(ValidationResult::Pass) } None => { - if self.managed { - return Ok(ValidationResult::Rejected); - } - Ok(ValidationResult::Pass) + solana_program::msg!("No collection provided"); + Ok(ValidationResult::Rejected) } } } diff --git a/programs/mpl-core/src/processor/create.rs b/programs/mpl-core/src/processor/create.rs index 7550d77c..0f3e5d2d 100644 --- a/programs/mpl-core/src/processor/create.rs +++ b/programs/mpl-core/src/processor/create.rs @@ -123,7 +123,7 @@ pub(crate) fn create<'a>(accounts: &'a [AccountInfo<'a>], args: CreateArgs) -> P if let Some(plugin_registry) = plugin_registry { for record in plugin_registry.registry { if matches!( - record.plugin_type.check_transfer(), + record.plugin_type.check_create(), CheckResult::CanApprove | CheckResult::CanReject ) { let result = Plugin::load(ctx.accounts.asset_address, record.offset)?