From a7adf52687c280d0b0845d7d175bb7e3c0bb7d01 Mon Sep 17 00:00:00 2001 From: Nhan Phan Date: Mon, 22 Jan 2024 15:53:28 -0800 Subject: [PATCH 1/3] add verified creator tests --- clients/js/test/updateMetadata.test.ts | 227 +++++++++++++++++++++++-- 1 file changed, 216 insertions(+), 11 deletions(-) diff --git a/clients/js/test/updateMetadata.test.ts b/clients/js/test/updateMetadata.test.ts index 42cae801..dd44585c 100644 --- a/clients/js/test/updateMetadata.test.ts +++ b/clients/js/test/updateMetadata.test.ts @@ -10,6 +10,10 @@ import { } from '@metaplex-foundation/umi'; import { generateSignerWithSol } from '@metaplex-foundation/umi-bundle-tests'; import test from 'ava'; +import { + DasApiAsset, + GetAssetProofRpcResponse, +} from '@metaplex-foundation/digital-asset-standard-api'; import { MetadataArgsArgs, UpdateArgsArgs, @@ -24,12 +28,9 @@ import { hashMetadataCreators, hashMetadataData, mintToCollectionV1, + verifyCreator, } from '../src'; import { mint, createTree, createUmi } from './_setup'; -import { - DasApiAsset, - GetAssetProofRpcResponse, -} from '@metaplex-foundation/digital-asset-standard-api'; test('it can update the metadata of a minted compressed NFT', async (t) => { // Given an empty Bubblegum tree. @@ -208,7 +209,7 @@ test('it cannot update metadata using collection update authority when collectio name: some('New name'), uri: some('https://updated-example.com/my-nft.json'), }; - let promise = updateMetadata(umi, { + const promise = updateMetadata(umi, { leafOwner, merkleTree, root: getCurrentRoot(merkleTreeAccount.tree), @@ -270,7 +271,7 @@ test('it can update metadata using collection update authority when collection i merkleTree, metadata, collectionMint: collectionMint.publicKey, - collectionAuthority: collectionAuthority, + collectionAuthority, }).sendAndConfirm(umi); // And when metadata is updated. @@ -354,7 +355,7 @@ test('it can update metadata using the getAssetWithProof helper with verified co merkleTree, metadata, collectionMint: collectionMint.publicKey, - collectionAuthority: collectionAuthority, + collectionAuthority, }).sendAndConfirm(umi); const leaf = publicKey( hashLeaf(umi, { @@ -452,7 +453,7 @@ test('it cannot update metadata using tree owner when collection is verified', a merkleTree, metadata, collectionMint: collectionMint.publicKey, - collectionAuthority: collectionAuthority, + collectionAuthority, treeCreatorOrDelegate: treeCreator, }).sendAndConfirm(umi); @@ -461,7 +462,7 @@ test('it cannot update metadata using tree owner when collection is verified', a name: some('New name'), uri: some('https://updated-example.com/my-nft.json'), }; - let promise = updateMetadata(umi, { + const promise = updateMetadata(umi, { leafOwner, merkleTree, root: getCurrentRoot(merkleTreeAccount.tree), @@ -514,7 +515,7 @@ test('it cannot update immutable metadata', async (t) => { }).sendAndConfirm(umi); // And the leaf was updated to be immutable in the merkle tree. - let immutableMetadata = { + const immutableMetadata = { ...metadata, isMutable: false, }; @@ -532,7 +533,7 @@ test('it cannot update immutable metadata', async (t) => { name: some('New name'), uri: some('https://updated-example.com/my-nft.json'), }; - let promise = updateMetadata(umi, { + const promise = updateMetadata(umi, { leafOwner, merkleTree, root: getCurrentRoot(merkleTreeAccount.tree), @@ -556,3 +557,207 @@ test('it cannot update immutable metadata', async (t) => { merkleTreeAccount = await fetchMerkleTree(umi, merkleTree); t.is(merkleTreeAccount.tree.rightMostPath.leaf, publicKey(notUpdatedLeaf)); }); + +test('it cannot verify currently unverified creator if not signer', async (t) => { + const umi = await createUmi(); + const creatorA = generateSigner(umi); + const creatorB = generateSigner(umi); + const merkleTree = await createTree(umi); + const merkleTreeAccount = await fetchMerkleTree(umi, merkleTree); + const leafOwner = generateSigner(umi).publicKey; + const { metadata, leafIndex } = await mint(umi, { + merkleTree, + leafOwner, + metadata: { + creators: [ + { address: creatorA.publicKey, verified: false, share: 60 }, + { address: creatorB.publicKey, verified: false, share: 40 }, + ], + }, + }); + + await verifyCreator(umi, { + leafOwner, + creator: creatorA, + merkleTree, + root: getCurrentRoot(merkleTreeAccount.tree), + nonce: leafIndex, + index: leafIndex, + metadata, + proof: [], + }).sendAndConfirm(umi); + + const promise = updateMetadata(umi, { + leafOwner, + merkleTree, + root: getCurrentRoot(merkleTreeAccount.tree), + nonce: leafIndex, + index: leafIndex, + currentMetadata: metadata, + proof: [], + updateArgs: { + name: 'New name', + creators: [ + { address: creatorA.publicKey, verified: true, share: 60 }, + { address: creatorB.publicKey, verified: true, share: 40 }, + ], + }, + }).sendAndConfirm(umi); + + // Then we expect a program error. + await t.throwsAsync(promise, { name: 'CreatorDidNotVerify' }); +}); + +test('it can verify currently unverified creator if signer', async (t) => { + const umi = await createUmi(); + const creatorA = umi.identity; + const creatorB = generateSigner(umi); + const merkleTree = await createTree(umi); + let merkleTreeAccount = await fetchMerkleTree(umi, merkleTree); + const leafOwner = generateSigner(umi).publicKey; + const { metadata, leafIndex } = await mint(umi, { + merkleTree, + leafOwner, + metadata: { + creators: [ + { address: creatorA.publicKey, verified: false, share: 60 }, + { address: creatorB.publicKey, verified: false, share: 40 }, + ], + }, + }); + + const updateArgs = { + name: 'New name', + creators: [ + { address: creatorA.publicKey, verified: true, share: 60 }, + { address: creatorB.publicKey, verified: false, share: 40 }, + ], + }; + + await updateMetadata(umi, { + leafOwner, + merkleTree, + root: getCurrentRoot(merkleTreeAccount.tree), + nonce: leafIndex, + index: leafIndex, + currentMetadata: metadata, + proof: [], + updateArgs, + }).sendAndConfirm(umi); + + // Then the leaf was updated in the merkle tree. + const updatedLeaf = hashLeaf(umi, { + merkleTree, + owner: leafOwner, + leafIndex, + metadata: { + ...metadata, + ...updateArgs, + }, + }); + merkleTreeAccount = await fetchMerkleTree(umi, merkleTree); + t.is(merkleTreeAccount.tree.rightMostPath.leaf, publicKey(updatedLeaf)); +}); + +test('it cannot unverify currently verified creator if not signer', async (t) => { + const umi = await createUmi(); + const creatorA = generateSigner(umi); + const creatorB = generateSigner(umi); + const merkleTree = await createTree(umi); + const merkleTreeAccount = await fetchMerkleTree(umi, merkleTree); + const leafOwner = generateSigner(umi).publicKey; + const { metadata, leafIndex } = await mint(umi, { + merkleTree, + leafOwner, + metadata: { + creators: [ + { address: creatorA.publicKey, verified: false, share: 60 }, + { address: creatorB.publicKey, verified: false, share: 40 }, + ], + }, + }); + + await verifyCreator(umi, { + leafOwner, + creator: creatorA, + merkleTree, + root: getCurrentRoot(merkleTreeAccount.tree), + nonce: leafIndex, + index: leafIndex, + metadata, + proof: [], + }).sendAndConfirm(umi); + + const updateArgs = { + name: 'New name', + creators: [ + { address: creatorA.publicKey, verified: false, share: 60 }, + { address: creatorB.publicKey, verified: false, share: 40 }, + ], + }; + + const promise = updateMetadata(umi, { + leafOwner, + merkleTree, + root: getCurrentRoot(merkleTreeAccount.tree), + nonce: leafIndex, + index: leafIndex, + currentMetadata: metadata, + proof: [], + updateArgs, + }).sendAndConfirm(umi); + + await t.throwsAsync(promise, { name: 'PublicKeyMismatch' }); + +}); + +test('it can unverify currently verified creator if signer', async (t) => { + const umi = await createUmi(); + const creatorA = umi.identity; + const creatorB = generateSigner(umi); + const merkleTree = await createTree(umi); + let merkleTreeAccount = await fetchMerkleTree(umi, merkleTree); + const leafOwner = generateSigner(umi).publicKey; + const { metadata, leafIndex } = await mint(umi, { + merkleTree, + leafOwner, + metadata: { + creators: [ + { address: creatorA.publicKey, verified: true, share: 60 }, + { address: creatorB.publicKey, verified: false, share: 40 }, + ], + }, + }); + + const updateArgs = { + name: 'New name', + creators: [ + { address: creatorA.publicKey, verified: false, share: 60 }, + { address: creatorB.publicKey, verified: false, share: 40 }, + ], + }; + + await updateMetadata(umi, { + leafOwner, + merkleTree, + root: getCurrentRoot(merkleTreeAccount.tree), + nonce: leafIndex, + index: leafIndex, + currentMetadata: metadata, + proof: [], + updateArgs, + }).sendAndConfirm(umi); + + // Then the leaf was updated in the merkle tree. + const updatedLeaf = hashLeaf(umi, { + merkleTree, + owner: leafOwner, + leafIndex, + metadata: { + ...metadata, + ...updateArgs, + }, + }); + merkleTreeAccount = await fetchMerkleTree(umi, merkleTree); + t.is(merkleTreeAccount.tree.rightMostPath.leaf, publicKey(updatedLeaf)); +}); From 5c693960a76ae5f7a11cd16b4658c2661990f22f Mon Sep 17 00:00:00 2001 From: Nhan Phan Date: Mon, 22 Jan 2024 16:28:35 -0800 Subject: [PATCH 2/3] lint --- clients/js/test/updateMetadata.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/clients/js/test/updateMetadata.test.ts b/clients/js/test/updateMetadata.test.ts index dd44585c..cc06a437 100644 --- a/clients/js/test/updateMetadata.test.ts +++ b/clients/js/test/updateMetadata.test.ts @@ -708,7 +708,6 @@ test('it cannot unverify currently verified creator if not signer', async (t) => }).sendAndConfirm(umi); await t.throwsAsync(promise, { name: 'PublicKeyMismatch' }); - }); test('it can unverify currently verified creator if signer', async (t) => { From 80e86cd78f2b651c74b6190a2ae38892e1a9db32 Mon Sep 17 00:00:00 2001 From: Nhan Phan Date: Tue, 23 Jan 2024 09:58:57 -0800 Subject: [PATCH 3/3] look for correct error, use updated current metadata --- clients/js/test/updateMetadata.test.ts | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/clients/js/test/updateMetadata.test.ts b/clients/js/test/updateMetadata.test.ts index cc06a437..280cb513 100644 --- a/clients/js/test/updateMetadata.test.ts +++ b/clients/js/test/updateMetadata.test.ts @@ -593,7 +593,13 @@ test('it cannot verify currently unverified creator if not signer', async (t) => root: getCurrentRoot(merkleTreeAccount.tree), nonce: leafIndex, index: leafIndex, - currentMetadata: metadata, + currentMetadata: { + ...metadata, + creators: [ + { address: creatorA.publicKey, verified: true, share: 60 }, + { address: creatorB.publicKey, verified: false, share: 40 }, + ], + }, proof: [], updateArgs: { name: 'New name', @@ -702,12 +708,18 @@ test('it cannot unverify currently verified creator if not signer', async (t) => root: getCurrentRoot(merkleTreeAccount.tree), nonce: leafIndex, index: leafIndex, - currentMetadata: metadata, + currentMetadata: { + ...metadata, + creators: [ + { address: creatorA.publicKey, verified: true, share: 60 }, + { address: creatorB.publicKey, verified: false, share: 40 }, + ], + }, proof: [], updateArgs, }).sendAndConfirm(umi); - await t.throwsAsync(promise, { name: 'PublicKeyMismatch' }); + await t.throwsAsync(promise, { name: 'CreatorDidNotUnverify' }); }); test('it can unverify currently verified creator if signer', async (t) => {