@velas/account-agent
Version:
sdk
121 lines (104 loc) • 2.96 kB
JavaScript
import { serialize, BinaryReader, BorshError } from 'borsh';
// Class wrapping a plain object
export class Assignable {
constructor(properties) {
Object.keys(properties).forEach((key) => {
this[key] = properties[key];
});
}
encode() {
return Buffer.from(serialize(SCHEMA, this));
}
static decode(data) {
return deserializeExtraBytes(SCHEMA, this, data);
}
}
// Class representing a Rust-compatible enum, since enums are only strings or
// numbers in pure JS
export class Enum extends Assignable {
constructor(properties) {
super(properties);
if (Object.keys(properties).length !== 1) {
throw new Error('Enum can only take single value');
}
this.enum = '';
Object.keys(properties).forEach(key => {
this.enum = key;
});
}
}
export const SCHEMA = new Map();
// TODO PR for leaving extra bytes, a lot of code copied from
// https://github.com/near/borsh-js/blob/master/borsh-ts/index.ts
function capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
function deserializeField(
schema,
fieldName,
fieldType,
reader
) {
try {
if (typeof fieldType === 'string') {
return reader[`read${capitalizeFirstLetter(fieldType)}`]();
}
if (fieldType instanceof Array) {
if (typeof fieldType[0] === 'number') {
return reader.readFixedArray(fieldType[0]);
}
return reader.readArray(() =>
deserializeField(schema, fieldName, fieldType[0], reader)
);
}
return deserializeStruct(schema, fieldType, reader);
} catch (error) {
if (error instanceof BorshError) {
error.addToFieldPath(fieldName);
}
throw error;
}
}
function deserializeStruct(
schema,
classType,
reader
) {
const structSchema = schema.get(classType);
if (!structSchema) {
throw new BorshError(`Class ${classType.name} is missing in schema`);
}
if (structSchema.kind === 'struct') {
const result = {};
for (const [fieldName, fieldType] of schema.get(classType).fields) {
result[fieldName] = deserializeField(
schema,
fieldName,
fieldType,
reader
);
}
return new classType(result);
}
if (structSchema.kind === 'enum') {
const idx = reader.readU8();
if (idx >= structSchema.values.length) {
throw new BorshError(`Enum index: ${idx} is out of range`);
}
const [fieldName, fieldType] = structSchema.values[idx];
const fieldValue = deserializeField(schema, fieldName, fieldType, reader);
return new classType({ [fieldName]: fieldValue });
}
throw new BorshError(
`Unexpected schema kind: ${structSchema.kind} for ${classType.constructor.name}`
);
}
/// Deserializes object from bytes using schema.
export function deserializeExtraBytes(
schema,
classType,
buffer
){
const reader = new BinaryReader(buffer);
return deserializeStruct(schema, classType, reader);
}