main.test.ts 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. import { Keypair, PublicKey, SystemProgram, Transaction, TransactionInstruction } from '@solana/web3.js';
  2. import * as borsh from 'borsh';
  3. import { assert } from 'chai';
  4. import { describe, it } from 'mocha';
  5. import { BanksClient, ProgramTestContext, start } from 'solana-bankrun';
  6. describe('counter program', async () => {
  7. const PROGRAM_ID = new PublicKey('z7msBPQHDJjTvdQRoEcKyENgXDhSRYeHieN1ZMTqo35');
  8. let context: ProgramTestContext;
  9. let client: BanksClient;
  10. let payer: Keypair;
  11. before(async () => {
  12. context = await start([{ name: 'counter_program', programId: PROGRAM_ID }], []);
  13. client = context.banksClient;
  14. payer = context.payer;
  15. });
  16. it('initialize and increment the counter', async () => {
  17. // derive the counter PDA
  18. const [counterPDA] = PublicKey.findProgramAddressSync(
  19. [Buffer.from('counter')], // seed
  20. PROGRAM_ID,
  21. );
  22. const instructionDiscriminators = {
  23. initialize: Buffer.from([0]),
  24. increment: Buffer.from([1]),
  25. };
  26. // create the initialize instruction
  27. const initializeIx = new TransactionInstruction({
  28. programId: PROGRAM_ID,
  29. keys: [
  30. { pubkey: payer.publicKey, isSigner: true, isWritable: true },
  31. { pubkey: counterPDA, isSigner: false, isWritable: true },
  32. { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
  33. ],
  34. data: instructionDiscriminators.initialize,
  35. });
  36. // send the initialize transaction
  37. const initializeTx = new Transaction();
  38. initializeTx.recentBlockhash = context.lastBlockhash;
  39. initializeTx.add(initializeIx).sign(payer);
  40. // process the transaction
  41. await client.processTransaction(initializeTx);
  42. // fetch the counter account data
  43. const accountInfo = await client.getAccount(counterPDA);
  44. assert(accountInfo !== null, 'counter account should exist');
  45. // define the counter schema
  46. const counterSchema: borsh.Schema = {
  47. struct: { discriminator: 'u64', value: 'u64' },
  48. };
  49. // deserialize the counter account data
  50. const counterData = borsh.deserialize(counterSchema, accountInfo?.data) as {
  51. value: bigint;
  52. };
  53. // check the counter value is 0
  54. assert(counterData.value === BigInt(0), 'counter value should be 0');
  55. // increment (must be a number between 0 and 255)
  56. const amount = BigInt(42);
  57. const amountBuffer = Buffer.alloc(8);
  58. amountBuffer.writeBigUInt64LE(amount);
  59. // data for the increment instruction
  60. const incrementData = Buffer.concat([instructionDiscriminators.increment, amountBuffer]);
  61. // create the increment instruction
  62. const incrementIx = new TransactionInstruction({
  63. programId: PROGRAM_ID,
  64. keys: [
  65. { pubkey: payer.publicKey, isSigner: true, isWritable: true },
  66. { pubkey: counterPDA, isSigner: false, isWritable: true },
  67. ],
  68. data: incrementData,
  69. });
  70. // send the increment transaction
  71. const incrementTx = new Transaction();
  72. incrementTx.recentBlockhash = context.lastBlockhash;
  73. incrementTx.add(incrementIx).sign(payer);
  74. // process the transaction
  75. await client.processTransaction(incrementTx);
  76. // fetch the counter account data
  77. const updatedAccountInfo = await client.getAccount(counterPDA);
  78. assert(updatedAccountInfo !== null, 'counter account should exist');
  79. // deserialize the updated counter account data
  80. const updatedCounterData = borsh.deserialize(counterSchema, updatedAccountInfo?.data) as { value: bigint };
  81. assert(updatedCounterData.value === BigInt(amount), `counter value should be ${amount} but we got ${updatedCounterData.value}`);
  82. });
  83. });