diff --git a/clients/js/test/removeAuthority.test.ts b/clients/js/test/removeAuthority.test.ts index bd621a4c..7c9d784f 100644 --- a/clients/js/test/removeAuthority.test.ts +++ b/clients/js/test/removeAuthority.test.ts @@ -1,6 +1,7 @@ import { generateSigner } from '@metaplex-foundation/umi'; import test from 'ava'; // import { base58 } from '@metaplex-foundation/umi/serializers'; +import { generateSignerWithSol } from '@metaplex-foundation/umi-bundle-tests'; import { Asset, AssetWithPlugins, @@ -11,6 +12,7 @@ import { create, fetchAsset, fetchAssetWithPlugins, + plugin, removeAuthority, updateAuthority, } from '../src'; @@ -217,3 +219,84 @@ test('it can remove the default authority from a plugin to make it immutable', a ], }); }); + +test('it can remove a pubkey authority from a plugin if that pubkey is the signer authority', async (t) => { + // Given a Umi instance and a new signer. + const umi = await createUmi(); + const assetAddress = generateSigner(umi); + const pubkeyAuth = await generateSignerWithSol(umi); + + // When we create a new account. + await create(umi, { + dataState: DataState.AccountState, + assetAddress, + name: 'Test Bread', + uri: 'https://example.com/bread', + plugins: [], + }).sendAndConfirm(umi); + + await addPlugin(umi, { + assetAddress: assetAddress.publicKey, + plugin: plugin('Freeze', [{ frozen: false }]), + }).sendAndConfirm(umi); + + await addAuthority(umi, { + assetAddress: assetAddress.publicKey, + pluginType: PluginType.Freeze, + newAuthority: { + __kind: 'Pubkey', + address: pubkeyAuth.publicKey, + }, + }).sendAndConfirm(umi); + + const asset1 = await fetchAssetWithPlugins(umi, assetAddress.publicKey); + // console.log(JSON.stringify(asset1, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2)); + t.like(asset1, { + publicKey: assetAddress.publicKey, + updateAuthority: updateAuthority('Address', [umi.identity.publicKey]), + owner: umi.identity.publicKey, + name: 'Test Bread', + uri: 'https://example.com/bread', + plugins: [ + { + authorities: [{ __kind: 'Owner' }, { __kind: 'Pubkey', address: pubkeyAuth.publicKey }], + plugin: { + __kind: 'Freeze', + fields: [{ frozen: false }], + }, + }, + ], + }); + + const umi2 = await createUmi(); + + await removeAuthority(umi2, { + payer: umi2.identity, + assetAddress: assetAddress.publicKey, + authority: pubkeyAuth, + pluginType: PluginType.Freeze, + authorityToRemove: { + __kind: 'Pubkey', + address: pubkeyAuth.publicKey, + }, + }).sendAndConfirm(umi); + + const asset2 = await fetchAssetWithPlugins(umi, assetAddress.publicKey); + // console.log(JSON.stringify(asset1, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2)); + t.like(asset2, { + publicKey: assetAddress.publicKey, + updateAuthority: updateAuthority('Address', [umi.identity.publicKey]), + owner: umi.identity.publicKey, + name: 'Test Bread', + uri: 'https://example.com/bread', + plugins: [ + { + authorities: [{ __kind: 'Owner' }], + plugin: { + __kind: 'Freeze', + fields: [{ frozen: false }], + }, + }, + ], + }); +}); diff --git a/programs/mpl-core/src/plugins/utils.rs b/programs/mpl-core/src/plugins/utils.rs index d3ecfe65..a1a70ede 100644 --- a/programs/mpl-core/src/plugins/utils.rs +++ b/programs/mpl-core/src/plugins/utils.rs @@ -355,7 +355,13 @@ pub fn remove_authority_from_plugin<'a>( .ok_or(MplCoreError::PluginNotFound)?; let resolved_authority = resolve_authority_to_default(asset, authority); - if resolved_authority != registry_record.authorities[0] { + + // TODO inspect this logic + if resolved_authority != registry_record.authorities[0] + && ( // pubkey authorities can remove themselves if they are a signer + Authority::Pubkey { address: authority.key.clone() } == authority_to_remove.clone() && + !registry_record.authorities.contains(authority_to_remove) + ) { return Err(MplCoreError::InvalidAuthority.into()); }