test.ts 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. import { describe, test } from 'mocha';
  2. import { assert, expect } from 'chai';
  3. import { Blockhash, Keypair, PublicKey, SystemProgram, Transaction, TransactionInstruction } from '@solana/web3.js';
  4. import { BanksClient, ProgramTestContext, Rent, start , } from 'solana-bankrun';
  5. import { BN } from 'bn.js';
  6. import * as borsh from "borsh"
  7. // This is a helper class to assign properties to the class
  8. class Assignable {
  9. constructor(properties) {
  10. for (const [key, value] of Object.entries(properties)) {
  11. this[key] = value;
  12. }
  13. }
  14. }
  15. enum MyInstruction {
  16. CreateFav = 0,
  17. GetFav = 1,
  18. }
  19. class CreateFav extends Assignable {
  20. number: number;
  21. instruction: MyInstruction;
  22. color: string;
  23. hobbies: string[];
  24. toBuffer() {
  25. return Buffer.from(borsh.serialize(CreateNewAccountSchema, this));
  26. }
  27. static fromBuffer(buffer: Buffer): CreateFav {
  28. return borsh.deserialize({
  29. struct: {
  30. number: "u64",
  31. color: "string",
  32. hobbies: {
  33. array: {
  34. type: "string"
  35. }
  36. }
  37. }}, buffer) as CreateFav;
  38. }
  39. }
  40. const CreateNewAccountSchema = {
  41. "struct": {
  42. instruction: "u8",
  43. number: "u64",
  44. color: "string",
  45. hobbies: {
  46. array: {
  47. type: "string"
  48. }
  49. }
  50. }
  51. }
  52. class GetFav extends Assignable {
  53. toBuffer() {
  54. return Buffer.from(borsh.serialize(GetFavSchema, this));
  55. }
  56. }
  57. const GetFavSchema = {
  58. "struct": {
  59. instruction: "u8"
  60. }
  61. }
  62. describe('Favorites Solana Native', () => {
  63. // Randomly generate the program keypair and load the program to solana-bankrun
  64. const programId = PublicKey.unique();
  65. let context: ProgramTestContext, client:BanksClient, payer: Keypair, blockhash: Blockhash;
  66. beforeEach(async () => {
  67. context = await start([{ name: 'favorites_native', programId }], []);
  68. client = context.banksClient;
  69. // Get the payer keypair from the context, this will be used to sign transactions with enough lamports
  70. payer = context.payer;
  71. blockhash = context.lastBlockhash;
  72. })
  73. test('Set the favorite pda and cross-check the updated data', async () => {
  74. const favoritesPda = PublicKey.findProgramAddressSync([Buffer.from("favorite"), payer.publicKey.toBuffer()], programId)[0];
  75. const favData = {instruction: MyInstruction.CreateFav, number: 42, color: "blue", hobbies: ["coding", "reading", "traveling"]}
  76. const favorites = new CreateFav(favData);
  77. const ix = new TransactionInstruction({
  78. keys: [
  79. {pubkey: payer.publicKey, isSigner: true, isWritable: true},
  80. {pubkey: favoritesPda, isSigner: false, isWritable: true},
  81. {pubkey: SystemProgram.programId, isSigner: false, isWritable: false}],
  82. programId,
  83. data: favorites.toBuffer(),
  84. });
  85. const tx = new Transaction().add(ix);
  86. tx.feePayer = payer.publicKey;
  87. tx.recentBlockhash = blockhash
  88. tx.sign(payer)
  89. tx.recentBlockhash = blockhash;
  90. await client.processTransaction(tx);
  91. const account = await client.getAccount(favoritesPda);
  92. const data = Buffer.from(account.data);
  93. const favoritesData = CreateFav.fromBuffer(data);
  94. console.log("Deserialized data:", favoritesData);
  95. expect(new BN(favoritesData.number as any, 'le').toNumber()).to.equal(favData.number);
  96. expect(favoritesData.color).to.equal(favData.color);
  97. expect(favoritesData.hobbies).to.deep.equal(favData.hobbies);
  98. });
  99. test('Check if the test fails if the pda seeds aren\'t same', async () => {
  100. // We put the wrong seeds knowingly to see if the test fails because of checks
  101. const favoritesPda = PublicKey.findProgramAddressSync([Buffer.from("favorite"), payer.publicKey.toBuffer()], programId)[0];
  102. const favData = {instruction: MyInstruction.CreateFav, number: 42, color: "blue", hobbies: ["coding", "reading", "traveling"]}
  103. const favorites = new CreateFav(favData);
  104. const ix = new TransactionInstruction({
  105. keys: [{pubkey: payer.publicKey, isSigner: true, isWritable: true}, {pubkey: favoritesPda, isSigner: false, isWritable: true}, {pubkey: SystemProgram.programId, isSigner: false, isWritable: false}],
  106. programId,
  107. data: favorites.toBuffer(),
  108. });
  109. const tx = new Transaction().add(ix);
  110. tx.feePayer = payer.publicKey;
  111. tx.recentBlockhash = blockhash
  112. tx.sign(payer)
  113. tx.recentBlockhash = blockhash;
  114. try {
  115. await client.processTransaction(tx)
  116. console.error("Expected the test to fail")
  117. } catch(err) {
  118. assert(true)
  119. }
  120. });
  121. test('Get the favorite pda and cross-check the data', async () => {
  122. // Creating a new account with payer's pubkey
  123. const favoritesPda = PublicKey.findProgramAddressSync([Buffer.from("favorite"), payer.publicKey.toBuffer()], programId)[0];
  124. const favData = {instruction: MyInstruction.CreateFav, number: 42, color: "hazel", hobbies: ["singing", "dancing", "skydiving"]}
  125. const favorites = new CreateFav(favData);
  126. const ix = new TransactionInstruction({
  127. keys: [
  128. {pubkey: payer.publicKey, isSigner: true, isWritable: true},
  129. {pubkey: favoritesPda, isSigner: false, isWritable: true},
  130. {pubkey: SystemProgram.programId, isSigner: false, isWritable: false}],
  131. programId,
  132. data: favorites.toBuffer(),
  133. });
  134. const tx1 = new Transaction().add(ix);
  135. tx1.feePayer = payer.publicKey;
  136. tx1.recentBlockhash = blockhash
  137. tx1.sign(payer)
  138. tx1.recentBlockhash = blockhash;
  139. await client.processTransaction(tx1)
  140. // Getting the user's data through the get_pda instruction
  141. const getfavData = {instruction: MyInstruction.GetFav}
  142. const getfavorites = new GetFav(getfavData);
  143. const ix2 = new TransactionInstruction({
  144. keys: [{pubkey: payer.publicKey, isSigner: true, isWritable: true}, {pubkey: favoritesPda, isSigner: false, isWritable: false}],
  145. programId,
  146. data:getfavorites.toBuffer(),
  147. });
  148. const tx = new Transaction().add(ix2);
  149. tx.feePayer = payer.publicKey;
  150. tx.recentBlockhash = blockhash
  151. tx.sign(payer)
  152. tx.recentBlockhash = blockhash;
  153. await client.processTransaction(tx);
  154. })
  155. })