test.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. import { Buffer } from 'node:buffer';
  2. import { PROGRAM_ID as TOKEN_METADATA_PROGRAM_ID } from '@metaplex-foundation/mpl-token-metadata';
  3. import { ASSOCIATED_TOKEN_PROGRAM_ID, TOKEN_PROGRAM_ID, getAssociatedTokenAddress } from '@solana/spl-token';
  4. import {
  5. Connection,
  6. Keypair,
  7. PublicKey,
  8. SYSVAR_RENT_PUBKEY,
  9. SystemProgram,
  10. Transaction,
  11. TransactionInstruction,
  12. sendAndConfirmTransaction,
  13. } from '@solana/web3.js';
  14. import { BN } from 'bn.js';
  15. import { CreateTokenArgs, MintNftArgs, MintSplArgs, MyInstruction, TransferTokensArgs } from './instructions';
  16. function createKeypairFromFile(path: string): Keypair {
  17. return Keypair.fromSecretKey(Buffer.from(JSON.parse(require('node:fs').readFileSync(path, 'utf-8'))));
  18. }
  19. describe('Transferring Tokens', async () => {
  20. // const connection = new Connection(`http://localhost:8899`, 'confirmed');
  21. const connection = new Connection('https://api.devnet.solana.com/', 'confirmed');
  22. const payer = createKeypairFromFile(`${require('node:os').homedir()}/.config/solana/id.json`);
  23. const program = createKeypairFromFile('./program/target/deploy/program-keypair.json');
  24. const tokenMintKeypair: Keypair = Keypair.generate();
  25. const nftMintKeypair: Keypair = Keypair.generate();
  26. const recipientWallet = Keypair.generate();
  27. it('Create an SPL Token!', async () => {
  28. const metadataAddress = PublicKey.findProgramAddressSync(
  29. [Buffer.from('metadata'), TOKEN_METADATA_PROGRAM_ID.toBuffer(), tokenMintKeypair.publicKey.toBuffer()],
  30. TOKEN_METADATA_PROGRAM_ID,
  31. )[0];
  32. const instructionData = new CreateTokenArgs({
  33. instruction: MyInstruction.Create,
  34. token_title: 'Solana Gold',
  35. token_symbol: 'GOLDSOL',
  36. token_uri: 'https://raw.githubusercontent.com/solana-developers/program-examples/new-examples/tokens/tokens/.assets/spl-token.json',
  37. decimals: 9,
  38. });
  39. const ix = new TransactionInstruction({
  40. keys: [
  41. {
  42. pubkey: tokenMintKeypair.publicKey,
  43. isSigner: true,
  44. isWritable: true,
  45. }, // Mint account
  46. { pubkey: payer.publicKey, isSigner: false, isWritable: true }, // Mint authority account
  47. { pubkey: metadataAddress, isSigner: false, isWritable: true }, // Metadata account
  48. { pubkey: payer.publicKey, isSigner: true, isWritable: true }, // Payer
  49. { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false }, // Rent account
  50. { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }, // System program
  51. { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, // Token program
  52. {
  53. pubkey: TOKEN_METADATA_PROGRAM_ID,
  54. isSigner: false,
  55. isWritable: false,
  56. }, // Token metadata program
  57. ],
  58. programId: program.publicKey,
  59. data: instructionData.toBuffer(),
  60. });
  61. const sx = await sendAndConfirmTransaction(connection, new Transaction().add(ix), [payer, tokenMintKeypair]);
  62. console.log('Success!');
  63. console.log(` Mint Address: ${tokenMintKeypair.publicKey}`);
  64. console.log(` Tx Signature: ${sx}`);
  65. });
  66. it('Create an NFT!', async () => {
  67. const metadataAddress = PublicKey.findProgramAddressSync(
  68. [Buffer.from('metadata'), TOKEN_METADATA_PROGRAM_ID.toBuffer(), nftMintKeypair.publicKey.toBuffer()],
  69. TOKEN_METADATA_PROGRAM_ID,
  70. )[0];
  71. const instructionData = new CreateTokenArgs({
  72. instruction: MyInstruction.Create,
  73. token_title: 'Homer NFT',
  74. token_symbol: 'HOMR',
  75. token_uri: 'https://raw.githubusercontent.com/solana-developers/program-examples/new-examples/tokens/tokens/.assets/nft.json',
  76. decimals: 0,
  77. });
  78. const ix = new TransactionInstruction({
  79. keys: [
  80. { pubkey: nftMintKeypair.publicKey, isSigner: true, isWritable: true }, // Mint account
  81. { pubkey: payer.publicKey, isSigner: false, isWritable: true }, // Mint authority account
  82. { pubkey: metadataAddress, isSigner: false, isWritable: true }, // Metadata account
  83. { pubkey: payer.publicKey, isSigner: true, isWritable: true }, // Payer
  84. { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false }, // Rent account
  85. { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }, // System program
  86. { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, // Token program
  87. {
  88. pubkey: TOKEN_METADATA_PROGRAM_ID,
  89. isSigner: false,
  90. isWritable: false,
  91. }, // Token metadata program
  92. ],
  93. programId: program.publicKey,
  94. data: instructionData.toBuffer(),
  95. });
  96. const sx = await sendAndConfirmTransaction(connection, new Transaction().add(ix), [payer, nftMintKeypair]);
  97. console.log('Success!');
  98. console.log(` Mint Address: ${nftMintKeypair.publicKey}`);
  99. console.log(` Tx Signature: ${sx}`);
  100. });
  101. it('Mint some tokens to your wallet!', async () => {
  102. const associatedTokenAccountAddress = await getAssociatedTokenAddress(tokenMintKeypair.publicKey, payer.publicKey);
  103. const instructionData = new MintSplArgs({
  104. instruction: MyInstruction.MintSpl,
  105. quantity: new BN(150),
  106. });
  107. const ix = new TransactionInstruction({
  108. keys: [
  109. {
  110. pubkey: tokenMintKeypair.publicKey,
  111. isSigner: false,
  112. isWritable: true,
  113. }, // Mint account
  114. { pubkey: payer.publicKey, isSigner: false, isWritable: true }, // Mint authority account
  115. {
  116. pubkey: associatedTokenAccountAddress,
  117. isSigner: false,
  118. isWritable: true,
  119. }, // ATA
  120. { pubkey: payer.publicKey, isSigner: true, isWritable: true }, // Payer
  121. { pubkey: SystemProgram.programId, isSigner: false, isWritable: true }, // System program
  122. { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, // Token program
  123. {
  124. pubkey: ASSOCIATED_TOKEN_PROGRAM_ID,
  125. isSigner: false,
  126. isWritable: false,
  127. }, // Token metadata program
  128. ],
  129. programId: program.publicKey,
  130. data: instructionData.toBuffer(),
  131. });
  132. const sx = await sendAndConfirmTransaction(connection, new Transaction().add(ix), [payer]);
  133. console.log('Success!');
  134. console.log(` ATA Address: ${associatedTokenAccountAddress}`);
  135. console.log(` Tx Signature: ${sx}`);
  136. });
  137. it('Mint the NFT to your wallet!', async () => {
  138. const metadataAddress = PublicKey.findProgramAddressSync(
  139. [Buffer.from('metadata'), TOKEN_METADATA_PROGRAM_ID.toBuffer(), nftMintKeypair.publicKey.toBuffer()],
  140. TOKEN_METADATA_PROGRAM_ID,
  141. )[0];
  142. const editionAddress = PublicKey.findProgramAddressSync(
  143. [Buffer.from('metadata'), TOKEN_METADATA_PROGRAM_ID.toBuffer(), nftMintKeypair.publicKey.toBuffer(), Buffer.from('edition')],
  144. TOKEN_METADATA_PROGRAM_ID,
  145. )[0];
  146. const associatedTokenAccountAddress = await getAssociatedTokenAddress(nftMintKeypair.publicKey, payer.publicKey);
  147. const instructionData = new MintNftArgs({
  148. instruction: MyInstruction.MintNft,
  149. });
  150. const ix = new TransactionInstruction({
  151. keys: [
  152. { pubkey: nftMintKeypair.publicKey, isSigner: false, isWritable: true }, // Mint account
  153. { pubkey: metadataAddress, isSigner: false, isWritable: true }, // Metadata account
  154. { pubkey: editionAddress, isSigner: false, isWritable: true }, // Edition account
  155. { pubkey: payer.publicKey, isSigner: false, isWritable: true }, // Mint authority account
  156. {
  157. pubkey: associatedTokenAccountAddress,
  158. isSigner: false,
  159. isWritable: true,
  160. }, // ATA
  161. { pubkey: payer.publicKey, isSigner: true, isWritable: true }, // Payer
  162. { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false }, // Rent account
  163. { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }, // System program
  164. { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, // Token program
  165. {
  166. pubkey: ASSOCIATED_TOKEN_PROGRAM_ID,
  167. isSigner: false,
  168. isWritable: false,
  169. }, // Associated token program
  170. {
  171. pubkey: TOKEN_METADATA_PROGRAM_ID,
  172. isSigner: false,
  173. isWritable: false,
  174. }, // Token metadata program
  175. ],
  176. programId: program.publicKey,
  177. data: instructionData.toBuffer(),
  178. });
  179. const sx = await sendAndConfirmTransaction(connection, new Transaction().add(ix), [payer]);
  180. console.log('Success!');
  181. console.log(` ATA Address: ${associatedTokenAccountAddress}`);
  182. console.log(` Tx Signature: ${sx}`);
  183. });
  184. it('Prep a new test wallet for transfers', async () => {
  185. await connection.confirmTransaction(
  186. await connection.requestAirdrop(recipientWallet.publicKey, await connection.getMinimumBalanceForRentExemption(0)),
  187. );
  188. console.log(`Recipient Pubkey: ${recipientWallet.publicKey}`);
  189. });
  190. it('Transfer tokens to another wallet!', async () => {
  191. const fromAssociatedTokenAddress = await getAssociatedTokenAddress(tokenMintKeypair.publicKey, payer.publicKey);
  192. console.log(`Owner Token Address: ${fromAssociatedTokenAddress}`);
  193. const toAssociatedTokenAddress = await getAssociatedTokenAddress(tokenMintKeypair.publicKey, recipientWallet.publicKey);
  194. console.log(`Recipient Token Address: ${toAssociatedTokenAddress}`);
  195. const transferToInstructionData = new TransferTokensArgs({
  196. instruction: MyInstruction.TransferTokens,
  197. quantity: new BN(15),
  198. });
  199. const ix = new TransactionInstruction({
  200. keys: [
  201. {
  202. pubkey: tokenMintKeypair.publicKey,
  203. isSigner: false,
  204. isWritable: true,
  205. }, // Mint account
  206. {
  207. pubkey: fromAssociatedTokenAddress,
  208. isSigner: false,
  209. isWritable: true,
  210. }, // Owner Token account
  211. { pubkey: toAssociatedTokenAddress, isSigner: false, isWritable: true }, // Recipient Token account
  212. { pubkey: payer.publicKey, isSigner: true, isWritable: true }, // Owner
  213. { pubkey: recipientWallet.publicKey, isSigner: true, isWritable: true }, // Recipient
  214. { pubkey: payer.publicKey, isSigner: true, isWritable: true }, // Payer
  215. { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }, // System program
  216. { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, // Token program
  217. {
  218. pubkey: ASSOCIATED_TOKEN_PROGRAM_ID,
  219. isSigner: false,
  220. isWritable: false,
  221. }, // Associated token program
  222. ],
  223. programId: program.publicKey,
  224. data: transferToInstructionData.toBuffer(),
  225. });
  226. await sendAndConfirmTransaction(connection, new Transaction().add(ix), [payer, recipientWallet], { skipPreflight: true });
  227. });
  228. it('Transfer NFT to another wallet!', async () => {
  229. const fromAssociatedTokenAddress = await getAssociatedTokenAddress(nftMintKeypair.publicKey, payer.publicKey);
  230. console.log(`Owner Token Address: ${fromAssociatedTokenAddress}`);
  231. const toAssociatedTokenAddress = await getAssociatedTokenAddress(nftMintKeypair.publicKey, recipientWallet.publicKey);
  232. console.log(`Recipient Token Address: ${toAssociatedTokenAddress}`);
  233. const transferToInstructionData = new TransferTokensArgs({
  234. instruction: MyInstruction.TransferTokens,
  235. quantity: new BN(1),
  236. });
  237. const ix = new TransactionInstruction({
  238. keys: [
  239. { pubkey: nftMintKeypair.publicKey, isSigner: false, isWritable: true }, // Mint account
  240. {
  241. pubkey: fromAssociatedTokenAddress,
  242. isSigner: false,
  243. isWritable: true,
  244. }, // Owner Token account
  245. { pubkey: toAssociatedTokenAddress, isSigner: false, isWritable: true }, // Recipient Token account
  246. { pubkey: payer.publicKey, isSigner: true, isWritable: true }, // Owner
  247. { pubkey: recipientWallet.publicKey, isSigner: true, isWritable: true }, // Recipient
  248. { pubkey: payer.publicKey, isSigner: true, isWritable: true }, // Payer
  249. { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }, // System program
  250. { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, // Token program
  251. {
  252. pubkey: ASSOCIATED_TOKEN_PROGRAM_ID,
  253. isSigner: false,
  254. isWritable: false,
  255. }, // Associated token program
  256. ],
  257. programId: program.publicKey,
  258. data: transferToInstructionData.toBuffer(),
  259. });
  260. await sendAndConfirmTransaction(connection, new Transaction().add(ix), [payer, recipientWallet], { skipPreflight: true });
  261. });
  262. });