tests.ts 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. import * as anchor from "@project-serum/anchor";
  2. import { loadWalletKey, decode, mapProof } from "./utils";
  3. import { IDL, CnftVault } from "../target/types/cnft_vault"
  4. import { PROGRAM_ID as BUBBLEGUM_PROGRAM_ID } from "@metaplex-foundation/mpl-bubblegum";
  5. import { SPL_ACCOUNT_COMPRESSION_PROGRAM_ID, SPL_NOOP_PROGRAM_ID } from "@solana/spl-account-compression";
  6. import { getAsset, getAssetProof } from "./readAPI";
  7. import { AccountMeta } from "@solana/web3.js";
  8. describe("cNFT Vault", () => {
  9. const provider = anchor.AnchorProvider.env();
  10. anchor.setProvider(provider);
  11. const payer = provider.wallet as anchor.Wallet;
  12. const program = anchor.workspace.CnftVault as anchor.Program<CnftVault>;
  13. const [vaultPDA, _bump] = anchor.web3.PublicKey.findProgramAddressSync(
  14. [Buffer.from("cNFT-vault", "utf8")],
  15. program.programId,
  16. );
  17. console.log("Vault address: " + vaultPDA.toBase58());
  18. it("Withdraw a cNFT!", async () => {
  19. // we expect the cNFT to already be in the vault
  20. // you can send it there (to vaultPDA) using any regular wallet
  21. // the cNFT has the following asset id
  22. const assetId = "DGWU3mHenDerCvjkeDsKYEbsvXbWvqdo1bVoXy3dkeTd"; // TODO
  23. // and is compressed in the following tree
  24. const tree = new anchor.web3.PublicKey("trezdkTFPKyj4gE9LAJYPpxn8AYVCvM7Mc4JkTb9X5B"); // TODO
  25. const receiver = payer.publicKey; // you can define any pubkey as the receiver here
  26. const [treeAuthority, _bump2] = anchor.web3.PublicKey.findProgramAddressSync(
  27. [tree.toBuffer()],
  28. BUBBLEGUM_PROGRAM_ID,
  29. );
  30. const asset = await getAsset(assetId);
  31. const proof = await getAssetProof(assetId);
  32. const proofPathAsAccounts = mapProof(proof);
  33. const root = decode(proof.root);
  34. const dataHash = decode(asset.compression.data_hash);
  35. const creatorHash = decode(asset.compression.creator_hash);
  36. const nonce = new anchor.BN(asset.compression.leaf_id);
  37. const index = asset.compression.leaf_id;
  38. const sx = await program.methods.withdrawCnft(root, dataHash, creatorHash, nonce, index)
  39. .accounts({
  40. leafOwner: vaultPDA,
  41. merkleTree: tree,
  42. newLeafOwner: receiver,
  43. treeAuthority: treeAuthority,
  44. bubblegumProgram: BUBBLEGUM_PROGRAM_ID,
  45. compressionProgram: SPL_ACCOUNT_COMPRESSION_PROGRAM_ID,
  46. logWrapper: SPL_NOOP_PROGRAM_ID,
  47. systemProgram: anchor.web3.SystemProgram.programId
  48. })
  49. .remainingAccounts(proofPathAsAccounts)
  50. .rpc();
  51. console.log("Success!");
  52. console.log(` Tx Signature: ${sx}`);
  53. });
  54. it("Withdraw two cNFTs!", async () => {
  55. // TODO change all of these to your values
  56. const assetId1 = "DGWU3mHenDerCvjkeDsKYEbsvXbWvqdo1bVoXy3dkeTd";
  57. const assetId2 = "14JojSTdBZvP7f77rCxB3oQK78skTVD6DiXrXUL4objg";
  58. const tree1 = new anchor.web3.PublicKey("trezdkTFPKyj4gE9LAJYPpxn8AYVCvM7Mc4JkTb9X5B")
  59. const tree2 = new anchor.web3.PublicKey("Feywkti8LLBLfxhSGmYgzUBqpq89qehfB1SMTYV1zCu")
  60. const receiver1 = new anchor.web3.PublicKey("Andys9wuoMdUeRiZLgRS5aJwYNFv4Ut6qQi8PNDTAPEM")
  61. const receiver2 = new anchor.web3.PublicKey("Andys9wuoMdUeRiZLgRS5aJwYNFv4Ut6qQi8PNDTAPEM")
  62. // ---
  63. const [treeAuthority1, _bump2] = anchor.web3.PublicKey.findProgramAddressSync(
  64. [tree1.toBuffer()],
  65. BUBBLEGUM_PROGRAM_ID,
  66. );
  67. const [treeAuthority2, _bump3] = anchor.web3.PublicKey.findProgramAddressSync(
  68. [tree2.toBuffer()],
  69. BUBBLEGUM_PROGRAM_ID,
  70. );
  71. const asset1 = await getAsset(assetId1);
  72. const asset2 = await getAsset(assetId2);
  73. const proof1 = await getAssetProof(assetId1);
  74. const proofPathAsAccounts1 = mapProof(proof1);
  75. const proof2 = await getAssetProof(assetId2);
  76. const proofPathAsAccounts2 = mapProof(proof2);
  77. const ixData1 = getInstructionData(asset1, proof1);
  78. const ixData2 = getInstructionData(asset2, proof2);
  79. const remainingAccounts: AccountMeta[] = [...proofPathAsAccounts1, ...proofPathAsAccounts2];
  80. const sx = await program.methods.withdrawTwoCnfts(...ixData1, ...ixData2)
  81. .accounts({
  82. leafOwner: vaultPDA,
  83. merkleTree1: tree1,
  84. newLeafOwner1: receiver1,
  85. treeAuthority1: treeAuthority1,
  86. merkleTree2: tree2,
  87. newLeafOwner2: receiver2,
  88. treeAuthority2: treeAuthority2,
  89. bubblegumProgram: BUBBLEGUM_PROGRAM_ID,
  90. compressionProgram: SPL_ACCOUNT_COMPRESSION_PROGRAM_ID,
  91. logWrapper: SPL_NOOP_PROGRAM_ID,
  92. systemProgram: anchor.web3.SystemProgram.programId
  93. })
  94. .remainingAccounts(remainingAccounts)
  95. .rpc();
  96. console.log("Success!");
  97. console.log(` Tx Signature: ${sx}`);
  98. });
  99. });
  100. function getInstructionData(asset: any, proof: any):
  101. [number[], number[], number[], anchor.BN, number, number] {
  102. const root = decode(proof.root);
  103. const dataHash = decode(asset.compression.data_hash);
  104. const creatorHash = decode(asset.compression.creator_hash);
  105. const nonce = new anchor.BN(asset.compression.leaf_id);
  106. const index = asset.compression.leaf_id;
  107. const proofLength = proof.proof.length;
  108. return [root, dataHash, creatorHash, nonce, index, proofLength];
  109. }