test.ts 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. import { Buffer } from 'node:buffer';
  2. import { describe, test } from 'node:test';
  3. import { Keypair, PublicKey, SystemProgram, Transaction, TransactionInstruction } from '@solana/web3.js';
  4. import * as borsh from 'borsh';
  5. import { start } from 'solana-bankrun';
  6. describe('PDAs', async () => {
  7. const PROGRAM_ID = PublicKey.unique();
  8. const context = await start([{ name: 'program_derived_addresses_program', programId: PROGRAM_ID }], []);
  9. const client = context.banksClient;
  10. const payer = context.payer;
  11. const rent = await client.getRent();
  12. class Assignable {
  13. constructor(properties) {
  14. for (const [key, value] of Object.entries(properties)) {
  15. this[key] = value;
  16. }
  17. }
  18. }
  19. class PageVisits extends Assignable {
  20. toBuffer() {
  21. return Buffer.from(borsh.serialize(PageVisitsSchema, this));
  22. }
  23. static fromBuffer(buffer: Buffer) {
  24. return borsh.deserialize(PageVisitsSchema, PageVisits, buffer);
  25. }
  26. }
  27. const PageVisitsSchema = new Map([
  28. [
  29. PageVisits,
  30. {
  31. kind: 'struct',
  32. fields: [
  33. ['page_visits', 'u32'],
  34. ['bump', 'u8'],
  35. ],
  36. },
  37. ],
  38. ]);
  39. class IncrementPageVisits extends Assignable {
  40. toBuffer() {
  41. return Buffer.from(borsh.serialize(IncrementPageVisitsSchema, this));
  42. }
  43. }
  44. const IncrementPageVisitsSchema = new Map([
  45. [
  46. IncrementPageVisits,
  47. {
  48. kind: 'struct',
  49. fields: [],
  50. },
  51. ],
  52. ]);
  53. const testUser = Keypair.generate();
  54. test('Create a test user', async () => {
  55. const ix = SystemProgram.createAccount({
  56. fromPubkey: payer.publicKey,
  57. lamports: Number(rent.minimumBalance(BigInt(0))),
  58. newAccountPubkey: testUser.publicKey,
  59. programId: SystemProgram.programId,
  60. space: 0,
  61. });
  62. const tx = new Transaction();
  63. const blockhash = context.lastBlockhash;
  64. tx.recentBlockhash = blockhash;
  65. tx.add(ix).sign(payer, testUser); // Add instruction and Sign the transaction
  66. await client.processTransaction(tx);
  67. console.log(`Local Wallet: ${payer.publicKey}`);
  68. console.log(`Created User: ${testUser.publicKey}`);
  69. });
  70. function derivePageVisitsPda(userPubkey: PublicKey) {
  71. return PublicKey.findProgramAddressSync([Buffer.from('page_visits'), userPubkey.toBuffer()], PROGRAM_ID);
  72. }
  73. test('Create the page visits tracking PDA', async () => {
  74. const [pageVisitsPda, pageVisitsBump] = derivePageVisitsPda(testUser.publicKey);
  75. const ix = new TransactionInstruction({
  76. keys: [
  77. { pubkey: pageVisitsPda, isSigner: false, isWritable: true },
  78. { pubkey: testUser.publicKey, isSigner: false, isWritable: false },
  79. { pubkey: payer.publicKey, isSigner: true, isWritable: true },
  80. { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
  81. ],
  82. programId: PROGRAM_ID,
  83. data: new PageVisits({ page_visits: 0, bump: pageVisitsBump }).toBuffer(),
  84. });
  85. const tx = new Transaction();
  86. const blockhash = context.lastBlockhash;
  87. tx.recentBlockhash = blockhash;
  88. tx.add(ix).sign(payer);
  89. await client.processTransaction(tx);
  90. });
  91. test('Visit the page!', async () => {
  92. const [pageVisitsPda, _] = derivePageVisitsPda(testUser.publicKey);
  93. const ix = new TransactionInstruction({
  94. keys: [
  95. { pubkey: pageVisitsPda, isSigner: false, isWritable: true },
  96. { pubkey: payer.publicKey, isSigner: true, isWritable: true },
  97. ],
  98. programId: PROGRAM_ID,
  99. data: new IncrementPageVisits({}).toBuffer(),
  100. });
  101. const tx = new Transaction();
  102. const blockhash = context.lastBlockhash;
  103. tx.recentBlockhash = blockhash;
  104. tx.add(ix).sign(payer);
  105. await client.processTransaction(tx);
  106. });
  107. // commented because couldn't get different blockhash
  108. test('Visit the page!', async () => {
  109. const [pageVisitsPda, _] = derivePageVisitsPda(testUser.publicKey);
  110. const ix = new TransactionInstruction({
  111. keys: [
  112. { pubkey: pageVisitsPda, isSigner: false, isWritable: true },
  113. { pubkey: payer.publicKey, isSigner: true, isWritable: true },
  114. ],
  115. programId: PROGRAM_ID,
  116. data: new IncrementPageVisits({}).toBuffer(),
  117. });
  118. const tx = new Transaction();
  119. const [blockhash, _block_height] = await client.getLatestBlockhash();
  120. tx.recentBlockhash = blockhash;
  121. tx.add(ix).sign(payer);
  122. await client.processTransaction(tx);
  123. });
  124. test('Read page visits', async () => {
  125. const [pageVisitsPda, _] = derivePageVisitsPda(testUser.publicKey);
  126. const accountInfo = await client.getAccount(pageVisitsPda);
  127. const readPageVisits = PageVisits.fromBuffer(Buffer.from(accountInfo.data));
  128. console.log(`Number of page visits: ${readPageVisits.page_visits}`);
  129. });
  130. });