_setup.ts 5.3 KB

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