@solana/spl-name-service
Version:
SPL Name Service JavaScript API
158 lines (144 loc) • 3.82 kB
text/typescript
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<Keypair>,
feePayer: Keypair,
txInstructions: Array<TransactionInstruction>,
): Promise<string> => {
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<Buffer> {
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<PublicKey> {
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<NameRegistryState> {
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<Buffer> }[]> {
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,
},
}),
);
}