import { AccountsCoder } from "../index.js"; import { Idl, IdlTypeDef } from "../../idl.js"; import * as BufferLayout from "buffer-layout"; import { NONCE_ACCOUNT_LENGTH, PublicKey } from "@solana/web3.js"; import { accountSize } from "../common.js"; export class SystemAccountsCoder implements AccountsCoder { constructor(private idl: Idl) {} public async encode(accountName: A, account: T): Promise { switch (accountName) { case "nonce": { const buffer = Buffer.alloc(NONCE_ACCOUNT_LENGTH); const len = NONCE_ACCOUNT_LAYOUT.encode(account, buffer); return buffer.slice(0, len); } default: { throw new Error(`Invalid account name: ${accountName}`); } } } public decode(accountName: A, ix: Buffer): T { return this.decodeUnchecked(accountName, ix); } public decodeUnchecked(accountName: A, ix: Buffer): T { switch (accountName) { case "nonce": { return decodeNonceAccount(ix); } default: { throw new Error(`Invalid account name: ${accountName}`); } } } // TODO: this won't use the appendData. public memcmp(accountName: A, _appendData?: Buffer): any { switch (accountName) { case "nonce": { return { dataSize: NONCE_ACCOUNT_LENGTH, }; } default: { throw new Error(`Invalid account name: ${accountName}`); } } } public size(idlAccount: IdlTypeDef): number { return accountSize(this.idl, idlAccount) ?? 0; } } function decodeNonceAccount(ix: Buffer): T { return NONCE_ACCOUNT_LAYOUT.decode(ix) as T; } class WrappedLayout extends BufferLayout.Layout { layout: BufferLayout.Layout; decoder: (data: T) => U; encoder: (src: U) => T; constructor( layout: BufferLayout.Layout, decoder: (data: T) => U, encoder: (src: U) => T, property?: string ) { super(layout.span, property); this.layout = layout; this.decoder = decoder; this.encoder = encoder; } decode(b: Buffer, offset?: number): U { return this.decoder(this.layout.decode(b, offset)); } encode(src: U, b: Buffer, offset?: number): number { return this.layout.encode(this.encoder(src), b, offset); } getSpan(b: Buffer, offset?: number): number { return this.layout.getSpan(b, offset); } } function publicKey(property?: string): BufferLayout.Layout { return new WrappedLayout( BufferLayout.blob(32), (b: Buffer) => new PublicKey(b), (key: PublicKey) => key.toBuffer(), property ); } const NONCE_ACCOUNT_LAYOUT = BufferLayout.struct([ BufferLayout.u32("version"), BufferLayout.u32("state"), publicKey("authorizedPubkey"), publicKey("nonce"), BufferLayout.struct( [BufferLayout.nu64("lamportsPerSignature")], "feeCalculator" ), ]);