Skip to content

Commit

Permalink
Merge pull request #71 from metaplex-foundation/feat/get-asset-id
Browse files Browse the repository at this point in the history
Adding ability to fetch Leaf Data from a TX.
  • Loading branch information
blockiosaurus authored Jan 12, 2024
2 parents 559efbc + c31284d commit 6ed1185
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 2 deletions.
34 changes: 32 additions & 2 deletions clients/js/src/leafAssetId.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Context, Pda, PublicKey } from '@metaplex-foundation/umi';
import { Context, Pda, PublicKey, TransactionSignature } from '@metaplex-foundation/umi';
import { publicKey, string, u64 } from '@metaplex-foundation/umi/serializers';
import { MPL_BUBBLEGUM_PROGRAM_ID } from './generated';
import { LeafSchema, MPL_BUBBLEGUM_PROGRAM_ID, getLeafSchemaSerializer } from './generated';

export function findLeafAssetIdPda(
context: Pick<Context, 'programs' | 'eddsa'>,
Expand All @@ -19,3 +19,33 @@ export function findLeafAssetIdPda(
u64().serialize(seeds.leafIndex),
]);
}

export async function parseLeafFromMintV1Transaction(
context: Pick<Context, 'programs' | 'eddsa' | 'rpc'>,
signature: TransactionSignature
): Promise<LeafSchema> {
const transaction = await context.rpc.getTransaction(signature);
const innerInstructions = transaction?.meta.innerInstructions;

if (innerInstructions) {
const leaf = getLeafSchemaSerializer().deserialize(innerInstructions[0].instructions[0].data.slice(8));
return leaf[0];
}

throw new Error('Could not parse leaf from transaction');
}

export async function parseLeafFromMintToCollectionV1Transaction(
context: Pick<Context, 'programs' | 'eddsa' | 'rpc'>,
signature: TransactionSignature
): Promise<LeafSchema> {
const transaction = await context.rpc.getTransaction(signature);
const innerInstructions = transaction?.meta.innerInstructions;

if (innerInstructions) {
const leaf = getLeafSchemaSerializer().deserialize(innerInstructions[0].instructions[1].data.slice(8));
return leaf[0];
}

throw new Error('Could not parse leaf from transaction');
}
95 changes: 95 additions & 0 deletions clients/js/test/parseMintV1.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import {
defaultPublicKey,
generateSigner,
none,
percentAmount,
} from '@metaplex-foundation/umi';
import { createNft } from '@metaplex-foundation/mpl-token-metadata';
import test from 'ava';
import { MetadataArgsArgs, fetchMerkleTree, findLeafAssetIdPda, mintToCollectionV1, mintV1, parseLeafFromMintToCollectionV1Transaction, parseLeafFromMintV1Transaction } from '../src';
import { createTree, createUmi } from './_setup';

test('it can parse the leaf from mint instructions', async (t) => {
// Given an empty Bubblegum tree.
const umi = await createUmi();
const merkleTree = await createTree(umi);
const leafOwner = generateSigner(umi).publicKey;
let merkleTreeAccount = await fetchMerkleTree(umi, merkleTree);
t.is(merkleTreeAccount.tree.sequenceNumber, 0n);
t.is(merkleTreeAccount.tree.activeIndex, 0n);
t.is(merkleTreeAccount.tree.bufferSize, 1n);
t.is(merkleTreeAccount.tree.rightMostPath.index, 0);
t.is(merkleTreeAccount.tree.rightMostPath.leaf, defaultPublicKey());

// When we mint a new NFT from the tree using the following metadata.
const metadata: MetadataArgsArgs = {
name: 'My NFT',
uri: 'https://example.com/my-nft.json',
sellerFeeBasisPoints: 500, // 5%
collection: none(),
creators: [],
};

// Test with 10 different leaves to be sure they increment correctly.
for (let nonce = 0; nonce < 10; nonce += 1) {
const { signature } = await mintV1(umi, { leafOwner, merkleTree, metadata }).sendAndConfirm(umi, { confirm: { commitment: 'confirmed' } });
const leaf = await parseLeafFromMintV1Transaction(umi, signature);
const assetId = findLeafAssetIdPda(umi, { merkleTree, leafIndex: nonce });

t.is(leafOwner, leaf.owner);
t.is(Number(leaf.nonce), nonce);
t.is(leaf.id, assetId[0])
}
});

test('it can parse the leaf from mintToCollection instructions)', async (t) => {
// Given an empty Bubblegum tree.
const umi = await createUmi();
const merkleTree = await createTree(umi);
const leafOwner = generateSigner(umi).publicKey;
let merkleTreeAccount = await fetchMerkleTree(umi, merkleTree);
t.is(merkleTreeAccount.tree.sequenceNumber, 0n);
t.is(merkleTreeAccount.tree.activeIndex, 0n);
t.is(merkleTreeAccount.tree.bufferSize, 1n);
t.is(merkleTreeAccount.tree.rightMostPath.index, 0);
t.is(merkleTreeAccount.tree.rightMostPath.leaf, defaultPublicKey());

// And a Collection NFT.
const collectionMint = generateSigner(umi);
await createNft(umi, {
mint: collectionMint,
name: 'My Collection',
uri: 'https://example.com/my-collection.json',
sellerFeeBasisPoints: percentAmount(5.5), // 5.5%
isCollection: true,
}).sendAndConfirm(umi);

// When we mint a new NFT from the tree using the following metadata, with collection unverified.
const metadata: MetadataArgsArgs = {
name: 'My NFT',
uri: 'https://example.com/my-nft.json',
sellerFeeBasisPoints: 550, // 5.5%
collection: {
key: collectionMint.publicKey,
verified: false,
},
creators: [],
};

// Test with 10 different leaves to be sure they increment correctly.
for (let nonce = 0; nonce < 10; nonce += 1) {
const { signature } = await mintToCollectionV1(umi, {
leafOwner,
merkleTree,
metadata,
collectionMint: collectionMint.publicKey,
}).sendAndConfirm(umi);

const leaf = await parseLeafFromMintToCollectionV1Transaction(umi, signature);
const assetId = findLeafAssetIdPda(umi, { merkleTree, leafIndex: nonce });

t.is(leafOwner, leaf.owner);
t.is(Number(leaf.nonce), nonce);
t.is(leaf.id, assetId[0])
}
});

0 comments on commit 6ed1185

Please sign in to comment.