123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149 |
- import { Keypair, PublicKey, SystemProgram, Transaction, TransactionInstruction } from '@solana/web3.js';
- import * as borsh from 'borsh';
- import { expect } from 'chai';
- import { BanksClient, ProgramTestContext, start } from 'solana-bankrun';
- // Constants for program identification
- const PROGRAM_ID = new PublicKey('Dw6Yq7TZSHdaqB2nKjsxuDrdp5xYCuZaVKFZb5vp5Y4Y');
- const ADDRESS_INFO_SEED = 'address_info';
- // Instruction discriminators
- const INSTRUCTION_DISCRIMINATORS = {
- createAddressInfo: Buffer.from([0]),
- };
- // Type definitions
- interface AddressInfoData {
- name: string;
- houseNumber: bigint;
- street: string;
- city: string;
- }
- interface AddressInfoDataRaw {
- name: Uint8Array;
- houseNumber: bigint;
- street: Uint8Array;
- city: Uint8Array;
- }
- interface AddressInfoAccount {
- data: AddressInfoData;
- }
- interface AddressInfoAccountRaw {
- data: AddressInfoDataRaw;
- }
- // Borsh schema definition
- const ADDRESS_INFO_SCHEMA: borsh.Schema = {
- struct: {
- discriminator: 'u64',
- data: {
- struct: {
- name: { array: { type: 'u8', len: 64 } },
- houseNumber: 'u64',
- street: { array: { type: 'u8', len: 64 } },
- city: { array: { type: 'u8', len: 64 } },
- },
- },
- },
- };
- // Helper functions
- const stringToFixedBytes = (str: string, length: number): Uint8Array => {
- const buffer = Buffer.alloc(length, 0);
- buffer.write(str, 'utf-8');
- return Uint8Array.from(buffer);
- };
- const fixedBytesToString = (data: Uint8Array): string => {
- return Buffer.from(data).toString('utf-8').replace(/\0/g, '');
- };
- const bigIntToBytes = (value: bigint): Uint8Array => {
- const buffer = Buffer.alloc(8);
- buffer.writeBigUInt64LE(value, 0);
- return Uint8Array.from(buffer);
- };
- const serializeAddressInfo = (data: AddressInfoData): Buffer => {
- return Buffer.concat([
- stringToFixedBytes(data.name, 64),
- bigIntToBytes(data.houseNumber),
- stringToFixedBytes(data.street, 64),
- stringToFixedBytes(data.city, 64),
- ]);
- };
- const deserializeAddressInfo = (raw: AddressInfoAccountRaw): AddressInfoAccount => {
- return {
- data: {
- name: fixedBytesToString(raw.data.name),
- houseNumber: raw.data.houseNumber,
- street: fixedBytesToString(raw.data.street),
- city: fixedBytesToString(raw.data.city),
- },
- };
- };
- describe('Address Info Program', () => {
- let context: ProgramTestContext;
- let client: BanksClient;
- let payer: Keypair;
- let addressInfoPda: PublicKey;
- before(async () => {
- // Initialize program test environment
- context = await start([{ name: 'account_data_program', programId: PROGRAM_ID }], []);
- client = context.banksClient;
- payer = context.payer;
- // Derive program PDA
- [addressInfoPda] = PublicKey.findProgramAddressSync([Buffer.from(ADDRESS_INFO_SEED)], PROGRAM_ID);
- });
- describe('create_address_info', () => {
- it('successfully creates and initializes an address info account', async () => {
- // Test data
- const addressInfo = {
- name: 'Joe C',
- houseNumber: BigInt(136),
- street: 'Mile High Dr.',
- city: 'Solana Beach',
- };
- // Create and send transaction
- const tx = new Transaction().add(
- new TransactionInstruction({
- programId: PROGRAM_ID,
- keys: [
- { pubkey: payer.publicKey, isSigner: true, isWritable: true },
- { pubkey: addressInfoPda, isSigner: false, isWritable: true },
- { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
- ],
- data: Buffer.concat([INSTRUCTION_DISCRIMINATORS.createAddressInfo, serializeAddressInfo(addressInfo)]),
- }),
- );
- tx.recentBlockhash = context.lastBlockhash;
- tx.sign(payer);
- await client.processTransaction(tx);
- // Verify account data
- const account = await client.getAccount(addressInfoPda);
- expect(account).to.not.be.null;
- const accountData = borsh.deserialize(ADDRESS_INFO_SCHEMA, account?.data) as AddressInfoAccountRaw;
- const deserializedData = deserializeAddressInfo(accountData);
- // Verify each field
- expect(deserializedData.data.name).to.equal(addressInfo.name);
- expect(deserializedData.data.houseNumber).to.equal(addressInfo.houseNumber);
- expect(deserializedData.data.street).to.equal(addressInfo.street);
- expect(deserializedData.data.city).to.equal(addressInfo.city);
- });
- });
- });
|