import assert from 'assert'; import { createHash } from 'crypto'; import { AccountInfo, Connection, GetProgramAccountsFilter, Keypair, PublicKey, Transaction, TransactionInstruction, } from '@solana/web3.js'; import BN from 'bn.js'; import { HASH_PREFIX, NAME_PROGRAM_ID } from './bindings'; import { NameRegistryState } from './state'; export class Numberu32 extends BN { /** * Convert to Buffer representation */ toBuffer(): Buffer { const a = super.toArray().reverse(); const b = Buffer.from(a); if (b.length === 4) { return b; } assert(b.length < 4, 'Numberu32 too large'); const zeroPad = Buffer.alloc(4); b.copy(zeroPad); return zeroPad; } /** * Construct a Numberu64 from Buffer representation */ static fromBuffer(buffer: Buffer): BN { assert(buffer.length === 4, `Invalid buffer length: ${buffer.length}`); return new BN( [...buffer] .reverse() .map((i) => `00${i.toString(16)}`.slice(-2)) .join(''), 16, ); } } export class Numberu64 extends BN { /** * Convert to Buffer representation */ toBuffer(): Buffer { const a = super.toArray().reverse(); const b = Buffer.from(a); if (b.length === 8) { return b; } assert(b.length < 8, 'Numberu64 too large'); const zeroPad = Buffer.alloc(8); b.copy(zeroPad); return zeroPad; } /** * Construct a Numberu64 from Buffer representation */ static fromBuffer(buffer: Buffer): BN { assert(buffer.length === 8, `Invalid buffer length: ${buffer.length}`); return new BN( [...buffer] .reverse() .map((i) => `00${i.toString(16)}`.slice(-2)) .join(''), 16, ); } } export const signAndSendTransactionInstructions = async ( // sign and send transaction connection: Connection, signers: Array, feePayer: Keypair, txInstructions: Array, ): Promise => { const tx = new Transaction(); tx.feePayer = feePayer.publicKey; signers.push(feePayer); tx.add(...txInstructions); return await connection.sendTransaction(tx, signers); }; export async function getHashedName(name: string): Promise { const input = HASH_PREFIX + name; const buffer = createHash('sha256').update(input, 'utf8').digest(); return buffer; } export async function getNameAccountKey( hashed_name: Buffer, nameClass?: PublicKey, nameParent?: PublicKey, ): Promise { const seeds = [hashed_name]; if (nameClass) { seeds.push(nameClass.toBuffer()); } else { seeds.push(Buffer.alloc(32)); } if (nameParent) { seeds.push(nameParent.toBuffer()); } else { seeds.push(Buffer.alloc(32)); } const [nameAccountKey] = await PublicKey.findProgramAddress( seeds, NAME_PROGRAM_ID, ); return nameAccountKey; } export async function getNameOwner( connection: Connection, nameAccountKey: PublicKey, ): Promise { const nameAccount = await connection.getAccountInfo(nameAccountKey); if (!nameAccount) { throw new Error('Unable to find the given account.'); } return NameRegistryState.retrieve(connection, nameAccountKey); } export async function getFilteredProgramAccounts( connection: Connection, programId: PublicKey, filters: GetProgramAccountsFilter[], ): Promise<{ publicKey: PublicKey; accountInfo: AccountInfo }[]> { const resp = await connection.getProgramAccounts(programId, { commitment: connection.commitment, filters, encoding: 'base64', }); return resp.map( ({ pubkey, account: { data, executable, owner, lamports } }) => ({ publicKey: pubkey, accountInfo: { data: data, executable, owner: owner, lamports, }, }), ); }