Skip to content

Commit

Permalink
allow collection update auth to use transfer delegate, update tests (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
nhanphan authored Jun 11, 2024
1 parent 0f3e905 commit 43a4419
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 47 deletions.
16 changes: 16 additions & 0 deletions clients/js/src/plugins/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ export function formPluginHeaderV1(
};
}

/**
* @deprecated Use the new 1.0 sdk instruction helpers like `create` instead of `createV1` which no longer require sub create functions like this.
* @param args
* @returns
*/
export function createPlugin(args: CreatePluginArgs): BasePlugin {
// TODO refactor when there are more required empty fields in plugins
if (args.type === 'UpdateDelegate') {
Expand All @@ -53,6 +58,12 @@ export function createPlugin(args: CreatePluginArgs): BasePlugin {
fields: [(args as any).data || {}],
};
}

/**
* @deprecated Use the new 1.0 sdk instruction helpers like `create` instead of `createV1` which no longer require sub create functions like this.
* @param args
* @returns
*/
export function pluginAuthorityPair(
args: PluginAuthorityPairHelperArgs
): PluginAuthorityPair {
Expand Down Expand Up @@ -98,6 +109,11 @@ export function createPluginV2(args: AssetAllPluginArgsV2): BasePlugin {
};
}

/**
* @deprecated Use the new 1.0 sdk instruction helpers like `create` instead of `createV1` which no longer require sub create functions like this.
* @param args
* @returns
*/
export function pluginAuthorityPairV2({
type,
authority,
Expand Down
121 changes: 82 additions & 39 deletions clients/js/test/plugins/asset/delegateTransfer.test.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,35 @@
import { generateSigner } from '@metaplex-foundation/umi';
import test from 'ava';
import {
PluginType,
approvePluginAuthorityV1,
transferV1,
pluginAuthorityPair,
revokePluginAuthorityV1,
addressPluginAuthority,
approvePluginAuthority,
transfer,
revokePluginAuthority,
} from '../../../src';
import {
DEFAULT_ASSET,
assertAsset,
createAsset,
createUmi,
} from '../../_setupRaw';
import { DEFAULT_ASSET, assertAsset, createUmi } from '../../_setupRaw';
import { createAsset, createAssetWithCollection } from '../../_setupSdk';

test('a delegate can transfer the asset', async (t) => {
// Given a Umi instance and a new signer.
const umi = await createUmi();
const delegateAddress = generateSigner(umi);
const newOwnerAddress = generateSigner(umi);

const asset = await createAsset(umi, {
plugins: [pluginAuthorityPair({ type: 'TransferDelegate' })],
plugins: [{ type: 'TransferDelegate' }],
});

await approvePluginAuthorityV1(umi, {
await approvePluginAuthority(umi, {
asset: asset.publicKey,
pluginType: PluginType.TransferDelegate,
newAuthority: addressPluginAuthority(delegateAddress.publicKey),
plugin: {
type: 'TransferDelegate',
},
newAuthority: {
type: 'Address',
address: delegateAddress.publicKey,
},
}).sendAndConfirm(umi);

await transferV1(umi, {
asset: asset.publicKey,
await transfer(umi, {
asset,
newOwner: newOwnerAddress.publicKey,
authority: delegateAddress,
}).sendAndConfirm(umi);
Expand All @@ -51,22 +48,24 @@ test('a delegate can transfer the asset', async (t) => {
});

test('owner can transfer asset with delegate transfer', async (t) => {
// Given a Umi instance and a new signer.
const umi = await createUmi();
const delegateAddress = generateSigner(umi);
const newOwnerAddress = generateSigner(umi);

const asset = await createAsset(umi, {
plugins: [
pluginAuthorityPair({
{
type: 'TransferDelegate',
authority: addressPluginAuthority(delegateAddress.publicKey),
}),
authority: {
type: 'Address',
address: delegateAddress.publicKey,
},
},
],
});

await transferV1(umi, {
asset: asset.publicKey,
await transfer(umi, {
asset,
newOwner: newOwnerAddress.publicKey,
}).sendAndConfirm(umi);

Expand All @@ -84,22 +83,26 @@ test('owner can transfer asset with delegate transfer', async (t) => {
});

test('it can revoke a delegate transfer plugin', async (t) => {
// Given a Umi instance and a new signer.
const umi = await createUmi();
const delegateAddress = generateSigner(umi);

const asset = await createAsset(umi, {
plugins: [
pluginAuthorityPair({
{
type: 'TransferDelegate',
authority: addressPluginAuthority(delegateAddress.publicKey),
}),
authority: {
type: 'Address',
address: delegateAddress.publicKey,
},
},
],
});

await revokePluginAuthorityV1(umi, {
await revokePluginAuthority(umi, {
asset: asset.publicKey,
pluginType: PluginType.TransferDelegate,
plugin: {
type: 'TransferDelegate',
},
}).sendAndConfirm(umi);

await assertAsset(t, umi, {
Expand All @@ -116,27 +119,31 @@ test('it can revoke a delegate transfer plugin', async (t) => {
});

test('it cannot transfer after delegate authority has been revoked', async (t) => {
// Given a Umi instance and a new signer.
const umi = await createUmi();
const delegateAddress = generateSigner(umi);
const newOwnerAddress = generateSigner(umi);

const asset = await createAsset(umi, {
plugins: [
pluginAuthorityPair({
{
type: 'TransferDelegate',
authority: addressPluginAuthority(delegateAddress.publicKey),
}),
authority: {
type: 'Address',
address: delegateAddress.publicKey,
},
},
],
});

await revokePluginAuthorityV1(umi, {
await revokePluginAuthority(umi, {
asset: asset.publicKey,
pluginType: PluginType.TransferDelegate,
plugin: {
type: 'TransferDelegate',
},
}).sendAndConfirm(umi);

const result = transferV1(umi, {
asset: asset.publicKey,
const result = transfer(umi, {
asset,
newOwner: newOwnerAddress.publicKey,
authority: delegateAddress,
}).sendAndConfirm(umi);
Expand All @@ -155,3 +162,39 @@ test('it cannot transfer after delegate authority has been revoked', async (t) =
},
});
});

test('it can transfer using delegated update authority from collection', async (t) => {
const umi = await createUmi();
const owner = generateSigner(umi);
const newOwner = generateSigner(umi);

const { asset, collection } = await createAssetWithCollection(umi, {
owner: owner.publicKey,
plugins: [
{
type: 'TransferDelegate',
authority: {
type: 'UpdateAuthority',
},
},
],
});

await transfer(umi, {
asset,
collection,
newOwner: newOwner.publicKey,
}).sendAndConfirm(umi);

await assertAsset(t, umi, {
...DEFAULT_ASSET,
asset: asset.publicKey,
owner: newOwner.publicKey,
updateAuthority: { type: 'Collection' },
transferDelegate: {
authority: {
type: 'Owner',
},
},
});
});
24 changes: 16 additions & 8 deletions programs/mpl-core/src/plugins/transfer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,23 @@ impl PluginValidation for TransferDelegate {
&self,
ctx: &PluginValidationContext,
) -> Result<ValidationResult, ProgramError> {
if ctx.self_authority
== (&Authority::Address {
address: *ctx.authority_info.key,
})
{
approve!()
} else {
abstain!()
match ctx.self_authority {
Authority::Address { address } if address == ctx.authority_info.key => {
return approve!();
}

Authority::UpdateAuthority => {
if ctx
.resolved_authorities
.map_or(false, |auths| auths.contains(&Authority::UpdateAuthority))
{
return approve!();
}
}

_ => {}
}
abstain!()
}

/// Validate the revoke plugin authority lifecycle action.
Expand Down

0 comments on commit 43a4419

Please sign in to comment.