utils.ts 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. import {
  2. MINT_SIZE,
  3. TOKEN_PROGRAM_ID,
  4. createAssociatedTokenAccountInstruction,
  5. createInitializeMint2Instruction,
  6. createMintToInstruction,
  7. getAssociatedTokenAddressSync,
  8. } from '@solana/spl-token';
  9. import { Keypair, LAMPORTS_PER_SOL, PublicKey, SystemProgram, Transaction } from '@solana/web3.js';
  10. import * as borsh from 'borsh';
  11. import { ProgramTestContext } from 'solana-bankrun';
  12. export const instructionDiscriminators = {
  13. CreateAmm: Buffer.from([0]),
  14. CreatePool: Buffer.from([1]),
  15. DepositLiquidity: Buffer.from([2]),
  16. WithdrawLiquidity: Buffer.from([3]),
  17. Swap: Buffer.from([4]),
  18. };
  19. export const getCreatePoolInstructionData = () => {
  20. return Buffer.concat([instructionDiscriminators.CreatePool]);
  21. };
  22. export const encodeBigint = (value: bigint) => {
  23. const buffer = Buffer.alloc(8);
  24. buffer.writeBigUInt64LE(value);
  25. return Uint8Array.from(buffer);
  26. };
  27. export const getDepositLiquidityInstructionData = (amountA: bigint, amountB: bigint) => {
  28. return Buffer.concat([instructionDiscriminators.DepositLiquidity, encodeBigint(amountA), encodeBigint(amountB)]);
  29. };
  30. export const getWithdrawLiquidityInstructionData = (amountLp: bigint) => {
  31. return Buffer.concat([instructionDiscriminators.WithdrawLiquidity, encodeBigint(amountLp)]);
  32. };
  33. export const getSwapInstructionData = (swapA: boolean, inputAmount: bigint, minimunAmountOut: bigint) => {
  34. return Buffer.concat([instructionDiscriminators.Swap, Buffer.from([swapA ? 1 : 0]), encodeBigint(inputAmount), encodeBigint(minimunAmountOut)]);
  35. };
  36. export const getCreateAmmInstructionData = (id: PublicKey, fee: number) => {
  37. const buffer = Buffer.alloc(2);
  38. buffer.writeUint16LE(fee, 0);
  39. return Buffer.concat([instructionDiscriminators.CreateAmm, id.toBuffer(), Buffer.from(buffer)]);
  40. };
  41. export const createAMint = async (context: ProgramTestContext, payer: Keypair, mint: Keypair) => {
  42. const tx = new Transaction();
  43. tx.add(
  44. SystemProgram.createAccount({
  45. fromPubkey: payer.publicKey,
  46. newAccountPubkey: mint.publicKey,
  47. // the `space` required for a token mint is accessible in the `@solana/spl-token` sdk
  48. space: MINT_SIZE,
  49. // store enough lamports needed for our `space` to be rent exempt
  50. lamports: Number((await context.banksClient.getRent()).minimumBalance(BigInt(MINT_SIZE))),
  51. // tokens are owned by the "token program"
  52. programId: TOKEN_PROGRAM_ID,
  53. }),
  54. createInitializeMint2Instruction(mint.publicKey, 9, payer.publicKey, payer.publicKey),
  55. );
  56. tx.recentBlockhash = context.lastBlockhash;
  57. tx.sign(payer, mint);
  58. // process the transaction
  59. await context.banksClient.processTransaction(tx);
  60. };
  61. export const mintTo = async (context: ProgramTestContext, payer: Keypair, owner: PublicKey, mint: PublicKey) => {
  62. const tokenAccount = getAssociatedTokenAddressSync(mint, owner, false);
  63. const tx = new Transaction();
  64. tx.add(
  65. createAssociatedTokenAccountInstruction(payer.publicKey, tokenAccount, owner, mint),
  66. createMintToInstruction(mint, tokenAccount, payer.publicKey, 1_000 * LAMPORTS_PER_SOL),
  67. );
  68. tx.recentBlockhash = context.lastBlockhash;
  69. tx.sign(payer);
  70. // process the transaction
  71. await context.banksClient.processTransaction(tx);
  72. return tokenAccount;
  73. };
  74. // Define AmmAccount type
  75. export type AmmAccount = {
  76. id: PublicKey;
  77. admin: PublicKey;
  78. fee: number;
  79. };
  80. // Define DataAccountRaw type for deserialization
  81. export type AmmAccountRaw = {
  82. id: Uint8Array;
  83. admin: Uint8Array;
  84. fee: number;
  85. };
  86. // Define the schema for the account data
  87. export const ammAccountSchema: borsh.Schema = {
  88. struct: {
  89. discriminator: 'u64',
  90. id: { array: { type: 'u8', len: 32 } },
  91. admin: { array: { type: 'u8', len: 32 } },
  92. fee: 'u16',
  93. },
  94. };
  95. export const deserializeAmmAccount = (data: Uint8Array): AmmAccount => {
  96. const account = borsh.deserialize(ammAccountSchema, data) as AmmAccountRaw;
  97. return {
  98. id: new PublicKey(account.id),
  99. admin: new PublicKey(account.admin),
  100. fee: account.fee,
  101. };
  102. };
  103. // Define AmmAccount type
  104. export type PoolAccount = {
  105. amm: PublicKey;
  106. mintA: PublicKey;
  107. mintB: PublicKey;
  108. };
  109. // Define DataAccountRaw type for deserialization
  110. export type PoolAccountRaw = {
  111. amm: Uint8Array;
  112. mint_a: Uint8Array;
  113. mint_b: Uint8Array;
  114. };
  115. // Define the schema for the account data
  116. export const poolAccountSchema: borsh.Schema = {
  117. struct: {
  118. discriminator: 'u64',
  119. amm: { array: { type: 'u8', len: 32 } },
  120. mint_a: { array: { type: 'u8', len: 32 } },
  121. mint_b: { array: { type: 'u8', len: 32 } },
  122. },
  123. };
  124. export const deserializePoolAccount = (data: Uint8Array): PoolAccount => {
  125. const account = borsh.deserialize(poolAccountSchema, data) as PoolAccountRaw;
  126. return {
  127. amm: new PublicKey(account.amm),
  128. mintA: new PublicKey(account.mint_a),
  129. mintB: new PublicKey(account.mint_b),
  130. };
  131. };