tests.ts 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. import { Buffer } from 'node:buffer';
  2. import { describe, test } from 'node:test';
  3. import { PROGRAM_ID as TOKEN_METADATA_PROGRAM_ID } from '@metaplex-foundation/mpl-token-metadata';
  4. import { ASSOCIATED_TOKEN_PROGRAM_ID, TOKEN_PROGRAM_ID, getAssociatedTokenAddressSync } from '@solana/spl-token';
  5. import { Keypair, PublicKey, SYSVAR_RENT_PUBKEY, SystemProgram, Transaction, TransactionInstruction } from '@solana/web3.js';
  6. import { start } from 'solana-bankrun';
  7. import { CreateTokenArgs, MintToArgs, TransferTokensArgs } from './instructions';
  8. describe('Transferring Tokens', async () => {
  9. const PROGRAM_ID = new PublicKey('z7msBPQHDJjTvdQRoEcKyENgXDhSRYeHieN1ZMTqo35');
  10. const context = await start(
  11. [
  12. { name: 'transfer_tokens_program', programId: PROGRAM_ID },
  13. { name: 'token_metadata', programId: TOKEN_METADATA_PROGRAM_ID },
  14. ],
  15. [],
  16. );
  17. const client = context.banksClient;
  18. const payer = context.payer;
  19. const tokenMintKeypair: Keypair = Keypair.generate();
  20. const nftMintKeypair: Keypair = Keypair.generate();
  21. const recipientWallet = Keypair.generate();
  22. test('Create an SPL Token!', async () => {
  23. const metadataPDA = PublicKey.findProgramAddressSync(
  24. [Buffer.from('metadata'), TOKEN_METADATA_PROGRAM_ID.toBuffer(), tokenMintKeypair.publicKey.toBuffer()],
  25. TOKEN_METADATA_PROGRAM_ID,
  26. )[0];
  27. // SPL Token default = 9 decimals
  28. //
  29. const createArgs = new CreateTokenArgs(
  30. 'Solana Gold',
  31. 'GOLDSOL',
  32. 'https://raw.githubusercontent.com/solana-developers/program-examples/new-examples/tokens/tokens/.assets/spl-token.json',
  33. 9,
  34. );
  35. const createTokenIx = new TransactionInstruction({
  36. keys: [
  37. { pubkey: payer.publicKey, isSigner: true, isWritable: true },
  38. {
  39. pubkey: tokenMintKeypair.publicKey,
  40. isSigner: true,
  41. isWritable: true,
  42. },
  43. { pubkey: metadataPDA, isSigner: false, isWritable: true },
  44. {
  45. pubkey: SystemProgram.programId,
  46. isSigner: false,
  47. isWritable: false,
  48. },
  49. { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
  50. {
  51. pubkey: TOKEN_METADATA_PROGRAM_ID,
  52. isSigner: false,
  53. isWritable: false,
  54. },
  55. { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false },
  56. ],
  57. programId: PROGRAM_ID,
  58. data: createArgs.toBuffer(),
  59. });
  60. const tx = new Transaction();
  61. const [blockhash, _] = await client.getLatestBlockhash();
  62. tx.recentBlockhash = blockhash;
  63. tx.add(createTokenIx).sign(payer, tokenMintKeypair);
  64. await client.processTransaction(tx);
  65. console.log('Success!');
  66. console.log(` Mint Address: ${tokenMintKeypair.publicKey}`);
  67. });
  68. test('Create an NFT!', async () => {
  69. const metadataPDA = PublicKey.findProgramAddressSync(
  70. [Buffer.from('metadata'), TOKEN_METADATA_PROGRAM_ID.toBuffer(), nftMintKeypair.publicKey.toBuffer()],
  71. TOKEN_METADATA_PROGRAM_ID,
  72. )[0];
  73. // NFT default = 0 decimals
  74. //
  75. const createArgs = new CreateTokenArgs(
  76. 'Homer NFT',
  77. 'HOMR',
  78. 'https://raw.githubusercontent.com/solana-developers/program-examples/new-examples/tokens/tokens/.assets/nft.json',
  79. 0,
  80. );
  81. const createTokenIx = new TransactionInstruction({
  82. keys: [
  83. { pubkey: payer.publicKey, isSigner: true, isWritable: true },
  84. { pubkey: nftMintKeypair.publicKey, isSigner: true, isWritable: true },
  85. { pubkey: metadataPDA, isSigner: false, isWritable: true },
  86. {
  87. pubkey: SystemProgram.programId,
  88. isSigner: false,
  89. isWritable: false,
  90. },
  91. { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
  92. {
  93. pubkey: TOKEN_METADATA_PROGRAM_ID,
  94. isSigner: false,
  95. isWritable: false,
  96. },
  97. { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false },
  98. ],
  99. programId: PROGRAM_ID,
  100. data: createArgs.toBuffer(),
  101. });
  102. const tx = new Transaction();
  103. const [blockhash, _] = await client.getLatestBlockhash();
  104. tx.recentBlockhash = blockhash;
  105. tx.add(createTokenIx).sign(payer, nftMintKeypair);
  106. await client.processTransaction(tx);
  107. console.log('Success!');
  108. console.log(` Mint Address: ${nftMintKeypair.publicKey}`);
  109. });
  110. test('Mint some tokens to your wallet!', async () => {
  111. const recipientATA = getAssociatedTokenAddressSync(tokenMintKeypair.publicKey, payer.publicKey);
  112. const mintArgs = new MintToArgs(100);
  113. const mintToIx = new TransactionInstruction({
  114. keys: [
  115. { pubkey: payer.publicKey, isSigner: true, isWritable: true }, // mint_authority
  116. { pubkey: payer.publicKey, isSigner: false, isWritable: false }, // recipient
  117. {
  118. pubkey: tokenMintKeypair.publicKey,
  119. isSigner: false,
  120. isWritable: true,
  121. }, // mint_pda must be writable
  122. { pubkey: recipientATA, isSigner: false, isWritable: true }, // associated_token_account must be writable
  123. { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, // spl_token::ID
  124. {
  125. pubkey: ASSOCIATED_TOKEN_PROGRAM_ID,
  126. isSigner: false,
  127. isWritable: false,
  128. }, // spl_associated_token_account::ID
  129. {
  130. pubkey: SystemProgram.programId,
  131. isSigner: false,
  132. isWritable: false,
  133. }, // system_program::ID
  134. ],
  135. programId: PROGRAM_ID,
  136. data: mintArgs.toBuffer(),
  137. });
  138. const tx = new Transaction();
  139. const [blockhash, _] = await client.getLatestBlockhash();
  140. tx.recentBlockhash = blockhash;
  141. tx.add(mintToIx).sign(payer);
  142. await client.processTransaction(tx);
  143. console.log('Success!');
  144. console.log(` ATA Address: ${recipientATA}`);
  145. });
  146. test('Transfer tokens to another wallet!', async () => {
  147. const fromAssociatedTokenAddress = getAssociatedTokenAddressSync(tokenMintKeypair.publicKey, payer.publicKey);
  148. console.log(`Owner Token Address: ${fromAssociatedTokenAddress}`);
  149. const toAssociatedTokenAddress = getAssociatedTokenAddressSync(tokenMintKeypair.publicKey, recipientWallet.publicKey);
  150. console.log(`Recipient Token Address: ${toAssociatedTokenAddress}`);
  151. const transferArgs = new TransferTokensArgs(15);
  152. const transferTokensIx = new TransactionInstruction({
  153. keys: [
  154. { pubkey: payer.publicKey, isSigner: true, isWritable: true }, // Owner
  155. { pubkey: recipientWallet.publicKey, isSigner: true, isWritable: true }, // Recipient
  156. {
  157. pubkey: tokenMintKeypair.publicKey,
  158. isSigner: false,
  159. isWritable: true,
  160. }, // Mint account
  161. {
  162. pubkey: fromAssociatedTokenAddress,
  163. isSigner: false,
  164. isWritable: true,
  165. }, // Owner Token account
  166. { pubkey: toAssociatedTokenAddress, isSigner: false, isWritable: true }, // Recipient Token account
  167. // { pubkey: payer.publicKey, isSigner: true, isWritable: true }, // Payer
  168. { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, // Token program
  169. {
  170. pubkey: ASSOCIATED_TOKEN_PROGRAM_ID,
  171. isSigner: false,
  172. isWritable: false,
  173. }, // Associated token program
  174. { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }, // System program
  175. ],
  176. programId: PROGRAM_ID,
  177. data: transferArgs.toBuffer(),
  178. });
  179. const tx = new Transaction();
  180. const [blockhash, _] = await client.getLatestBlockhash();
  181. tx.recentBlockhash = blockhash;
  182. tx.add(transferTokensIx).sign(payer, recipientWallet);
  183. await client.processTransaction(tx);
  184. });
  185. });