addressInfo.test.ts 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. import { Keypair, PublicKey, SystemProgram, Transaction, TransactionInstruction } from '@solana/web3.js';
  2. import * as borsh from 'borsh';
  3. import { expect } from 'chai';
  4. import { BanksClient, ProgramTestContext, start } from 'solana-bankrun';
  5. // Constants for program identification
  6. const PROGRAM_ID = new PublicKey('Dw6Yq7TZSHdaqB2nKjsxuDrdp5xYCuZaVKFZb5vp5Y4Y');
  7. const ADDRESS_INFO_SEED = 'address_info';
  8. // Instruction discriminators
  9. const INSTRUCTION_DISCRIMINATORS = {
  10. createAddressInfo: Buffer.from([0]),
  11. };
  12. // Type definitions
  13. interface AddressInfoData {
  14. name: string;
  15. houseNumber: bigint;
  16. street: string;
  17. city: string;
  18. }
  19. interface AddressInfoDataRaw {
  20. name: Uint8Array;
  21. houseNumber: bigint;
  22. street: Uint8Array;
  23. city: Uint8Array;
  24. }
  25. interface AddressInfoAccount {
  26. data: AddressInfoData;
  27. }
  28. interface AddressInfoAccountRaw {
  29. data: AddressInfoDataRaw;
  30. }
  31. // Borsh schema definition
  32. const ADDRESS_INFO_SCHEMA: borsh.Schema = {
  33. struct: {
  34. discriminator: 'u64',
  35. data: {
  36. struct: {
  37. name: { array: { type: 'u8', len: 64 } },
  38. houseNumber: 'u64',
  39. street: { array: { type: 'u8', len: 64 } },
  40. city: { array: { type: 'u8', len: 64 } },
  41. },
  42. },
  43. },
  44. };
  45. // Helper functions
  46. const stringToFixedBytes = (str: string, length: number): Uint8Array => {
  47. const buffer = Buffer.alloc(length, 0);
  48. buffer.write(str, 'utf-8');
  49. return Uint8Array.from(buffer);
  50. };
  51. const fixedBytesToString = (data: Uint8Array): string => {
  52. return Buffer.from(data).toString('utf-8').replace(/\0/g, '');
  53. };
  54. const bigIntToBytes = (value: bigint): Uint8Array => {
  55. const buffer = Buffer.alloc(8);
  56. buffer.writeBigUInt64LE(value, 0);
  57. return Uint8Array.from(buffer);
  58. };
  59. const serializeAddressInfo = (data: AddressInfoData): Buffer => {
  60. return Buffer.concat([
  61. stringToFixedBytes(data.name, 64),
  62. bigIntToBytes(data.houseNumber),
  63. stringToFixedBytes(data.street, 64),
  64. stringToFixedBytes(data.city, 64),
  65. ]);
  66. };
  67. const deserializeAddressInfo = (raw: AddressInfoAccountRaw): AddressInfoAccount => {
  68. return {
  69. data: {
  70. name: fixedBytesToString(raw.data.name),
  71. houseNumber: raw.data.houseNumber,
  72. street: fixedBytesToString(raw.data.street),
  73. city: fixedBytesToString(raw.data.city),
  74. },
  75. };
  76. };
  77. describe('Address Info Program', () => {
  78. let context: ProgramTestContext;
  79. let client: BanksClient;
  80. let payer: Keypair;
  81. let addressInfoPda: PublicKey;
  82. before(async () => {
  83. // Initialize program test environment
  84. context = await start([{ name: 'account_data_program', programId: PROGRAM_ID }], []);
  85. client = context.banksClient;
  86. payer = context.payer;
  87. // Derive program PDA
  88. [addressInfoPda] = PublicKey.findProgramAddressSync([Buffer.from(ADDRESS_INFO_SEED)], PROGRAM_ID);
  89. });
  90. describe('create_address_info', () => {
  91. it('successfully creates and initializes an address info account', async () => {
  92. // Test data
  93. const addressInfo = {
  94. name: 'Joe C',
  95. houseNumber: BigInt(136),
  96. street: 'Mile High Dr.',
  97. city: 'Solana Beach',
  98. };
  99. // Create and send transaction
  100. const tx = new Transaction().add(
  101. new TransactionInstruction({
  102. programId: PROGRAM_ID,
  103. keys: [
  104. { pubkey: payer.publicKey, isSigner: true, isWritable: true },
  105. { pubkey: addressInfoPda, isSigner: false, isWritable: true },
  106. { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
  107. ],
  108. data: Buffer.concat([INSTRUCTION_DISCRIMINATORS.createAddressInfo, serializeAddressInfo(addressInfo)]),
  109. }),
  110. );
  111. tx.recentBlockhash = context.lastBlockhash;
  112. tx.sign(payer);
  113. await client.processTransaction(tx);
  114. // Verify account data
  115. const account = await client.getAccount(addressInfoPda);
  116. expect(account).to.not.be.null;
  117. const accountData = borsh.deserialize(ADDRESS_INFO_SCHEMA, account?.data) as AddressInfoAccountRaw;
  118. const deserializedData = deserializeAddressInfo(accountData);
  119. // Verify each field
  120. expect(deserializedData.data.name).to.equal(addressInfo.name);
  121. expect(deserializedData.data.houseNumber).to.equal(addressInfo.houseNumber);
  122. expect(deserializedData.data.street).to.equal(addressInfo.street);
  123. expect(deserializedData.data.city).to.equal(addressInfo.city);
  124. });
  125. });
  126. });