_setup.ts 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  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. getMintToInstruction,
  32. getTokenSize,
  33. } from '../src';
  34. type Client = {
  35. rpc: Rpc<SolanaRpcApi>;
  36. rpcSubscriptions: RpcSubscriptions<SolanaRpcSubscriptionsApi>;
  37. };
  38. export const createDefaultSolanaClient = (): Client => {
  39. const rpc = createSolanaRpc('http://127.0.0.1:8899');
  40. const rpcSubscriptions = createSolanaRpcSubscriptions('ws://127.0.0.1:8900');
  41. return { rpc, rpcSubscriptions };
  42. };
  43. export const generateKeyPairSignerWithSol = async (
  44. client: Client,
  45. putativeLamports: bigint = 1_000_000_000n
  46. ) => {
  47. const signer = await generateKeyPairSigner();
  48. await airdropFactory(client)({
  49. recipientAddress: signer.address,
  50. lamports: lamports(putativeLamports),
  51. commitment: 'confirmed',
  52. });
  53. return signer;
  54. };
  55. export const createDefaultTransaction = async (
  56. client: Client,
  57. feePayer: TransactionSigner
  58. ) => {
  59. const { value: latestBlockhash } = await client.rpc
  60. .getLatestBlockhash()
  61. .send();
  62. return pipe(
  63. createTransactionMessage({ version: 0 }),
  64. (tx) => setTransactionMessageFeePayerSigner(feePayer, tx),
  65. (tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx)
  66. );
  67. };
  68. export const signAndSendTransaction = async (
  69. client: Client,
  70. transactionMessage: CompilableTransactionMessage &
  71. TransactionMessageWithBlockhashLifetime,
  72. commitment: Commitment = 'confirmed'
  73. ) => {
  74. const signedTransaction =
  75. await signTransactionMessageWithSigners(transactionMessage);
  76. const signature = getSignatureFromTransaction(signedTransaction);
  77. await sendAndConfirmTransactionFactory(client)(signedTransaction, {
  78. commitment,
  79. });
  80. return signature;
  81. };
  82. export const getBalance = async (client: Client, address: Address) =>
  83. (await client.rpc.getBalance(address, { commitment: 'confirmed' }).send())
  84. .value;
  85. export const createMint = async (
  86. client: Client,
  87. payer: TransactionSigner,
  88. mintAuthority: Address,
  89. decimals: number = 0
  90. ): Promise<Address> => {
  91. const space = BigInt(getMintSize());
  92. const [transactionMessage, rent, mint] = await Promise.all([
  93. createDefaultTransaction(client, payer),
  94. client.rpc.getMinimumBalanceForRentExemption(space).send(),
  95. generateKeyPairSigner(),
  96. ]);
  97. const instructions = [
  98. getCreateAccountInstruction({
  99. payer,
  100. newAccount: mint,
  101. lamports: rent,
  102. space,
  103. programAddress: TOKEN_PROGRAM_ADDRESS,
  104. }),
  105. getInitializeMintInstruction({
  106. mint: mint.address,
  107. decimals,
  108. mintAuthority,
  109. }),
  110. ];
  111. await pipe(
  112. transactionMessage,
  113. (tx) => appendTransactionMessageInstructions(instructions, tx),
  114. (tx) => signAndSendTransaction(client, tx)
  115. );
  116. return mint.address;
  117. };
  118. export const createToken = async (
  119. client: Client,
  120. payer: TransactionSigner,
  121. mint: Address,
  122. owner: Address
  123. ): Promise<Address> => {
  124. const space = BigInt(getTokenSize());
  125. const [transactionMessage, rent, token] = await Promise.all([
  126. createDefaultTransaction(client, payer),
  127. client.rpc.getMinimumBalanceForRentExemption(space).send(),
  128. generateKeyPairSigner(),
  129. ]);
  130. const instructions = [
  131. getCreateAccountInstruction({
  132. payer,
  133. newAccount: token,
  134. lamports: rent,
  135. space,
  136. programAddress: TOKEN_PROGRAM_ADDRESS,
  137. }),
  138. getInitializeAccountInstruction({ account: token.address, mint, owner }),
  139. ];
  140. await pipe(
  141. transactionMessage,
  142. (tx) => appendTransactionMessageInstructions(instructions, tx),
  143. (tx) => signAndSendTransaction(client, tx)
  144. );
  145. return token.address;
  146. };
  147. export const createTokenWithAmount = async (
  148. client: Client,
  149. payer: TransactionSigner,
  150. mintAuthority: TransactionSigner,
  151. mint: Address,
  152. owner: Address,
  153. amount: bigint
  154. ): Promise<Address> => {
  155. const space = BigInt(getTokenSize());
  156. const [transactionMessage, rent, token] = await Promise.all([
  157. createDefaultTransaction(client, payer),
  158. client.rpc.getMinimumBalanceForRentExemption(space).send(),
  159. generateKeyPairSigner(),
  160. ]);
  161. const instructions = [
  162. getCreateAccountInstruction({
  163. payer,
  164. newAccount: token,
  165. lamports: rent,
  166. space,
  167. programAddress: TOKEN_PROGRAM_ADDRESS,
  168. }),
  169. getInitializeAccountInstruction({ account: token.address, mint, owner }),
  170. getMintToInstruction({ mint, token: token.address, mintAuthority, amount }),
  171. ];
  172. await pipe(
  173. transactionMessage,
  174. (tx) => appendTransactionMessageInstructions(instructions, tx),
  175. (tx) => signAndSendTransaction(client, tx)
  176. );
  177. return token.address;
  178. };