import { DecompressibleState, MetadataArgsArgs, createTree as baseCreateTree, mintV1 as baseMintV1, fetchMerkleTree, findLeafAssetIdPda, findTreeConfigPda, hashLeaf, mplBubblegum, setDecompressibleState, } from '@metaplex-foundation/mpl-bubblegum'; import { mplTokenMetadata } from '@metaplex-foundation/mpl-token-metadata'; import { Context, Pda, PublicKey, SolAmount, Umi, createSignerFromKeypair, generateSigner, none, publicKey, signerIdentity, sol, } from '@metaplex-foundation/umi'; import { createUmi as createBundleUmi } from '@metaplex-foundation/umi-bundle-defaults'; import { fromWeb3JsKeypair } from '@metaplex-foundation/umi-web3js-adapters'; import { Connection, Keypair } from '@solana/web3.js'; export const baseCreateUmi = async ( signers: Array<[Keypair, boolean]>, connection: Connection, airdropAmount = sol(100), ): Promise => { const umi = createBundleUmi(connection); for (let index = 0; index < signers.length; index++) { const signer = signers[index]; umi.use( signerIdentity( createSignerFromKeypair(umi, fromWeb3JsKeypair(signer[0])), signer[1], ), ); } await umi.rpc.airdrop(umi.identity.publicKey, airdropAmount); return umi; }; export const createUmi = async ( signers: Array<[Keypair, boolean]>, connection: Connection, airdropAmount?: SolAmount, ) => (await baseCreateUmi(signers, connection, airdropAmount)) .use(mplTokenMetadata()) .use(mplBubblegum()); export const createTree = async ( context: Context, input: Partial[1]> = {}, ): Promise => { const merkleTree = generateSigner(context); let builder = await baseCreateTree(context, { merkleTree, maxDepth: 14, maxBufferSize: 64, ...input, }); builder = builder.append( setDecompressibleState(context, { treeConfig: input.treeConfig ?? findTreeConfigPda(context, { merkleTree: merkleTree.publicKey }), treeCreator: input.treeCreator ?? context.identity, decompressableState: DecompressibleState.Enabled, }), ); await builder.sendAndConfirm(context); return merkleTree.publicKey; }; export const mint = async ( context: Context, input: Omit[1], 'metadata' | 'leafOwner'> & { leafIndex?: number | bigint; metadata?: Partial[1]['metadata']>; leafOwner?: PublicKey; }, ): Promise<{ metadata: MetadataArgsArgs; assetId: Pda; leaf: PublicKey; leafIndex: number; }> => { const merkleTree = publicKey(input.merkleTree, false); const leafOwner = input.leafOwner ?? context.identity.publicKey; const leafIndex = Number( input.leafIndex ?? (await fetchMerkleTree(context, merkleTree)).tree.activeIndex, ); const metadata: MetadataArgsArgs = { name: 'My NFT', uri: 'https://example.com/my-nft.json', sellerFeeBasisPoints: 500, // 5% collection: none(), creators: [], ...input.metadata, }; await baseMintV1(context, { ...input, metadata, leafOwner, }).sendAndConfirm(context); return { metadata, assetId: findLeafAssetIdPda(context, { merkleTree, leafIndex }), leafIndex, leaf: publicKey( hashLeaf(context, { merkleTree, owner: publicKey(leafOwner, false), delegate: publicKey(input.leafDelegate ?? leafOwner, false), leafIndex, metadata, }), ), }; };