_setup.ts 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. import { getCreateAccountInstruction } from '@solana-program/system';
  2. import {
  3. Address,
  4. Commitment,
  5. CompilableTransactionMessage,
  6. Rpc,
  7. RpcSubscriptions,
  8. SolanaRpcApi,
  9. SolanaRpcSubscriptionsApi,
  10. TransactionMessageWithBlockhashLifetime,
  11. TransactionSigner,
  12. airdropFactory,
  13. appendTransactionMessageInstructions,
  14. createSolanaRpc,
  15. createSolanaRpcSubscriptions,
  16. createTransactionMessage,
  17. generateKeyPairSigner,
  18. getSignatureFromTransaction,
  19. lamports,
  20. pipe,
  21. sendAndConfirmTransactionFactory,
  22. setTransactionMessageFeePayerSigner,
  23. setTransactionMessageLifetimeUsingBlockhash,
  24. signTransactionMessageWithSigners,
  25. } from '@solana/web3.js';
  26. import {
  27. TOKEN_PROGRAM_ADDRESS,
  28. getInitializeAccountInstruction,
  29. getInitializeMintInstruction,
  30. getMintSize,
  31. getTokenSize,
  32. } from '../src/index.js';
  33. type Client = {
  34. rpc: Rpc<SolanaRpcApi>;
  35. rpcSubscriptions: RpcSubscriptions<SolanaRpcSubscriptionsApi>;
  36. };
  37. export const createDefaultSolanaClient = (): Client => {
  38. const rpc = createSolanaRpc('http://127.0.0.1:8899');
  39. const rpcSubscriptions = createSolanaRpcSubscriptions('ws://127.0.0.1:8900');
  40. return { rpc, rpcSubscriptions };
  41. };
  42. export const generateKeyPairSignerWithSol = async (
  43. client: Client,
  44. putativeLamports: bigint = 1_000_000_000n
  45. ) => {
  46. const signer = await generateKeyPairSigner();
  47. await airdropFactory(client)({
  48. recipientAddress: signer.address,
  49. lamports: lamports(putativeLamports),
  50. commitment: 'confirmed',
  51. });
  52. return signer;
  53. };
  54. export const createDefaultTransaction = async (
  55. client: Client,
  56. feePayer: TransactionSigner
  57. ) => {
  58. const { value: latestBlockhash } = await client.rpc
  59. .getLatestBlockhash()
  60. .send();
  61. return pipe(
  62. createTransactionMessage({ version: 0 }),
  63. (tx) => setTransactionMessageFeePayerSigner(feePayer, tx),
  64. (tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx)
  65. );
  66. };
  67. export const signAndSendTransaction = async (
  68. client: Client,
  69. transactionMessage: CompilableTransactionMessage &
  70. TransactionMessageWithBlockhashLifetime,
  71. commitment: Commitment = 'confirmed'
  72. ) => {
  73. const signedTransaction =
  74. await signTransactionMessageWithSigners(transactionMessage);
  75. const signature = getSignatureFromTransaction(signedTransaction);
  76. await sendAndConfirmTransactionFactory(client)(signedTransaction, {
  77. commitment,
  78. });
  79. return signature;
  80. };
  81. export const getBalance = async (client: Client, address: Address) =>
  82. (await client.rpc.getBalance(address, { commitment: 'confirmed' }).send())
  83. .value;
  84. export const createMint = async (
  85. client: Client,
  86. payer: TransactionSigner,
  87. mintAuthority: Address,
  88. decimals: number = 0
  89. ): Promise<Address> => {
  90. const space = BigInt(getMintSize());
  91. const [transactionMessage, rent, mint] = await Promise.all([
  92. createDefaultTransaction(client, payer),
  93. client.rpc.getMinimumBalanceForRentExemption(space).send(),
  94. generateKeyPairSigner(),
  95. ]);
  96. const instructions = [
  97. getCreateAccountInstruction({
  98. payer,
  99. newAccount: mint,
  100. lamports: rent,
  101. space,
  102. programAddress: TOKEN_PROGRAM_ADDRESS,
  103. }),
  104. getInitializeMintInstruction({
  105. mint: mint.address,
  106. decimals,
  107. mintAuthority,
  108. }),
  109. ];
  110. await pipe(
  111. transactionMessage,
  112. (tx) => appendTransactionMessageInstructions(instructions, tx),
  113. (tx) => signAndSendTransaction(client, tx)
  114. );
  115. return mint.address;
  116. };
  117. export const createToken = async (
  118. client: Client,
  119. payer: TransactionSigner,
  120. mint: Address,
  121. owner: Address
  122. ): Promise<Address> => {
  123. const space = BigInt(getTokenSize());
  124. const [transactionMessage, rent, token] = await Promise.all([
  125. createDefaultTransaction(client, payer),
  126. client.rpc.getMinimumBalanceForRentExemption(space).send(),
  127. generateKeyPairSigner(),
  128. ]);
  129. const instructions = [
  130. getCreateAccountInstruction({
  131. payer,
  132. newAccount: token,
  133. lamports: rent,
  134. space,
  135. programAddress: TOKEN_PROGRAM_ADDRESS,
  136. }),
  137. getInitializeAccountInstruction({ account: token.address, mint, owner }),
  138. ];
  139. await pipe(
  140. transactionMessage,
  141. (tx) => appendTransactionMessageInstructions(instructions, tx),
  142. (tx) => signAndSendTransaction(client, tx)
  143. );
  144. return token.address;
  145. };