transfer-hook.ts 4.1 KB

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