122 lines
3.0 KiB
TypeScript
122 lines
3.0 KiB
TypeScript
|
import { PublicKey } from '@solana/web3.js';
|
||
|
import BN from 'bn.js';
|
||
|
import * as BufferLayout from 'buffer-layout';
|
||
|
|
||
|
/**
|
||
|
* Layout for a public key
|
||
|
*/
|
||
|
export const publicKey = (property = 'publicKey'): unknown => {
|
||
|
const publicKeyLayout = BufferLayout.blob(32, property);
|
||
|
|
||
|
const _decode = publicKeyLayout.decode.bind(publicKeyLayout);
|
||
|
const _encode = publicKeyLayout.encode.bind(publicKeyLayout);
|
||
|
|
||
|
publicKeyLayout.decode = (buffer: Buffer, offset: number) => {
|
||
|
const data = _decode(buffer, offset);
|
||
|
return new PublicKey(data);
|
||
|
};
|
||
|
|
||
|
publicKeyLayout.encode = (key: PublicKey, buffer: Buffer, offset: number) => {
|
||
|
return _encode(key.toBuffer(), buffer, offset);
|
||
|
};
|
||
|
|
||
|
return publicKeyLayout;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Layout for a 64bit unsigned value
|
||
|
*/
|
||
|
export const uint64 = (property = 'uint64'): unknown => {
|
||
|
const layout = BufferLayout.blob(8, property);
|
||
|
|
||
|
const _decode = layout.decode.bind(layout);
|
||
|
const _encode = layout.encode.bind(layout);
|
||
|
|
||
|
layout.decode = (buffer: Buffer, offset: number) => {
|
||
|
const data = _decode(buffer, offset);
|
||
|
return new BN(
|
||
|
[...data]
|
||
|
.reverse()
|
||
|
.map(i => `00${i.toString(16)}`.slice(-2))
|
||
|
.join(''),
|
||
|
16,
|
||
|
);
|
||
|
};
|
||
|
|
||
|
layout.encode = (num: BN, buffer: Buffer, offset: number) => {
|
||
|
const a = num.toArray().reverse();
|
||
|
let b = Buffer.from(a);
|
||
|
if (b.length !== 8) {
|
||
|
const zeroPad = Buffer.alloc(8);
|
||
|
b.copy(zeroPad);
|
||
|
b = zeroPad;
|
||
|
}
|
||
|
return _encode(b, buffer, offset);
|
||
|
};
|
||
|
|
||
|
return layout;
|
||
|
};
|
||
|
|
||
|
// TODO: wrap in BN (what about decimals?)
|
||
|
export const uint128 = (property = 'uint128'): unknown => {
|
||
|
const layout = BufferLayout.blob(16, property);
|
||
|
|
||
|
const _decode = layout.decode.bind(layout);
|
||
|
const _encode = layout.encode.bind(layout);
|
||
|
|
||
|
layout.decode = (buffer: Buffer, offset: number) => {
|
||
|
const data = _decode(buffer, offset);
|
||
|
return new BN(
|
||
|
[...data]
|
||
|
.reverse()
|
||
|
.map(i => `00${i.toString(16)}`.slice(-2))
|
||
|
.join(''),
|
||
|
16,
|
||
|
);
|
||
|
};
|
||
|
|
||
|
layout.encode = (num: BN, buffer: Buffer, offset: number) => {
|
||
|
const a = num.toArray().reverse();
|
||
|
let b = Buffer.from(a);
|
||
|
if (b.length !== 16) {
|
||
|
const zeroPad = Buffer.alloc(16);
|
||
|
b.copy(zeroPad);
|
||
|
b = zeroPad;
|
||
|
}
|
||
|
|
||
|
return _encode(b, buffer, offset);
|
||
|
};
|
||
|
|
||
|
return layout;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Layout for a Rust String type
|
||
|
*/
|
||
|
export const rustString = (property = 'string'): unknown => {
|
||
|
const rsl = BufferLayout.struct(
|
||
|
[
|
||
|
BufferLayout.u32('length'),
|
||
|
BufferLayout.u32('lengthPadding'),
|
||
|
BufferLayout.blob(BufferLayout.offset(BufferLayout.u32(), -8), 'chars'),
|
||
|
],
|
||
|
property,
|
||
|
);
|
||
|
const _decode = rsl.decode.bind(rsl);
|
||
|
const _encode = rsl.encode.bind(rsl);
|
||
|
|
||
|
rsl.decode = (buffer: Buffer, offset: number) => {
|
||
|
const data = _decode(buffer, offset);
|
||
|
return data.chars.toString('utf8');
|
||
|
};
|
||
|
|
||
|
rsl.encode = (str: string, buffer: Buffer, offset: number) => {
|
||
|
const data = {
|
||
|
chars: Buffer.from(str, 'utf8'),
|
||
|
};
|
||
|
return _encode(data, buffer, offset);
|
||
|
};
|
||
|
|
||
|
return rsl;
|
||
|
};
|