transfer-hook.ts 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. import * as anchor from "@coral-xyz/anchor";
  2. import { Program } from "@coral-xyz/anchor";
  3. import { TransferHook } from "../target/types/transfer_hook";
  4. import {
  5. Transaction,
  6. sendAndConfirmTransaction,
  7. Keypair,
  8. } from "@solana/web3.js";
  9. import {
  10. TOKEN_2022_PROGRAM_ID,
  11. ASSOCIATED_TOKEN_PROGRAM_ID,
  12. createAssociatedTokenAccountInstruction,
  13. createMintToInstruction,
  14. getAssociatedTokenAddressSync,
  15. createTransferCheckedWithTransferHookInstruction,
  16. } from "@solana/spl-token";
  17. describe("transfer-hook", () => {
  18. // Configure the client to use the local cluster.
  19. const provider = anchor.AnchorProvider.env();
  20. anchor.setProvider(provider);
  21. const program = anchor.workspace.TransferHook as Program<TransferHook>;
  22. const wallet = provider.wallet as anchor.Wallet;
  23. const connection = provider.connection;
  24. // Generate keypair to use as address for the transfer-hook enabled mint
  25. const mint = new Keypair();
  26. const decimals = 2;
  27. // Sender token account address
  28. const sourceTokenAccount = getAssociatedTokenAddressSync(
  29. mint.publicKey,
  30. wallet.publicKey,
  31. false,
  32. TOKEN_2022_PROGRAM_ID,
  33. ASSOCIATED_TOKEN_PROGRAM_ID
  34. );
  35. // Recipient token account address
  36. const recipient = Keypair.generate();
  37. const destinationTokenAccount = getAssociatedTokenAddressSync(
  38. mint.publicKey,
  39. recipient.publicKey,
  40. false,
  41. TOKEN_2022_PROGRAM_ID,
  42. ASSOCIATED_TOKEN_PROGRAM_ID
  43. );
  44. it("Create Mint with Transfer Hook Extension", async () => {
  45. const transactionSignature = await program.methods
  46. .initialize(decimals)
  47. .accounts({ mintAccount: mint.publicKey })
  48. .signers([mint])
  49. .rpc({ skipPreflight: true });
  50. console.log("Your transaction signature", transactionSignature);
  51. });
  52. // Create the two token accounts for the transfer-hook enabled mint
  53. // Fund the sender token account with 100 tokens
  54. it("Create Token Accounts and Mint Tokens", async () => {
  55. // 100 tokens
  56. const amount = 100 * 10 ** decimals;
  57. const transaction = new Transaction().add(
  58. createAssociatedTokenAccountInstruction(
  59. wallet.publicKey,
  60. sourceTokenAccount,
  61. wallet.publicKey,
  62. mint.publicKey,
  63. TOKEN_2022_PROGRAM_ID,
  64. ASSOCIATED_TOKEN_PROGRAM_ID
  65. ),
  66. createAssociatedTokenAccountInstruction(
  67. wallet.publicKey,
  68. destinationTokenAccount,
  69. recipient.publicKey,
  70. mint.publicKey,
  71. TOKEN_2022_PROGRAM_ID,
  72. ASSOCIATED_TOKEN_PROGRAM_ID
  73. ),
  74. createMintToInstruction(
  75. mint.publicKey,
  76. sourceTokenAccount,
  77. wallet.publicKey,
  78. amount,
  79. [],
  80. TOKEN_2022_PROGRAM_ID
  81. )
  82. );
  83. const txSig = await sendAndConfirmTransaction(
  84. connection,
  85. transaction,
  86. [wallet.payer],
  87. { skipPreflight: true }
  88. );
  89. console.log(`Transaction Signature: ${txSig}`);
  90. });
  91. // Account to store extra accounts required by the transfer hook instruction
  92. it("Create ExtraAccountMetaList Account", async () => {
  93. const initializeExtraAccountMetaListInstruction = await program.methods
  94. .initializeExtraAccountMetaList()
  95. .accounts({
  96. mint: mint.publicKey,
  97. })
  98. .instruction();
  99. const transaction = new Transaction().add(
  100. initializeExtraAccountMetaListInstruction
  101. );
  102. const txSig = await sendAndConfirmTransaction(
  103. provider.connection,
  104. transaction,
  105. [wallet.payer],
  106. { skipPreflight: true, commitment: "confirmed" }
  107. );
  108. console.log("Transaction Signature:", txSig);
  109. });
  110. it("Transfer Hook with Extra Account Meta", async () => {
  111. // 1 tokens
  112. const amount = 1 * 10 ** decimals;
  113. const bigIntAmount = BigInt(amount);
  114. // Standard token transfer instruction
  115. const transferInstruction =
  116. await createTransferCheckedWithTransferHookInstruction(
  117. connection,
  118. sourceTokenAccount,
  119. mint.publicKey,
  120. destinationTokenAccount,
  121. wallet.publicKey,
  122. bigIntAmount,
  123. decimals,
  124. [],
  125. "confirmed",
  126. TOKEN_2022_PROGRAM_ID
  127. );
  128. const transaction = new Transaction().add(transferInstruction);
  129. const txSig = await sendAndConfirmTransaction(
  130. connection,
  131. transaction,
  132. [wallet.payer],
  133. { skipPreflight: true }
  134. );
  135. console.log("Transfer Signature:", txSig);
  136. });
  137. });