123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 |
- import * as anchor from '@coral-xyz/anchor';
- import { PROGRAM_ID as BUBBLEGUM_PROGRAM_ID } from '@metaplex-foundation/mpl-bubblegum';
- import { SPL_ACCOUNT_COMPRESSION_PROGRAM_ID, SPL_NOOP_PROGRAM_ID } from '@solana/spl-account-compression';
- import type { AccountMeta } from '@solana/web3.js';
- import { type CnftVault, IDL } from '../target/types/cnft_vault';
- import { getAsset, getAssetProof } from './readAPI';
- import { decode, loadWalletKey, mapProof } from './utils';
- describe('cNFT Vault', () => {
- const provider = anchor.AnchorProvider.env();
- anchor.setProvider(provider);
- const payer = provider.wallet as anchor.Wallet;
- const program = anchor.workspace.CnftVault as anchor.Program<CnftVault>;
- const [vaultPDA, _bump] = anchor.web3.PublicKey.findProgramAddressSync([Buffer.from('cNFT-vault', 'utf8')], program.programId);
- console.log(`Vault address: ${vaultPDA.toBase58()}`);
- it('Withdraw a cNFT!', async () => {
- // we expect the cNFT to already be in the vault
- // you can send it there (to vaultPDA) using any regular wallet
- // the cNFT has the following asset id
- const assetId = 'DGWU3mHenDerCvjkeDsKYEbsvXbWvqdo1bVoXy3dkeTd'; // TODO
- // and is compressed in the following tree
- const tree = new anchor.web3.PublicKey('trezdkTFPKyj4gE9LAJYPpxn8AYVCvM7Mc4JkTb9X5B'); // TODO
- const receiver = payer.publicKey; // you can define any pubkey as the receiver here
- const [treeAuthority, _bump2] = anchor.web3.PublicKey.findProgramAddressSync([tree.toBuffer()], BUBBLEGUM_PROGRAM_ID);
- const asset = await getAsset(assetId);
- const proof = await getAssetProof(assetId);
- const proofPathAsAccounts = mapProof(proof);
- const root = decode(proof.root);
- const dataHash = decode(asset.compression.data_hash);
- const creatorHash = decode(asset.compression.creator_hash);
- const nonce = new anchor.BN(asset.compression.leaf_id);
- const index = asset.compression.leaf_id;
- const sx = await program.methods
- .withdrawCnft(root, dataHash, creatorHash, nonce, index)
- .accounts({
- leafOwner: vaultPDA,
- merkleTree: tree,
- newLeafOwner: receiver,
- treeAuthority: treeAuthority,
- bubblegumProgram: BUBBLEGUM_PROGRAM_ID,
- compressionProgram: SPL_ACCOUNT_COMPRESSION_PROGRAM_ID,
- logWrapper: SPL_NOOP_PROGRAM_ID,
- systemProgram: anchor.web3.SystemProgram.programId,
- })
- .remainingAccounts(proofPathAsAccounts)
- .rpc();
- console.log('Success!');
- console.log(` Tx Signature: ${sx}`);
- });
- it('Withdraw two cNFTs!', async () => {
- // TODO change all of these to your values
- const assetId1 = 'DGWU3mHenDerCvjkeDsKYEbsvXbWvqdo1bVoXy3dkeTd';
- const assetId2 = '14JojSTdBZvP7f77rCxB3oQK78skTVD6DiXrXUL4objg';
- const tree1 = new anchor.web3.PublicKey('trezdkTFPKyj4gE9LAJYPpxn8AYVCvM7Mc4JkTb9X5B');
- const tree2 = new anchor.web3.PublicKey('Feywkti8LLBLfxhSGmYgzUBqpq89qehfB1SMTYV1zCu');
- const receiver1 = new anchor.web3.PublicKey('Andys9wuoMdUeRiZLgRS5aJwYNFv4Ut6qQi8PNDTAPEM');
- const receiver2 = new anchor.web3.PublicKey('Andys9wuoMdUeRiZLgRS5aJwYNFv4Ut6qQi8PNDTAPEM');
- // ---
- const [treeAuthority1, _bump2] = anchor.web3.PublicKey.findProgramAddressSync([tree1.toBuffer()], BUBBLEGUM_PROGRAM_ID);
- const [treeAuthority2, _bump3] = anchor.web3.PublicKey.findProgramAddressSync([tree2.toBuffer()], BUBBLEGUM_PROGRAM_ID);
- const asset1 = await getAsset(assetId1);
- const asset2 = await getAsset(assetId2);
- const proof1 = await getAssetProof(assetId1);
- const proofPathAsAccounts1 = mapProof(proof1);
- const proof2 = await getAssetProof(assetId2);
- const proofPathAsAccounts2 = mapProof(proof2);
- const ixData1 = getInstructionData(asset1, proof1);
- const ixData2 = getInstructionData(asset2, proof2);
- const remainingAccounts: AccountMeta[] = [...proofPathAsAccounts1, ...proofPathAsAccounts2];
- const sx = await program.methods
- .withdrawTwoCnfts(...ixData1, ...ixData2)
- .accounts({
- leafOwner: vaultPDA,
- merkleTree1: tree1,
- newLeafOwner1: receiver1,
- treeAuthority1: treeAuthority1,
- merkleTree2: tree2,
- newLeafOwner2: receiver2,
- treeAuthority2: treeAuthority2,
- bubblegumProgram: BUBBLEGUM_PROGRAM_ID,
- compressionProgram: SPL_ACCOUNT_COMPRESSION_PROGRAM_ID,
- logWrapper: SPL_NOOP_PROGRAM_ID,
- systemProgram: anchor.web3.SystemProgram.programId,
- })
- .remainingAccounts(remainingAccounts)
- .rpc();
- console.log('Success!');
- console.log(` Tx Signature: ${sx}`);
- });
- });
- function getInstructionData(asset: any, proof: any): [number[], number[], number[], anchor.BN, number, number] {
- const root = decode(proof.root);
- const dataHash = decode(asset.compression.data_hash);
- const creatorHash = decode(asset.compression.creator_hash);
- const nonce = new anchor.BN(asset.compression.leaf_id);
- const index = asset.compression.leaf_id;
- const proofLength = proof.proof.length;
- return [root, dataHash, creatorHash, nonce, index, proofLength];
- }
|