Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@mysten/bcs

Package Overview
Dependencies
Maintainers
4
Versions
522
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@mysten/bcs - npm Package Compare versions

Comparing version 0.0.0-experimental-20230929052502 to 0.0.0-experimental-20230929184743

1999

./dist/index.js

@@ -1,1977 +0,22 @@

"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var __accessCheck = (obj, member, msg) => {
if (!member.has(obj))
throw TypeError("Cannot " + msg);
};
var __privateGet = (obj, member, getter) => {
__accessCheck(obj, member, "read from private field");
return getter ? getter.call(obj) : member.get(obj);
};
var __privateAdd = (obj, member, value) => {
if (member.has(obj))
throw TypeError("Cannot add the same private member more than once");
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
};
var __privateSet = (obj, member, value, setter) => {
__accessCheck(obj, member, "write to private field");
setter ? setter.call(obj, value) : member.set(obj, value);
return value;
};
// src/index.ts
var src_exports = {};
__export(src_exports, {
BCS: () => BCS,
BcsReader: () => BcsReader,
BcsType: () => BcsType,
BcsWriter: () => BcsWriter,
SerializedBcs: () => SerializedBcs,
bcs: () => bcs,
decodeStr: () => decodeStr,
encodeStr: () => encodeStr,
fromB58: () => fromB58,
fromB64: () => fromB64,
fromHEX: () => fromHEX,
getRustConfig: () => getRustConfig,
getSuiMoveConfig: () => getSuiMoveConfig,
registerPrimitives: () => registerPrimitives,
splitGenericParameters: () => splitGenericParameters,
toB58: () => toB58,
toB64: () => toB64,
toHEX: () => toHEX
});
module.exports = __toCommonJS(src_exports);
// src/b58.ts
var import_bs58 = __toESM(require("bs58"));
var toB58 = (buffer) => import_bs58.default.encode(buffer);
var fromB58 = (str) => import_bs58.default.decode(str);
// src/b64.ts
function b64ToUint6(nChr) {
return nChr > 64 && nChr < 91 ? nChr - 65 : nChr > 96 && nChr < 123 ? nChr - 71 : nChr > 47 && nChr < 58 ? nChr + 4 : nChr === 43 ? 62 : nChr === 47 ? 63 : 0;
}
function fromB64(sBase64, nBlocksSize) {
var sB64Enc = sBase64.replace(/[^A-Za-z0-9+/]/g, ""), nInLen = sB64Enc.length, nOutLen = nBlocksSize ? Math.ceil((nInLen * 3 + 1 >> 2) / nBlocksSize) * nBlocksSize : nInLen * 3 + 1 >> 2, taBytes = new Uint8Array(nOutLen);
for (var nMod3, nMod4, nUint24 = 0, nOutIdx = 0, nInIdx = 0; nInIdx < nInLen; nInIdx++) {
nMod4 = nInIdx & 3;
nUint24 |= b64ToUint6(sB64Enc.charCodeAt(nInIdx)) << 6 * (3 - nMod4);
if (nMod4 === 3 || nInLen - nInIdx === 1) {
for (nMod3 = 0; nMod3 < 3 && nOutIdx < nOutLen; nMod3++, nOutIdx++) {
taBytes[nOutIdx] = nUint24 >>> (16 >>> nMod3 & 24) & 255;
}
nUint24 = 0;
}
}
return taBytes;
}
function uint6ToB64(nUint6) {
return nUint6 < 26 ? nUint6 + 65 : nUint6 < 52 ? nUint6 + 71 : nUint6 < 62 ? nUint6 - 4 : nUint6 === 62 ? 43 : nUint6 === 63 ? 47 : 65;
}
function toB64(aBytes) {
var nMod3 = 2, sB64Enc = "";
for (var nLen = aBytes.length, nUint24 = 0, nIdx = 0; nIdx < nLen; nIdx++) {
nMod3 = nIdx % 3;
nUint24 |= aBytes[nIdx] << (16 >>> nMod3 & 24);
if (nMod3 === 2 || aBytes.length - nIdx === 1) {
sB64Enc += String.fromCodePoint(
uint6ToB64(nUint24 >>> 18 & 63),
uint6ToB64(nUint24 >>> 12 & 63),
uint6ToB64(nUint24 >>> 6 & 63),
uint6ToB64(nUint24 & 63)
);
nUint24 = 0;
}
}
return sB64Enc.slice(0, sB64Enc.length - 2 + nMod3) + (nMod3 === 2 ? "" : nMod3 === 1 ? "=" : "==");
}
// src/hex.ts
function fromHEX(hexStr) {
const normalized = hexStr.startsWith("0x") ? hexStr.slice(2) : hexStr;
const padded = normalized.length % 2 === 0 ? normalized : `0${normalized}}`;
const intArr = padded.match(/.{2}/g)?.map((byte) => parseInt(byte, 16)) ?? [];
return Uint8Array.from(intArr);
}
function toHEX(bytes) {
return bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, "0"), "");
}
// src/uleb.ts
function ulebEncode(num) {
let arr = [];
let len = 0;
if (num === 0) {
return [0];
}
while (num > 0) {
arr[len] = num & 127;
if (num >>= 7) {
arr[len] |= 128;
}
len += 1;
}
return arr;
}
function ulebDecode(arr) {
let total = 0;
let shift = 0;
let len = 0;
while (true) {
let byte = arr[len];
len += 1;
total |= (byte & 127) << shift;
if ((byte & 128) === 0) {
break;
}
shift += 7;
}
return {
value: total,
length: len
};
}
// src/reader.ts
var BcsReader = class {
/**
* @param {Uint8Array} data Data to use as a buffer.
*/
constructor(data) {
this.bytePosition = 0;
this.dataView = new DataView(data.buffer);
}
/**
* Shift current cursor position by `bytes`.
*
* @param {Number} bytes Number of bytes to
* @returns {this} Self for possible chaining.
*/
shift(bytes) {
this.bytePosition += bytes;
return this;
}
/**
* Read U8 value from the buffer and shift cursor by 1.
* @returns
*/
read8() {
let value = this.dataView.getUint8(this.bytePosition);
this.shift(1);
return value;
}
/**
* Read U16 value from the buffer and shift cursor by 2.
* @returns
*/
read16() {
let value = this.dataView.getUint16(this.bytePosition, true);
this.shift(2);
return value;
}
/**
* Read U32 value from the buffer and shift cursor by 4.
* @returns
*/
read32() {
let value = this.dataView.getUint32(this.bytePosition, true);
this.shift(4);
return value;
}
/**
* Read U64 value from the buffer and shift cursor by 8.
* @returns
*/
read64() {
let value1 = this.read32();
let value2 = this.read32();
let result = value2.toString(16) + value1.toString(16).padStart(8, "0");
return BigInt("0x" + result).toString(10);
}
/**
* Read U128 value from the buffer and shift cursor by 16.
*/
read128() {
let value1 = BigInt(this.read64());
let value2 = BigInt(this.read64());
let result = value2.toString(16) + value1.toString(16).padStart(16, "0");
return BigInt("0x" + result).toString(10);
}
/**
* Read U128 value from the buffer and shift cursor by 32.
* @returns
*/
read256() {
let value1 = BigInt(this.read128());
let value2 = BigInt(this.read128());
let result = value2.toString(16) + value1.toString(16).padStart(32, "0");
return BigInt("0x" + result).toString(10);
}
/**
* Read `num` number of bytes from the buffer and shift cursor by `num`.
* @param num Number of bytes to read.
*/
readBytes(num) {
let start = this.bytePosition + this.dataView.byteOffset;
let value = new Uint8Array(this.dataView.buffer, start, num);
this.shift(num);
return value;
}
/**
* Read ULEB value - an integer of varying size. Used for enum indexes and
* vector lengths.
* @returns {Number} The ULEB value.
*/
readULEB() {
let start = this.bytePosition + this.dataView.byteOffset;
let buffer = new Uint8Array(this.dataView.buffer, start);
let { value, length } = ulebDecode(buffer);
this.shift(length);
return value;
}
/**
* Read a BCS vector: read a length and then apply function `cb` X times
* where X is the length of the vector, defined as ULEB in BCS bytes.
* @param cb Callback to process elements of vector.
* @returns {Array<Any>} Array of the resulting values, returned by callback.
*/
readVec(cb) {
let length = this.readULEB();
let result = [];
for (let i = 0; i < length; i++) {
result.push(cb(this, i, length));
}
return result;
}
};
// src/utils.ts
function encodeStr(data, encoding) {
switch (encoding) {
case "base58":
return toB58(data);
case "base64":
return toB64(data);
case "hex":
return toHEX(data);
default:
throw new Error("Unsupported encoding, supported values are: base64, hex");
}
}
function decodeStr(data, encoding) {
switch (encoding) {
case "base58":
return fromB58(data);
case "base64":
return fromB64(data);
case "hex":
return fromHEX(data);
default:
throw new Error("Unsupported encoding, supported values are: base64, hex");
}
}
function splitGenericParameters(str, genericSeparators = ["<", ">"]) {
const [left, right] = genericSeparators;
const tok = [];
let word = "";
let nestedAngleBrackets = 0;
for (let i = 0; i < str.length; i++) {
const char = str[i];
if (char === left) {
nestedAngleBrackets++;
}
if (char === right) {
nestedAngleBrackets--;
}
if (nestedAngleBrackets === 0 && char === ",") {
tok.push(word.trim());
word = "";
continue;
}
word += char;
}
tok.push(word.trim());
return tok;
}
// src/writer.ts
var BcsWriter = class {
constructor({ size = 1024, maxSize, allocateSize = 1024 } = {}) {
this.bytePosition = 0;
this.size = size;
this.maxSize = maxSize || size;
this.allocateSize = allocateSize;
this.dataView = new DataView(new ArrayBuffer(size));
}
ensureSizeOrGrow(bytes) {
const requiredSize = this.bytePosition + bytes;
if (requiredSize > this.size) {
const nextSize = Math.min(this.maxSize, this.size + this.allocateSize);
if (requiredSize > nextSize) {
throw new Error(
`Attempting to serialize to BCS, but buffer does not have enough size. Allocated size: ${this.size}, Max size: ${this.maxSize}, Required size: ${requiredSize}`
);
}
this.size = nextSize;
const nextBuffer = new ArrayBuffer(this.size);
new Uint8Array(nextBuffer).set(new Uint8Array(this.dataView.buffer));
this.dataView = new DataView(nextBuffer);
}
}
/**
* Shift current cursor position by `bytes`.
*
* @param {Number} bytes Number of bytes to
* @returns {this} Self for possible chaining.
*/
shift(bytes) {
this.bytePosition += bytes;
return this;
}
/**
* Write a U8 value into a buffer and shift cursor position by 1.
* @param {Number} value Value to write.
* @returns {this}
*/
write8(value) {
this.ensureSizeOrGrow(1);
this.dataView.setUint8(this.bytePosition, Number(value));
return this.shift(1);
}
/**
* Write a U16 value into a buffer and shift cursor position by 2.
* @param {Number} value Value to write.
* @returns {this}
*/
write16(value) {
this.ensureSizeOrGrow(2);
this.dataView.setUint16(this.bytePosition, Number(value), true);
return this.shift(2);
}
/**
* Write a U32 value into a buffer and shift cursor position by 4.
* @param {Number} value Value to write.
* @returns {this}
*/
write32(value) {
this.ensureSizeOrGrow(4);
this.dataView.setUint32(this.bytePosition, Number(value), true);
return this.shift(4);
}
/**
* Write a U64 value into a buffer and shift cursor position by 8.
* @param {bigint} value Value to write.
* @returns {this}
*/
write64(value) {
toLittleEndian(BigInt(value), 8).forEach((el) => this.write8(el));
return this;
}
/**
* Write a U128 value into a buffer and shift cursor position by 16.
*
* @param {bigint} value Value to write.
* @returns {this}
*/
write128(value) {
toLittleEndian(BigInt(value), 16).forEach((el) => this.write8(el));
return this;
}
/**
* Write a U256 value into a buffer and shift cursor position by 16.
*
* @param {bigint} value Value to write.
* @returns {this}
*/
write256(value) {
toLittleEndian(BigInt(value), 32).forEach((el) => this.write8(el));
return this;
}
/**
* Write a ULEB value into a buffer and shift cursor position by number of bytes
* written.
* @param {Number} value Value to write.
* @returns {this}
*/
writeULEB(value) {
ulebEncode(value).forEach((el) => this.write8(el));
return this;
}
/**
* Write a vector into a buffer by first writing the vector length and then calling
* a callback on each passed value.
*
* @param {Array<Any>} vector Array of elements to write.
* @param {WriteVecCb} cb Callback to call on each element of the vector.
* @returns {this}
*/
writeVec(vector, cb) {
this.writeULEB(vector.length);
Array.from(vector).forEach((el, i) => cb(this, el, i, vector.length));
return this;
}
/**
* Adds support for iterations over the object.
* @returns {Uint8Array}
*/
*[Symbol.iterator]() {
for (let i = 0; i < this.bytePosition; i++) {
yield this.dataView.getUint8(i);
}
return this.toBytes();
}
/**
* Get underlying buffer taking only value bytes (in case initial buffer size was bigger).
* @returns {Uint8Array} Resulting bcs.
*/
toBytes() {
return new Uint8Array(this.dataView.buffer.slice(0, this.bytePosition));
}
/**
* Represent data as 'hex' or 'base64'
* @param encoding Encoding to use: 'base64' or 'hex'
*/
toString(encoding) {
return encodeStr(this.toBytes(), encoding);
}
};
function toLittleEndian(bigint, size) {
let result = new Uint8Array(size);
let i = 0;
while (bigint > 0) {
result[i] = Number(bigint % BigInt(256));
bigint = bigint / BigInt(256);
i += 1;
}
return result;
}
// src/bcs-type.ts
var _write, _serialize;
var _BcsType = class _BcsType {
constructor(options) {
__privateAdd(this, _write, void 0);
__privateAdd(this, _serialize, void 0);
this.name = options.name;
this.read = options.read;
this.serializedSize = options.serializedSize ?? (() => null);
__privateSet(this, _write, options.write);
__privateSet(this, _serialize, options.serialize ?? ((value, options2) => {
const writer = new BcsWriter({ size: this.serializedSize(value) ?? void 0, ...options2 });
__privateGet(this, _write).call(this, value, writer);
return writer.toBytes();
}));
this.validate = options.validate ?? (() => {
});
}
write(value, writer) {
this.validate(value);
__privateGet(this, _write).call(this, value, writer);
}
serialize(value, options) {
this.validate(value);
return new SerializedBcs(this, __privateGet(this, _serialize).call(this, value, options));
}
parse(bytes) {
const reader = new BcsReader(bytes);
return this.read(reader);
}
transform({
name,
input,
output
}) {
return new _BcsType({
name: name ?? this.name,
read: (reader) => output(this.read(reader)),
write: (value, writer) => __privateGet(this, _write).call(this, input(value), writer),
serializedSize: (value) => this.serializedSize(input(value)),
serialize: (value, options) => __privateGet(this, _serialize).call(this, input(value), options),
validate: (value) => this.validate(input(value))
});
}
};
_write = new WeakMap();
_serialize = new WeakMap();
var BcsType = _BcsType;
var _schema, _bytes;
var SerializedBcs = class {
constructor(type, schema) {
__privateAdd(this, _schema, void 0);
__privateAdd(this, _bytes, void 0);
__privateSet(this, _schema, type);
__privateSet(this, _bytes, schema);
}
toBytes() {
return __privateGet(this, _bytes);
}
toHex() {
return toHEX(__privateGet(this, _bytes));
}
toBase64() {
return toB64(__privateGet(this, _bytes));
}
toBase58() {
return toB58(__privateGet(this, _bytes));
}
parse() {
return __privateGet(this, _schema).parse(__privateGet(this, _bytes));
}
};
_schema = new WeakMap();
_bytes = new WeakMap();
function fixedSizeBcsType({
size,
...options
}) {
return new BcsType({
...options,
serializedSize: () => size
});
}
function uIntBcsType({
readMethod,
writeMethod,
...options
}) {
return fixedSizeBcsType({
...options,
read: (reader) => reader[readMethod](),
write: (value, writer) => writer[writeMethod](value),
validate: (value) => {
if (value < 0 || value > options.maxValue) {
throw new TypeError(
`Invalid ${options.name} value: ${value}. Expected value in range 0-${options.maxValue}`
);
}
options.validate?.(value);
}
});
}
function bigUIntBcsType({
readMethod,
writeMethod,
...options
}) {
return fixedSizeBcsType({
...options,
read: (reader) => reader[readMethod](),
write: (value, writer) => writer[writeMethod](BigInt(value)),
validate: (val) => {
const value = BigInt(val);
if (value < 0 || value > options.maxValue) {
throw new TypeError(
`Invalid ${options.name} value: ${value}. Expected value in range 0-${options.maxValue}`
);
}
options.validate?.(value);
}
});
}
function dynamicSizeBcsType({
serialize,
...options
}) {
const type = new BcsType({
...options,
serialize,
write: (value, writer) => {
for (const byte of type.serialize(value).toBytes()) {
writer.write8(byte);
}
}
});
return type;
}
function stringLikeBcsType({
toBytes,
fromBytes,
...options
}) {
return new BcsType({
...options,
read: (reader) => {
const length = reader.readULEB();
const bytes = reader.readBytes(length);
return fromBytes(bytes);
},
write: (hex, writer) => {
const bytes = toBytes(hex);
writer.writeULEB(bytes.length);
for (let i = 0; i < bytes.length; i++) {
writer.write8(bytes[i]);
}
},
serialize: (value) => {
const bytes = toBytes(value);
const size = ulebEncode(bytes.length);
const result = new Uint8Array(size.length + bytes.length);
result.set(size, 0);
result.set(bytes, size.length);
return result;
},
validate: (value) => {
if (typeof value !== "string") {
throw new TypeError(`Invalid ${options.name} value: ${value}. Expected string`);
}
options.validate?.(value);
}
});
}
function lazyBcsType(cb) {
let lazyType = null;
function getType() {
if (!lazyType) {
lazyType = cb();
}
return lazyType;
}
return new BcsType({
name: "lazy",
read: (data) => getType().read(data),
serializedSize: (value) => getType().serializedSize(value),
write: (value, writer) => getType().write(value, writer),
serialize: (value, options) => getType().serialize(value, options).toBytes()
});
}
// src/bcs.ts
var bcs = {
/**
* Creates a BcsType that can be used to read and write an 8-bit unsigned integer.
* @example
* bcs.u8().serialize(255).toBytes() // Uint8Array [ 255 ]
*/
u8(options) {
return uIntBcsType({
name: "u8",
readMethod: "read8",
writeMethod: "write8",
size: 1,
maxValue: 2 ** 8 - 1,
...options
});
},
/**
* Creates a BcsType that can be used to read and write a 16-bit unsigned integer.
* @example
* bcs.u16().serialize(65535).toBytes() // Uint8Array [ 255, 255 ]
*/
u16(options) {
return uIntBcsType({
name: "u16",
readMethod: "read16",
writeMethod: "write16",
size: 2,
maxValue: 2 ** 16 - 1,
...options
});
},
/**
* Creates a BcsType that can be used to read and write a 32-bit unsigned integer.
* @example
* bcs.u32().serialize(4294967295).toBytes() // Uint8Array [ 255, 255, 255, 255 ]
*/
u32(options) {
return uIntBcsType({
name: "u32",
readMethod: "read32",
writeMethod: "write32",
size: 4,
maxValue: 2 ** 32 - 1,
...options
});
},
/**
* Creates a BcsType that can be used to read and write a 64-bit unsigned integer.
* @example
* bcs.u64().serialize(1).toBytes() // Uint8Array [ 1, 0, 0, 0, 0, 0, 0, 0 ]
*/
u64(options) {
return bigUIntBcsType({
name: "u64",
readMethod: "read64",
writeMethod: "write64",
size: 8,
maxValue: 2n ** 64n - 1n,
...options
});
},
/**
* Creates a BcsType that can be used to read and write a 128-bit unsigned integer.
* @example
* bcs.u128().serialize(1).toBytes() // Uint8Array [ 1, ..., 0 ]
*/
u128(options) {
return bigUIntBcsType({
name: "u128",
readMethod: "read128",
writeMethod: "write128",
size: 16,
maxValue: 2n ** 128n - 1n,
...options
});
},
/**
* Creates a BcsType that can be used to read and write a 256-bit unsigned integer.
* @example
* bcs.u256().serialize(1).toBytes() // Uint8Array [ 1, ..., 0 ]
*/
u256(options) {
return bigUIntBcsType({
name: "u256",
readMethod: "read256",
writeMethod: "write256",
size: 32,
maxValue: 2n ** 256n - 1n,
...options
});
},
/**
* Creates a BcsType that can be used to read and write boolean values.
* @example
* bcs.bool().serialize(true).toBytes() // Uint8Array [ 1 ]
*/
bool(options) {
return fixedSizeBcsType({
name: "bool",
size: 1,
read: (reader) => reader.read8() === 1,
write: (value, writer) => writer.write8(value ? 1 : 0),
...options,
validate: (value) => {
options?.validate?.(value);
if (typeof value !== "boolean") {
throw new TypeError(`Expected boolean, found ${typeof value}`);
}
}
});
},
/**
* Creates a BcsType that can be used to read and write unsigned LEB encoded integers
* @example
*
*/
uleb128(options) {
return dynamicSizeBcsType({
name: "uleb128",
read: (reader) => reader.readULEB(),
serialize: (value) => {
return Uint8Array.from(ulebEncode(value));
},
...options
});
},
/**
* Creates a BcsType representing a fixed length byte array
* @param size The number of bytes this types represents
* @example
* bcs.bytes(3).serialize(new Uint8Array([1, 2, 3])).toBytes() // Uint8Array [1, 2, 3]
*/
bytes(size, options) {
return fixedSizeBcsType({
name: `bytes[${size}]`,
size,
read: (reader) => reader.readBytes(size),
write: (value, writer) => {
for (let i = 0; i < size; i++) {
writer.write8(value[i] ?? 0);
}
},
...options,
validate: (value) => {
options?.validate?.(value);
if (!("length" in value)) {
throw new TypeError(`Expected array, found ${typeof value}`);
}
if (value.length !== size) {
throw new TypeError(`Expected array of length ${size}, found ${value.length}`);
}
}
});
},
/**
* Creates a BcsType that can ser/de string values. Strings will be UTF-8 encoded
* @example
* bcs.string().serialize('a').toBytes() // Uint8Array [ 1, 97 ]
*/
string(options) {
return stringLikeBcsType({
name: "string",
toBytes: (value) => new TextEncoder().encode(value),
fromBytes: (bytes) => new TextDecoder().decode(bytes),
...options
});
},
/**
* Creates a BcsType that represents a fixed length array of a given type
* @param size The number of elements in the array
* @param type The BcsType of each element in the array
* @example
* bcs.fixedArray(3, bcs.u8()).serialize([1, 2, 3]).toBytes() // Uint8Array [ 1, 2, 3 ]
*/
fixedArray(size, type, options) {
return new BcsType({
name: `${type.name}[${size}]`,
read: (reader) => {
const result = new Array(size);
for (let i = 0; i < size; i++) {
result[i] = type.read(reader);
}
return result;
},
write: (value, writer) => {
for (const item of value) {
type.write(item, writer);
}
},
...options,
validate: (value) => {
options?.validate?.(value);
if (!("length" in value)) {
throw new TypeError(`Expected array, found ${typeof value}`);
}
if (value.length !== size) {
throw new TypeError(`Expected array of length ${size}, found ${value.length}`);
}
}
});
},
/**
* Creates a BcsType representing an optional value
* @param type The BcsType of the optional value
* @example
* bcs.option(bcs.u8()).serialize(null).toBytes() // Uint8Array [ 0 ]
* bcs.option(bcs.u8()).serialize(1).toBytes() // Uint8Array [ 1, 1 ]
*/
option(type) {
return bcs.enum(`Option<${type.name}>`, {
None: null,
Some: type
}).transform({
input: (value) => {
if (value == null) {
return { None: true };
}
return { Some: value };
},
output: (value) => {
if ("Some" in value) {
return value.Some;
}
return null;
}
});
},
/**
* Creates a BcsType representing a variable length vector of a given type
* @param type The BcsType of each element in the vector
*
* @example
* bcs.vector(bcs.u8()).toBytes([1, 2, 3]) // Uint8Array [ 3, 1, 2, 3 ]
*/
vector(type, options) {
return new BcsType({
name: `vector<${type.name}>`,
read: (reader) => {
const length = reader.readULEB();
const result = new Array(length);
for (let i = 0; i < length; i++) {
result[i] = type.read(reader);
}
return result;
},
write: (value, writer) => {
writer.writeULEB(value.length);
for (const item of value) {
type.write(item, writer);
}
},
...options,
validate: (value) => {
options?.validate?.(value);
if (!("length" in value)) {
throw new TypeError(`Expected array, found ${typeof value}`);
}
}
});
},
/**
* Creates a BcsType representing a tuple of a given set of types
* @param types The BcsTypes for each element in the tuple
*
* @example
* const tuple = bcs.tuple([bcs.u8(), bcs.string(), bcs.bool()])
* tuple.serialize([1, 'a', true]).toBytes() // Uint8Array [ 1, 1, 97, 1 ]
*/
tuple(types, options) {
return new BcsType({
name: `(${types.map((t) => t.name).join(", ")})`,
serializedSize: (values) => {
let total = 0;
for (let i = 0; i < types.length; i++) {
const size = types[i].serializedSize(values[i]);
if (size == null) {
return null;
}
total += size;
}
return total;
},
read: (reader) => {
const result = [];
for (const type of types) {
result.push(type.read(reader));
}
return result;
},
write: (value, writer) => {
for (let i = 0; i < types.length; i++) {
types[i].write(value[i], writer);
}
},
...options,
validate: (value) => {
options?.validate?.(value);
if (!Array.isArray(value)) {
throw new TypeError(`Expected array, found ${typeof value}`);
}
if (value.length !== types.length) {
throw new TypeError(`Expected array of length ${types.length}, found ${value.length}`);
}
}
});
},
/**
* Creates a BcsType representing a struct of a given set of fields
* @param name The name of the struct
* @param fields The fields of the struct. The order of the fields affects how data is serialized and deserialized
*
* @example
* const struct = bcs.struct('MyStruct', {
* a: bcs.u8(),
* b: bcs.string(),
* })
* struct.serialize({ a: 1, b: 'a' }).toBytes() // Uint8Array [ 1, 1, 97 ]
*/
struct(name, fields, options) {
const canonicalOrder = Object.entries(fields);
return new BcsType({
name,
serializedSize: (values) => {
let total = 0;
for (const [field, type] of canonicalOrder) {
const size = type.serializedSize(values[field]);
if (size == null) {
return null;
}
total += size;
}
return total;
},
read: (reader) => {
const result = {};
for (const [field, type] of canonicalOrder) {
result[field] = type.read(reader);
}
return result;
},
write: (value, writer) => {
for (const [field, type] of canonicalOrder) {
type.write(value[field], writer);
}
},
...options,
validate: (value) => {
options?.validate?.(value);
if (typeof value !== "object" || value == null) {
throw new TypeError(`Expected object, found ${typeof value}`);
}
}
});
},
/**
* Creates a BcsType representing an enum of a given set of options
* @param name The name of the enum
* @param values The values of the enum. The order of the values affects how data is serialized and deserialized.
* null can be used to represent a variant with no data.
*
* @example
* const enum = bcs.enum('MyEnum', {
* A: bcs.u8(),
* B: bcs.string(),
* C: null,
* })
* enum.serialize({ A: 1 }).toBytes() // Uint8Array [ 0, 1 ]
* enum.serialize({ B: 'a' }).toBytes() // Uint8Array [ 1, 1, 97 ]
* enum.serialize({ C: true }).toBytes() // Uint8Array [ 2 ]
*/
enum(name, values, options) {
const canonicalOrder = Object.entries(values);
return new BcsType({
name,
read: (reader) => {
const index = reader.readULEB();
const [name2, type] = canonicalOrder[index];
return {
[name2]: type?.read(reader) ?? true
};
},
write: (value, writer) => {
const [name2, val] = Object.entries(value)[0];
for (let i = 0; i < canonicalOrder.length; i++) {
const [optionName, optionType] = canonicalOrder[i];
if (optionName === name2) {
writer.writeULEB(i);
optionType?.write(val, writer);
return;
}
}
},
...options,
validate: (value) => {
options?.validate?.(value);
if (typeof value !== "object" || value == null) {
throw new TypeError(`Expected object, found ${typeof value}`);
}
const keys = Object.keys(value);
if (keys.length !== 1) {
throw new TypeError(`Expected object with one key, found ${keys.length}`);
}
const [name2] = keys;
if (!Object.hasOwn(values, name2)) {
throw new TypeError(`Invalid enum variant ${name2}`);
}
}
});
},
/**
* Creates a BcsType representing a map of a given key and value type
* @param keyType The BcsType of the key
* @param valueType The BcsType of the value
* @example
* const map = bcs.map(bcs.u8(), bcs.string())
* map.serialize(new Map([[2, 'a']])).toBytes() // Uint8Array [ 1, 2, 1, 97 ]
*/
map(keyType, valueType) {
return bcs.vector(bcs.tuple([keyType, valueType])).transform({
name: `Map<${keyType.name}, ${valueType.name}>`,
input: (value) => {
return [...value.entries()];
},
output: (value) => {
const result = /* @__PURE__ */ new Map();
for (const [key, val] of value) {
result.set(key, val);
}
return result;
}
});
},
/**
* Creates a helper function representing a generic type. This method returns
* a function that can be used to create concrete version of the generic type.
* @param names The names of the generic parameters
* @param cb A callback that returns the generic type
* @example
* const MyStruct = bcs.generic(['T'], (T) => bcs.struct('MyStruct', { inner: T }))
* MyStruct(bcs.u8()).serialize({ inner: 1 }).toBytes() // Uint8Array [ 1 ]
* MyStruct(bcs.string()).serialize({ inner: 'a' }).toBytes() // Uint8Array [ 1, 97 ]
*/
generic(names, cb) {
return (...types) => {
return cb(...types).transform({
name: `${cb.name}<${types.map((t) => t.name).join(", ")}>`,
input: (value) => value,
output: (value) => value
});
};
},
/**
* Creates a BcsType that wraps another BcsType which is lazily evaluated. This is useful for creating recursive types.
* @param cb A callback that returns the BcsType
*/
lazy(cb) {
return lazyBcsType(cb);
}
};
// src/legacy-registry.ts
var SUI_ADDRESS_LENGTH = 32;
var _BCS = class _BCS {
/**
* Construct a BCS instance with a prepared schema.
*
* @param schema A prepared schema with type definitions
* @param withPrimitives Whether to register primitive types by default
*/
constructor(schema) {
/**
* Map of kind `TypeName => TypeInterface`. Holds all
* callbacks for (de)serialization of every registered type.
*
* If the value stored is a string, it is treated as an alias.
*/
this.types = /* @__PURE__ */ new Map();
/**
* Count temp keys to generate a new one when requested.
*/
this.counter = 0;
if (schema instanceof _BCS) {
this.schema = schema.schema;
this.types = new Map(schema.types);
return;
}
this.schema = schema;
this.registerAddressType(_BCS.ADDRESS, schema.addressLength, schema.addressEncoding);
this.registerVectorType(schema.vectorType);
if (schema.types && schema.types.structs) {
for (let name of Object.keys(schema.types.structs)) {
this.registerStructType(name, schema.types.structs[name]);
}
}
if (schema.types && schema.types.enums) {
for (let name of Object.keys(schema.types.enums)) {
this.registerEnumType(name, schema.types.enums[name]);
}
}
if (schema.types && schema.types.aliases) {
for (let name of Object.keys(schema.types.aliases)) {
this.registerAlias(name, schema.types.aliases[name]);
}
}
if (schema.withPrimitives !== false) {
registerPrimitives(this);
}
}
/**
* Name of the key to use for temporary struct definitions.
* Returns a temp key + index (for a case when multiple temp
* structs are processed).
*/
tempKey() {
return `bcs-struct-${++this.counter}`;
}
/**
* Serialize data into bcs.
*
* @example
* bcs.registerVectorType('vector<u8>', 'u8');
*
* let serialized = BCS
* .set('vector<u8>', [1,2,3,4,5,6])
* .toBytes();
*
* console.assert(toHex(serialized) === '06010203040506');
*
* @param type Name of the type to serialize (must be registered) or a struct type.
* @param data Data to serialize.
* @param size Serialization buffer size. Default 1024 = 1KB.
* @return A BCS reader instance. Usually you'd want to call `.toBytes()`
*/
ser(type, data, options) {
if (typeof type === "string" || Array.isArray(type)) {
const { name, params } = this.parseTypeName(type);
return this.getTypeInterface(name).encode(this, data, options, params);
}
if (typeof type === "object") {
const key = this.tempKey();
const temp = new _BCS(this);
return temp.registerStructType(key, type).ser(key, data, options);
}
throw new Error(`Incorrect type passed into the '.ser()' function.
${JSON.stringify(type)}`);
}
/**
* Deserialize BCS into a JS type.
*
* @example
* let num = bcs.ser('u64', '4294967295').toString('hex');
* let deNum = bcs.de('u64', num, 'hex');
* console.assert(deNum.toString(10) === '4294967295');
*
* @param type Name of the type to deserialize (must be registered) or a struct type definition.
* @param data Data to deserialize.
* @param encoding Optional - encoding to use if data is of type String
* @return Deserialized data.
*/
de(type, data, encoding) {
if (typeof data === "string") {
if (encoding) {
data = decodeStr(data, encoding);
} else {
throw new Error("To pass a string to `bcs.de`, specify encoding");
}
}
if (typeof type === "string" || Array.isArray(type)) {
const { name, params } = this.parseTypeName(type);
return this.getTypeInterface(name).decode(this, data, params);
}
if (typeof type === "object") {
const temp = new _BCS(this);
const key = this.tempKey();
return temp.registerStructType(key, type).de(key, data, encoding);
}
throw new Error(`Incorrect type passed into the '.de()' function.
${JSON.stringify(type)}`);
}
/**
* Check whether a `TypeInterface` has been loaded for a `type`.
* @param type Name of the type to check.
* @returns
*/
hasType(type) {
return this.types.has(type);
}
/**
* Create an alias for a type.
* WARNING: this can potentially lead to recursion
* @param name Alias to use
* @param forType Type to reference
* @returns
*
* @example
* ```
* let bcs = new BCS(getSuiMoveConfig());
* bcs.registerAlias('ObjectDigest', BCS.BASE58);
* let b58_digest = bcs.de('ObjectDigest', '<digest_bytes>', 'base64');
* ```
*/
registerAlias(name, forType) {
this.types.set(name, forType);
return this;
}
/**
* Method to register new types for BCS internal representation.
* For each registered type 2 callbacks must be specified and one is optional:
*
* - encodeCb(writer, data) - write a way to serialize data with BcsWriter;
* - decodeCb(reader) - write a way to deserialize data with BcsReader;
* - validateCb(data) - validate data - either return bool or throw an error
*
* @example
* // our type would be a string that consists only of numbers
* bcs.registerType('number_string',
* (writer, data) => writer.writeVec(data, (w, el) => w.write8(el)),
* (reader) => reader.readVec((r) => r.read8()).join(''), // read each value as u8
* (value) => /[0-9]+/.test(value) // test that it has at least one digit
* );
* console.log(Array.from(bcs.ser('number_string', '12345').toBytes()) == [5,1,2,3,4,5]);
*
* @param name
* @param encodeCb Callback to encode a value.
* @param decodeCb Callback to decode a value.
* @param validateCb Optional validator Callback to check type before serialization.
*/
registerType(typeName, encodeCb, decodeCb, validateCb = () => true) {
const { name, params: generics } = this.parseTypeName(typeName);
this.types.set(name, {
encode(self, data, options, typeParams) {
const typeMap = generics.reduce((acc, value, index) => {
return Object.assign(acc, { [value]: typeParams[index] });
}, {});
return this._encodeRaw.call(self, new BcsWriter(options), data, typeParams, typeMap);
},
decode(self, data, typeParams) {
const typeMap = generics.reduce((acc, value, index) => {
return Object.assign(acc, { [value]: typeParams[index] });
}, {});
return this._decodeRaw.call(self, new BcsReader(data), typeParams, typeMap);
},
// these methods should always be used with caution as they require pre-defined
// reader and writer and mainly exist to allow multi-field (de)serialization;
_encodeRaw(writer, data, typeParams, typeMap) {
if (validateCb(data)) {
return encodeCb.call(this, writer, data, typeParams, typeMap);
} else {
throw new Error(`Validation failed for type ${name}, data: ${data}`);
}
},
_decodeRaw(reader, typeParams, typeMap) {
return decodeCb.call(this, reader, typeParams, typeMap);
}
});
return this;
}
/**
* Method to register BcsType instances to the registry
* Types are registered with a callback that provides BcsType instances for each generic
* passed to the type.
*
* - createType(...generics) - Return a BcsType instance
*
* @example
* // our type would be a string that consists only of numbers
* bcs.registerType('Box<T>', (T) => {
* return bcs.struct({
* value: T
* });
* });
* console.log(Array.from(bcs.ser('Box<string>', '12345').toBytes()) == [5,1,2,3,4,5]);
*
* @param name
* @param createType a Callback to create the BcsType with any passed in generics
*/
registerBcsType(typeName, createType) {
this.registerType(
typeName,
(writer, data, typeParams) => {
const generics = typeParams.map(
(param) => new BcsType({
name: String(param),
write: (data2, writer2) => {
const { name, params } = this.parseTypeName(param);
const typeInterface = this.getTypeInterface(name);
const typeMap = params.reduce((acc, value, index) => {
return Object.assign(acc, { [value]: typeParams[index] });
}, {});
return typeInterface._encodeRaw.call(this, writer2, data2, params, typeMap);
},
read: () => {
throw new Error("Not implemented");
}
})
);
createType(...generics).write(data, writer);
return writer;
},
(reader, typeParams) => {
const generics = typeParams.map(
(param) => new BcsType({
name: String(param),
write: (data, writer) => {
throw new Error("Not implemented");
},
read: (reader2) => {
const { name, params } = this.parseTypeName(param);
const typeInterface = this.getTypeInterface(name);
const typeMap = params.reduce((acc, value, index) => {
return Object.assign(acc, { [value]: typeParams[index] });
}, {});
return typeInterface._decodeRaw.call(this, reader2, params, typeMap);
}
})
);
return createType(...generics).read(reader);
}
);
return this;
}
/**
* Register an address type which is a sequence of U8s of specified length.
* @example
* bcs.registerAddressType('address', SUI_ADDRESS_LENGTH);
* let addr = bcs.de('address', 'c3aca510c785c7094ac99aeaa1e69d493122444df50bb8a99dfa790c654a79af');
*
* @param name Name of the address type.
* @param length Byte length of the address.
* @param encoding Encoding to use for the address type
* @returns
*/
registerAddressType(name, length, encoding = "hex") {
switch (encoding) {
case "base64":
return this.registerType(
name,
function encodeAddress(writer, data) {
return fromB64(data).reduce((writer2, el) => writer2.write8(el), writer);
},
function decodeAddress(reader) {
return toB64(reader.readBytes(length));
}
);
case "hex":
return this.registerType(
name,
function encodeAddress(writer, data) {
return fromHEX(data).reduce((writer2, el) => writer2.write8(el), writer);
},
function decodeAddress(reader) {
return toHEX(reader.readBytes(length));
}
);
default:
throw new Error("Unsupported encoding! Use either hex or base64");
}
}
/**
* Register custom vector type inside the bcs.
*
* @example
* bcs.registerVectorType('vector<T>'); // generic registration
* let array = bcs.de('vector<u8>', '06010203040506', 'hex'); // [1,2,3,4,5,6];
* let again = bcs.ser('vector<u8>', [1,2,3,4,5,6]).toString('hex');
*
* @param name Name of the type to register
* @param elementType Optional name of the inner type of the vector
* @return Returns self for chaining.
*/
registerVectorType(typeName) {
let { name, params } = this.parseTypeName(typeName);
if (params.length > 1) {
throw new Error("Vector can have only one type parameter; got " + name);
}
return this.registerType(
typeName,
function encodeVector(writer, data, typeParams, typeMap) {
return writer.writeVec(data, (writer2, el) => {
let elementType = typeParams[0];
if (!elementType) {
throw new Error(`Incorrect number of type parameters passed a to vector '${typeName}'`);
}
let { name: name2, params: params2 } = this.parseTypeName(elementType);
if (this.hasType(name2)) {
return this.getTypeInterface(name2)._encodeRaw.call(this, writer2, el, params2, typeMap);
}
if (!(name2 in typeMap)) {
throw new Error(
`Unable to find a matching type definition for ${name2} in vector; make sure you passed a generic`
);
}
let { name: innerName, params: innerParams } = this.parseTypeName(typeMap[name2]);
return this.getTypeInterface(innerName)._encodeRaw.call(
this,
writer2,
el,
innerParams,
typeMap
);
});
},
function decodeVector(reader, typeParams, typeMap) {
return reader.readVec((reader2) => {
let elementType = typeParams[0];
if (!elementType) {
throw new Error(`Incorrect number of type parameters passed to a vector '${typeName}'`);
}
let { name: name2, params: params2 } = this.parseTypeName(elementType);
if (this.hasType(name2)) {
return this.getTypeInterface(name2)._decodeRaw.call(this, reader2, params2, typeMap);
}
if (!(name2 in typeMap)) {
throw new Error(
`Unable to find a matching type definition for ${name2} in vector; make sure you passed a generic`
);
}
let { name: innerName, params: innerParams } = this.parseTypeName(typeMap[name2]);
return this.getTypeInterface(innerName)._decodeRaw.call(
this,
reader2,
innerParams,
typeMap
);
});
}
);
}
/**
* Safe method to register a custom Move struct. The first argument is a name of the
* struct which is only used on the FrontEnd and has no affect on serialization results,
* and the second is a struct description passed as an Object.
*
* The description object MUST have the same order on all of the platforms (ie in Move
* or in Rust).
*
* @example
* // Move / Rust struct
* // struct Coin {
* // value: u64,
* // owner: vector<u8>, // name // Vec<u8> in Rust
* // is_locked: bool,
* // }
*
* bcs.registerStructType('Coin', {
* value: bcs.U64,
* owner: bcs.STRING,
* is_locked: bcs.BOOL
* });
*
* // Created in Rust with diem/bcs
* // let rust_bcs_str = '80d1b105600000000e4269672057616c6c65742047757900';
* let rust_bcs_str = [ // using an Array here as BCS works with Uint8Array
* 128, 209, 177, 5, 96, 0, 0,
* 0, 14, 66, 105, 103, 32, 87,
* 97, 108, 108, 101, 116, 32, 71,
* 117, 121, 0
* ];
*
* // Let's encode the value as well
* let test_set = bcs.ser('Coin', {
* owner: 'Big Wallet Guy',
* value: '412412400000',
* is_locked: false,
* });
*
* console.assert(Array.from(test_set.toBytes()) === rust_bcs_str, 'Whoopsie, result mismatch');
*
* @param name Name of the type to register.
* @param fields Fields of the struct. Must be in the correct order.
* @return Returns BCS for chaining.
*/
registerStructType(typeName, fields) {
for (let key in fields) {
let internalName = this.tempKey();
let value = fields[key];
if (!Array.isArray(value) && typeof value !== "string") {
fields[key] = internalName;
this.registerStructType(internalName, value);
}
}
let struct = Object.freeze(fields);
let canonicalOrder = Object.keys(struct);
let { name: structName, params: generics } = this.parseTypeName(typeName);
return this.registerType(
typeName,
function encodeStruct(writer, data, typeParams, typeMap) {
if (!data || data.constructor !== Object) {
throw new Error(`Expected ${structName} to be an Object, got: ${data}`);
}
if (typeParams.length !== generics.length) {
throw new Error(
`Incorrect number of generic parameters passed; expected: ${generics.length}, got: ${typeParams.length}`
);
}
for (let key of canonicalOrder) {
if (!(key in data)) {
throw new Error(`Struct ${structName} requires field ${key}:${struct[key]}`);
}
const { name: fieldType, params: fieldParams } = this.parseTypeName(
struct[key]
);
if (!generics.includes(fieldType)) {
this.getTypeInterface(fieldType)._encodeRaw.call(
this,
writer,
data[key],
fieldParams,
typeMap
);
} else {
const paramIdx = generics.indexOf(fieldType);
let { name, params } = this.parseTypeName(typeParams[paramIdx]);
if (this.hasType(name)) {
this.getTypeInterface(name)._encodeRaw.call(
this,
writer,
data[key],
params,
typeMap
);
continue;
}
if (!(name in typeMap)) {
throw new Error(
`Unable to find a matching type definition for ${name} in ${structName}; make sure you passed a generic`
);
}
let { name: innerName, params: innerParams } = this.parseTypeName(typeMap[name]);
this.getTypeInterface(innerName)._encodeRaw.call(
this,
writer,
data[key],
innerParams,
typeMap
);
}
}
return writer;
},
function decodeStruct(reader, typeParams, typeMap) {
if (typeParams.length !== generics.length) {
throw new Error(
`Incorrect number of generic parameters passed; expected: ${generics.length}, got: ${typeParams.length}`
);
}
let result = {};
for (let key of canonicalOrder) {
const { name: fieldName, params: fieldParams } = this.parseTypeName(
struct[key]
);
if (!generics.includes(fieldName)) {
result[key] = this.getTypeInterface(fieldName)._decodeRaw.call(
this,
reader,
fieldParams,
typeMap
);
} else {
const paramIdx = generics.indexOf(fieldName);
let { name, params } = this.parseTypeName(typeParams[paramIdx]);
if (this.hasType(name)) {
result[key] = this.getTypeInterface(name)._decodeRaw.call(
this,
reader,
params,
typeMap
);
continue;
}
if (!(name in typeMap)) {
throw new Error(
`Unable to find a matching type definition for ${name} in ${structName}; make sure you passed a generic`
);
}
let { name: innerName, params: innerParams } = this.parseTypeName(typeMap[name]);
result[key] = this.getTypeInterface(innerName)._decodeRaw.call(
this,
reader,
innerParams,
typeMap
);
}
}
return result;
}
);
}
/**
* Safe method to register custom enum type where each invariant holds the value of another type.
* @example
* bcs.registerStructType('Coin', { value: 'u64' });
* bcs.registerEnumType('MyEnum', {
* single: 'Coin',
* multi: 'vector<Coin>',
* empty: null
* });
*
* console.log(
* bcs.de('MyEnum', 'AICWmAAAAAAA', 'base64'), // { single: { value: 10000000 } }
* bcs.de('MyEnum', 'AQIBAAAAAAAAAAIAAAAAAAAA', 'base64') // { multi: [ { value: 1 }, { value: 2 } ] }
* )
*
* // and serialization
* bcs.ser('MyEnum', { single: { value: 10000000 } }).toBytes();
* bcs.ser('MyEnum', { multi: [ { value: 1 }, { value: 2 } ] });
*
* @param name
* @param variants
*/
registerEnumType(typeName, variants) {
for (let key in variants) {
let internalName = this.tempKey();
let value = variants[key];
if (value !== null && !Array.isArray(value) && typeof value !== "string") {
variants[key] = internalName;
this.registerStructType(internalName, value);
}
}
let struct = Object.freeze(variants);
let canonicalOrder = Object.keys(struct);
let { name, params: canonicalTypeParams } = this.parseTypeName(typeName);
return this.registerType(
typeName,
function encodeEnum(writer, data, typeParams, typeMap) {
if (!data) {
throw new Error(`Unable to write enum "${name}", missing data.
Received: "${data}"`);
}
if (typeof data !== "object") {
throw new Error(
`Incorrect data passed into enum "${name}", expected object with properties: "${canonicalOrder.join(
" | "
)}".
Received: "${JSON.stringify(data)}"`
);
}
let key = Object.keys(data)[0];
if (key === void 0) {
throw new Error(`Empty object passed as invariant of the enum "${name}"`);
}
let orderByte = canonicalOrder.indexOf(key);
if (orderByte === -1) {
throw new Error(
`Unknown invariant of the enum "${name}", allowed values: "${canonicalOrder.join(
" | "
)}"; received "${key}"`
);
}
let invariant = canonicalOrder[orderByte];
let invariantType = struct[invariant];
writer.write8(orderByte);
if (invariantType === null) {
return writer;
}
let paramIndex = canonicalTypeParams.indexOf(invariantType);
let typeOrParam = paramIndex === -1 ? invariantType : typeParams[paramIndex];
{
let { name: name2, params } = this.parseTypeName(typeOrParam);
return this.getTypeInterface(name2)._encodeRaw.call(
this,
writer,
data[key],
params,
typeMap
);
}
},
function decodeEnum(reader, typeParams, typeMap) {
let orderByte = reader.readULEB();
let invariant = canonicalOrder[orderByte];
let invariantType = struct[invariant];
if (orderByte === -1) {
throw new Error(
`Decoding type mismatch, expected enum "${name}" invariant index, received "${orderByte}"`
);
}
if (invariantType === null) {
return { [invariant]: true };
}
let paramIndex = canonicalTypeParams.indexOf(invariantType);
let typeOrParam = paramIndex === -1 ? invariantType : typeParams[paramIndex];
{
let { name: name2, params } = this.parseTypeName(typeOrParam);
return {
[invariant]: this.getTypeInterface(name2)._decodeRaw.call(this, reader, params, typeMap)
};
}
}
);
}
/**
* Get a set of encoders/decoders for specific type.
* Mainly used to define custom type de/serialization logic.
*
* @param type
* @returns {TypeInterface}
*/
getTypeInterface(type) {
let typeInterface = this.types.get(type);
if (typeof typeInterface === "string") {
let chain = [];
while (typeof typeInterface === "string") {
if (chain.includes(typeInterface)) {
throw new Error(`Recursive definition found: ${chain.join(" -> ")} -> ${typeInterface}`);
}
chain.push(typeInterface);
typeInterface = this.types.get(typeInterface);
}
}
if (typeInterface === void 0) {
throw new Error(`Type ${type} is not registered`);
}
return typeInterface;
}
/**
* Parse a type name and get the type's generics.
* @example
* let { typeName, typeParams } = parseTypeName('Option<Coin<SUI>>');
* // typeName: Option
* // typeParams: [ 'Coin<SUI>' ]
*
* @param name Name of the type to process
* @returns Object with typeName and typeParams listed as Array
*/
parseTypeName(name) {
if (Array.isArray(name)) {
let [typeName2, ...params2] = name;
return { name: typeName2, params: params2 };
}
if (typeof name !== "string") {
throw new Error(`Illegal type passed as a name of the type: ${name}`);
}
let [left, right] = this.schema.genericSeparators || ["<", ">"];
let l_bound = name.indexOf(left);
let r_bound = Array.from(name).reverse().indexOf(right);
if (l_bound === -1 && r_bound === -1) {
return { name, params: [] };
}
if (l_bound === -1 || r_bound === -1) {
throw new Error(`Unclosed generic in name '${name}'`);
}
let typeName = name.slice(0, l_bound);
let params = splitGenericParameters(
name.slice(l_bound + 1, name.length - r_bound - 1),
this.schema.genericSeparators
);
return { name: typeName, params };
}
};
// Predefined types constants
_BCS.U8 = "u8";
_BCS.U16 = "u16";
_BCS.U32 = "u32";
_BCS.U64 = "u64";
_BCS.U128 = "u128";
_BCS.U256 = "u256";
_BCS.BOOL = "bool";
_BCS.VECTOR = "vector";
_BCS.ADDRESS = "address";
_BCS.STRING = "string";
_BCS.HEX = "hex-string";
_BCS.BASE58 = "base58-string";
_BCS.BASE64 = "base64-string";
var BCS = _BCS;
function registerPrimitives(bcs2) {
bcs2.registerType(
BCS.U8,
function(writer, data) {
return writer.write8(data);
},
function(reader) {
return reader.read8();
},
(u8) => u8 < 256
);
bcs2.registerType(
BCS.U16,
function(writer, data) {
return writer.write16(data);
},
function(reader) {
return reader.read16();
},
(u16) => u16 < 65536
);
bcs2.registerType(
BCS.U32,
function(writer, data) {
return writer.write32(data);
},
function(reader) {
return reader.read32();
},
(u32) => u32 <= 4294967296n
);
bcs2.registerType(
BCS.U64,
function(writer, data) {
return writer.write64(data);
},
function(reader) {
return reader.read64();
}
);
bcs2.registerType(
BCS.U128,
function(writer, data) {
return writer.write128(data);
},
function(reader) {
return reader.read128();
}
);
bcs2.registerType(
BCS.U256,
function(writer, data) {
return writer.write256(data);
},
function(reader) {
return reader.read256();
}
);
bcs2.registerType(
BCS.BOOL,
function(writer, data) {
return writer.write8(data);
},
function(reader) {
return reader.read8().toString(10) === "1";
}
);
bcs2.registerType(
BCS.STRING,
function(writer, data) {
return writer.writeVec(Array.from(data), (writer2, el) => writer2.write8(el.charCodeAt(0)));
},
function(reader) {
return reader.readVec((reader2) => reader2.read8()).map((el) => String.fromCharCode(Number(el))).join("");
},
(_str) => true
);
bcs2.registerType(
BCS.HEX,
function(writer, data) {
return writer.writeVec(Array.from(fromHEX(data)), (writer2, el) => writer2.write8(el));
},
function(reader) {
let bytes = reader.readVec((reader2) => reader2.read8());
return toHEX(new Uint8Array(bytes));
}
);
bcs2.registerType(
BCS.BASE58,
function(writer, data) {
return writer.writeVec(Array.from(fromB58(data)), (writer2, el) => writer2.write8(el));
},
function(reader) {
let bytes = reader.readVec((reader2) => reader2.read8());
return toB58(new Uint8Array(bytes));
}
);
bcs2.registerType(
BCS.BASE64,
function(writer, data) {
return writer.writeVec(Array.from(fromB64(data)), (writer2, el) => writer2.write8(el));
},
function(reader) {
let bytes = reader.readVec((reader2) => reader2.read8());
return toB64(new Uint8Array(bytes));
}
);
}
function getRustConfig() {
return {
genericSeparators: ["<", ">"],
vectorType: "Vec",
addressLength: SUI_ADDRESS_LENGTH,
addressEncoding: "hex"
};
}
function getSuiMoveConfig() {
return {
genericSeparators: ["<", ">"],
vectorType: "vector",
addressLength: SUI_ADDRESS_LENGTH,
addressEncoding: "hex"
};
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
BCS,
BcsReader,
BcsType,
BcsWriter,
SerializedBcs,
bcs,
decodeStr,
encodeStr,
fromB58,
fromB64,
fromHEX,
getRustConfig,
getSuiMoveConfig,
registerPrimitives,
splitGenericParameters,
toB58,
toB64,
toHEX
});
//# sourceMappingURL=index.js.map
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0
/*
* BCS implementation {@see https://github.com/diem/bcs } for JavaScript.
* Intended to be used for Move applications; supports both NodeJS and browser.
*
* For more details and examples {@see README.md }.
*
* @module bcs
* @property {BcsReader}
*/
import { fromB58, toB58 } from './b58.js';
import { fromB64, toB64 } from './b64.js';
import { BcsType, SerializedBcs } from './bcs-type.js';
import { bcs } from './bcs.js';
import { fromHEX, toHEX } from './hex.js';
import { BcsReader } from './reader.js';
import { decodeStr, encodeStr, splitGenericParameters } from './utils.js';
import { BcsWriter } from './writer.js';
export * from './legacy-registry.js';
// Re-export all encoding dependencies.
export { bcs, BcsType, SerializedBcs, toB58, fromB58, toB64, fromB64, fromHEX, toHEX, encodeStr, decodeStr, splitGenericParameters, BcsReader, BcsWriter, };

2

CHANGELOG.md
# Change Log
## 0.0.0-experimental-20230929052502
## 0.0.0-experimental-20230929184743

@@ -5,0 +5,0 @@ ### Minor Changes

@@ -1,1977 +0,22 @@

"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var __accessCheck = (obj, member, msg) => {
if (!member.has(obj))
throw TypeError("Cannot " + msg);
};
var __privateGet = (obj, member, getter) => {
__accessCheck(obj, member, "read from private field");
return getter ? getter.call(obj) : member.get(obj);
};
var __privateAdd = (obj, member, value) => {
if (member.has(obj))
throw TypeError("Cannot add the same private member more than once");
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
};
var __privateSet = (obj, member, value, setter) => {
__accessCheck(obj, member, "write to private field");
setter ? setter.call(obj, value) : member.set(obj, value);
return value;
};
// src/index.ts
var src_exports = {};
__export(src_exports, {
BCS: () => BCS,
BcsReader: () => BcsReader,
BcsType: () => BcsType,
BcsWriter: () => BcsWriter,
SerializedBcs: () => SerializedBcs,
bcs: () => bcs,
decodeStr: () => decodeStr,
encodeStr: () => encodeStr,
fromB58: () => fromB58,
fromB64: () => fromB64,
fromHEX: () => fromHEX,
getRustConfig: () => getRustConfig,
getSuiMoveConfig: () => getSuiMoveConfig,
registerPrimitives: () => registerPrimitives,
splitGenericParameters: () => splitGenericParameters,
toB58: () => toB58,
toB64: () => toB64,
toHEX: () => toHEX
});
module.exports = __toCommonJS(src_exports);
// src/b58.ts
var import_bs58 = __toESM(require("bs58"));
var toB58 = (buffer) => import_bs58.default.encode(buffer);
var fromB58 = (str) => import_bs58.default.decode(str);
// src/b64.ts
function b64ToUint6(nChr) {
return nChr > 64 && nChr < 91 ? nChr - 65 : nChr > 96 && nChr < 123 ? nChr - 71 : nChr > 47 && nChr < 58 ? nChr + 4 : nChr === 43 ? 62 : nChr === 47 ? 63 : 0;
}
function fromB64(sBase64, nBlocksSize) {
var sB64Enc = sBase64.replace(/[^A-Za-z0-9+/]/g, ""), nInLen = sB64Enc.length, nOutLen = nBlocksSize ? Math.ceil((nInLen * 3 + 1 >> 2) / nBlocksSize) * nBlocksSize : nInLen * 3 + 1 >> 2, taBytes = new Uint8Array(nOutLen);
for (var nMod3, nMod4, nUint24 = 0, nOutIdx = 0, nInIdx = 0; nInIdx < nInLen; nInIdx++) {
nMod4 = nInIdx & 3;
nUint24 |= b64ToUint6(sB64Enc.charCodeAt(nInIdx)) << 6 * (3 - nMod4);
if (nMod4 === 3 || nInLen - nInIdx === 1) {
for (nMod3 = 0; nMod3 < 3 && nOutIdx < nOutLen; nMod3++, nOutIdx++) {
taBytes[nOutIdx] = nUint24 >>> (16 >>> nMod3 & 24) & 255;
}
nUint24 = 0;
}
}
return taBytes;
}
function uint6ToB64(nUint6) {
return nUint6 < 26 ? nUint6 + 65 : nUint6 < 52 ? nUint6 + 71 : nUint6 < 62 ? nUint6 - 4 : nUint6 === 62 ? 43 : nUint6 === 63 ? 47 : 65;
}
function toB64(aBytes) {
var nMod3 = 2, sB64Enc = "";
for (var nLen = aBytes.length, nUint24 = 0, nIdx = 0; nIdx < nLen; nIdx++) {
nMod3 = nIdx % 3;
nUint24 |= aBytes[nIdx] << (16 >>> nMod3 & 24);
if (nMod3 === 2 || aBytes.length - nIdx === 1) {
sB64Enc += String.fromCodePoint(
uint6ToB64(nUint24 >>> 18 & 63),
uint6ToB64(nUint24 >>> 12 & 63),
uint6ToB64(nUint24 >>> 6 & 63),
uint6ToB64(nUint24 & 63)
);
nUint24 = 0;
}
}
return sB64Enc.slice(0, sB64Enc.length - 2 + nMod3) + (nMod3 === 2 ? "" : nMod3 === 1 ? "=" : "==");
}
// src/hex.ts
function fromHEX(hexStr) {
const normalized = hexStr.startsWith("0x") ? hexStr.slice(2) : hexStr;
const padded = normalized.length % 2 === 0 ? normalized : `0${normalized}}`;
const intArr = padded.match(/.{2}/g)?.map((byte) => parseInt(byte, 16)) ?? [];
return Uint8Array.from(intArr);
}
function toHEX(bytes) {
return bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, "0"), "");
}
// src/uleb.ts
function ulebEncode(num) {
let arr = [];
let len = 0;
if (num === 0) {
return [0];
}
while (num > 0) {
arr[len] = num & 127;
if (num >>= 7) {
arr[len] |= 128;
}
len += 1;
}
return arr;
}
function ulebDecode(arr) {
let total = 0;
let shift = 0;
let len = 0;
while (true) {
let byte = arr[len];
len += 1;
total |= (byte & 127) << shift;
if ((byte & 128) === 0) {
break;
}
shift += 7;
}
return {
value: total,
length: len
};
}
// src/reader.ts
var BcsReader = class {
/**
* @param {Uint8Array} data Data to use as a buffer.
*/
constructor(data) {
this.bytePosition = 0;
this.dataView = new DataView(data.buffer);
}
/**
* Shift current cursor position by `bytes`.
*
* @param {Number} bytes Number of bytes to
* @returns {this} Self for possible chaining.
*/
shift(bytes) {
this.bytePosition += bytes;
return this;
}
/**
* Read U8 value from the buffer and shift cursor by 1.
* @returns
*/
read8() {
let value = this.dataView.getUint8(this.bytePosition);
this.shift(1);
return value;
}
/**
* Read U16 value from the buffer and shift cursor by 2.
* @returns
*/
read16() {
let value = this.dataView.getUint16(this.bytePosition, true);
this.shift(2);
return value;
}
/**
* Read U32 value from the buffer and shift cursor by 4.
* @returns
*/
read32() {
let value = this.dataView.getUint32(this.bytePosition, true);
this.shift(4);
return value;
}
/**
* Read U64 value from the buffer and shift cursor by 8.
* @returns
*/
read64() {
let value1 = this.read32();
let value2 = this.read32();
let result = value2.toString(16) + value1.toString(16).padStart(8, "0");
return BigInt("0x" + result).toString(10);
}
/**
* Read U128 value from the buffer and shift cursor by 16.
*/
read128() {
let value1 = BigInt(this.read64());
let value2 = BigInt(this.read64());
let result = value2.toString(16) + value1.toString(16).padStart(16, "0");
return BigInt("0x" + result).toString(10);
}
/**
* Read U128 value from the buffer and shift cursor by 32.
* @returns
*/
read256() {
let value1 = BigInt(this.read128());
let value2 = BigInt(this.read128());
let result = value2.toString(16) + value1.toString(16).padStart(32, "0");
return BigInt("0x" + result).toString(10);
}
/**
* Read `num` number of bytes from the buffer and shift cursor by `num`.
* @param num Number of bytes to read.
*/
readBytes(num) {
let start = this.bytePosition + this.dataView.byteOffset;
let value = new Uint8Array(this.dataView.buffer, start, num);
this.shift(num);
return value;
}
/**
* Read ULEB value - an integer of varying size. Used for enum indexes and
* vector lengths.
* @returns {Number} The ULEB value.
*/
readULEB() {
let start = this.bytePosition + this.dataView.byteOffset;
let buffer = new Uint8Array(this.dataView.buffer, start);
let { value, length } = ulebDecode(buffer);
this.shift(length);
return value;
}
/**
* Read a BCS vector: read a length and then apply function `cb` X times
* where X is the length of the vector, defined as ULEB in BCS bytes.
* @param cb Callback to process elements of vector.
* @returns {Array<Any>} Array of the resulting values, returned by callback.
*/
readVec(cb) {
let length = this.readULEB();
let result = [];
for (let i = 0; i < length; i++) {
result.push(cb(this, i, length));
}
return result;
}
};
// src/utils.ts
function encodeStr(data, encoding) {
switch (encoding) {
case "base58":
return toB58(data);
case "base64":
return toB64(data);
case "hex":
return toHEX(data);
default:
throw new Error("Unsupported encoding, supported values are: base64, hex");
}
}
function decodeStr(data, encoding) {
switch (encoding) {
case "base58":
return fromB58(data);
case "base64":
return fromB64(data);
case "hex":
return fromHEX(data);
default:
throw new Error("Unsupported encoding, supported values are: base64, hex");
}
}
function splitGenericParameters(str, genericSeparators = ["<", ">"]) {
const [left, right] = genericSeparators;
const tok = [];
let word = "";
let nestedAngleBrackets = 0;
for (let i = 0; i < str.length; i++) {
const char = str[i];
if (char === left) {
nestedAngleBrackets++;
}
if (char === right) {
nestedAngleBrackets--;
}
if (nestedAngleBrackets === 0 && char === ",") {
tok.push(word.trim());
word = "";
continue;
}
word += char;
}
tok.push(word.trim());
return tok;
}
// src/writer.ts
var BcsWriter = class {
constructor({ size = 1024, maxSize, allocateSize = 1024 } = {}) {
this.bytePosition = 0;
this.size = size;
this.maxSize = maxSize || size;
this.allocateSize = allocateSize;
this.dataView = new DataView(new ArrayBuffer(size));
}
ensureSizeOrGrow(bytes) {
const requiredSize = this.bytePosition + bytes;
if (requiredSize > this.size) {
const nextSize = Math.min(this.maxSize, this.size + this.allocateSize);
if (requiredSize > nextSize) {
throw new Error(
`Attempting to serialize to BCS, but buffer does not have enough size. Allocated size: ${this.size}, Max size: ${this.maxSize}, Required size: ${requiredSize}`
);
}
this.size = nextSize;
const nextBuffer = new ArrayBuffer(this.size);
new Uint8Array(nextBuffer).set(new Uint8Array(this.dataView.buffer));
this.dataView = new DataView(nextBuffer);
}
}
/**
* Shift current cursor position by `bytes`.
*
* @param {Number} bytes Number of bytes to
* @returns {this} Self for possible chaining.
*/
shift(bytes) {
this.bytePosition += bytes;
return this;
}
/**
* Write a U8 value into a buffer and shift cursor position by 1.
* @param {Number} value Value to write.
* @returns {this}
*/
write8(value) {
this.ensureSizeOrGrow(1);
this.dataView.setUint8(this.bytePosition, Number(value));
return this.shift(1);
}
/**
* Write a U16 value into a buffer and shift cursor position by 2.
* @param {Number} value Value to write.
* @returns {this}
*/
write16(value) {
this.ensureSizeOrGrow(2);
this.dataView.setUint16(this.bytePosition, Number(value), true);
return this.shift(2);
}
/**
* Write a U32 value into a buffer and shift cursor position by 4.
* @param {Number} value Value to write.
* @returns {this}
*/
write32(value) {
this.ensureSizeOrGrow(4);
this.dataView.setUint32(this.bytePosition, Number(value), true);
return this.shift(4);
}
/**
* Write a U64 value into a buffer and shift cursor position by 8.
* @param {bigint} value Value to write.
* @returns {this}
*/
write64(value) {
toLittleEndian(BigInt(value), 8).forEach((el) => this.write8(el));
return this;
}
/**
* Write a U128 value into a buffer and shift cursor position by 16.
*
* @param {bigint} value Value to write.
* @returns {this}
*/
write128(value) {
toLittleEndian(BigInt(value), 16).forEach((el) => this.write8(el));
return this;
}
/**
* Write a U256 value into a buffer and shift cursor position by 16.
*
* @param {bigint} value Value to write.
* @returns {this}
*/
write256(value) {
toLittleEndian(BigInt(value), 32).forEach((el) => this.write8(el));
return this;
}
/**
* Write a ULEB value into a buffer and shift cursor position by number of bytes
* written.
* @param {Number} value Value to write.
* @returns {this}
*/
writeULEB(value) {
ulebEncode(value).forEach((el) => this.write8(el));
return this;
}
/**
* Write a vector into a buffer by first writing the vector length and then calling
* a callback on each passed value.
*
* @param {Array<Any>} vector Array of elements to write.
* @param {WriteVecCb} cb Callback to call on each element of the vector.
* @returns {this}
*/
writeVec(vector, cb) {
this.writeULEB(vector.length);
Array.from(vector).forEach((el, i) => cb(this, el, i, vector.length));
return this;
}
/**
* Adds support for iterations over the object.
* @returns {Uint8Array}
*/
*[Symbol.iterator]() {
for (let i = 0; i < this.bytePosition; i++) {
yield this.dataView.getUint8(i);
}
return this.toBytes();
}
/**
* Get underlying buffer taking only value bytes (in case initial buffer size was bigger).
* @returns {Uint8Array} Resulting bcs.
*/
toBytes() {
return new Uint8Array(this.dataView.buffer.slice(0, this.bytePosition));
}
/**
* Represent data as 'hex' or 'base64'
* @param encoding Encoding to use: 'base64' or 'hex'
*/
toString(encoding) {
return encodeStr(this.toBytes(), encoding);
}
};
function toLittleEndian(bigint, size) {
let result = new Uint8Array(size);
let i = 0;
while (bigint > 0) {
result[i] = Number(bigint % BigInt(256));
bigint = bigint / BigInt(256);
i += 1;
}
return result;
}
// src/bcs-type.ts
var _write, _serialize;
var _BcsType = class _BcsType {
constructor(options) {
__privateAdd(this, _write, void 0);
__privateAdd(this, _serialize, void 0);
this.name = options.name;
this.read = options.read;
this.serializedSize = options.serializedSize ?? (() => null);
__privateSet(this, _write, options.write);
__privateSet(this, _serialize, options.serialize ?? ((value, options2) => {
const writer = new BcsWriter({ size: this.serializedSize(value) ?? void 0, ...options2 });
__privateGet(this, _write).call(this, value, writer);
return writer.toBytes();
}));
this.validate = options.validate ?? (() => {
});
}
write(value, writer) {
this.validate(value);
__privateGet(this, _write).call(this, value, writer);
}
serialize(value, options) {
this.validate(value);
return new SerializedBcs(this, __privateGet(this, _serialize).call(this, value, options));
}
parse(bytes) {
const reader = new BcsReader(bytes);
return this.read(reader);
}
transform({
name,
input,
output
}) {
return new _BcsType({
name: name ?? this.name,
read: (reader) => output(this.read(reader)),
write: (value, writer) => __privateGet(this, _write).call(this, input(value), writer),
serializedSize: (value) => this.serializedSize(input(value)),
serialize: (value, options) => __privateGet(this, _serialize).call(this, input(value), options),
validate: (value) => this.validate(input(value))
});
}
};
_write = new WeakMap();
_serialize = new WeakMap();
var BcsType = _BcsType;
var _schema, _bytes;
var SerializedBcs = class {
constructor(type, schema) {
__privateAdd(this, _schema, void 0);
__privateAdd(this, _bytes, void 0);
__privateSet(this, _schema, type);
__privateSet(this, _bytes, schema);
}
toBytes() {
return __privateGet(this, _bytes);
}
toHex() {
return toHEX(__privateGet(this, _bytes));
}
toBase64() {
return toB64(__privateGet(this, _bytes));
}
toBase58() {
return toB58(__privateGet(this, _bytes));
}
parse() {
return __privateGet(this, _schema).parse(__privateGet(this, _bytes));
}
};
_schema = new WeakMap();
_bytes = new WeakMap();
function fixedSizeBcsType({
size,
...options
}) {
return new BcsType({
...options,
serializedSize: () => size
});
}
function uIntBcsType({
readMethod,
writeMethod,
...options
}) {
return fixedSizeBcsType({
...options,
read: (reader) => reader[readMethod](),
write: (value, writer) => writer[writeMethod](value),
validate: (value) => {
if (value < 0 || value > options.maxValue) {
throw new TypeError(
`Invalid ${options.name} value: ${value}. Expected value in range 0-${options.maxValue}`
);
}
options.validate?.(value);
}
});
}
function bigUIntBcsType({
readMethod,
writeMethod,
...options
}) {
return fixedSizeBcsType({
...options,
read: (reader) => reader[readMethod](),
write: (value, writer) => writer[writeMethod](BigInt(value)),
validate: (val) => {
const value = BigInt(val);
if (value < 0 || value > options.maxValue) {
throw new TypeError(
`Invalid ${options.name} value: ${value}. Expected value in range 0-${options.maxValue}`
);
}
options.validate?.(value);
}
});
}
function dynamicSizeBcsType({
serialize,
...options
}) {
const type = new BcsType({
...options,
serialize,
write: (value, writer) => {
for (const byte of type.serialize(value).toBytes()) {
writer.write8(byte);
}
}
});
return type;
}
function stringLikeBcsType({
toBytes,
fromBytes,
...options
}) {
return new BcsType({
...options,
read: (reader) => {
const length = reader.readULEB();
const bytes = reader.readBytes(length);
return fromBytes(bytes);
},
write: (hex, writer) => {
const bytes = toBytes(hex);
writer.writeULEB(bytes.length);
for (let i = 0; i < bytes.length; i++) {
writer.write8(bytes[i]);
}
},
serialize: (value) => {
const bytes = toBytes(value);
const size = ulebEncode(bytes.length);
const result = new Uint8Array(size.length + bytes.length);
result.set(size, 0);
result.set(bytes, size.length);
return result;
},
validate: (value) => {
if (typeof value !== "string") {
throw new TypeError(`Invalid ${options.name} value: ${value}. Expected string`);
}
options.validate?.(value);
}
});
}
function lazyBcsType(cb) {
let lazyType = null;
function getType() {
if (!lazyType) {
lazyType = cb();
}
return lazyType;
}
return new BcsType({
name: "lazy",
read: (data) => getType().read(data),
serializedSize: (value) => getType().serializedSize(value),
write: (value, writer) => getType().write(value, writer),
serialize: (value, options) => getType().serialize(value, options).toBytes()
});
}
// src/bcs.ts
var bcs = {
/**
* Creates a BcsType that can be used to read and write an 8-bit unsigned integer.
* @example
* bcs.u8().serialize(255).toBytes() // Uint8Array [ 255 ]
*/
u8(options) {
return uIntBcsType({
name: "u8",
readMethod: "read8",
writeMethod: "write8",
size: 1,
maxValue: 2 ** 8 - 1,
...options
});
},
/**
* Creates a BcsType that can be used to read and write a 16-bit unsigned integer.
* @example
* bcs.u16().serialize(65535).toBytes() // Uint8Array [ 255, 255 ]
*/
u16(options) {
return uIntBcsType({
name: "u16",
readMethod: "read16",
writeMethod: "write16",
size: 2,
maxValue: 2 ** 16 - 1,
...options
});
},
/**
* Creates a BcsType that can be used to read and write a 32-bit unsigned integer.
* @example
* bcs.u32().serialize(4294967295).toBytes() // Uint8Array [ 255, 255, 255, 255 ]
*/
u32(options) {
return uIntBcsType({
name: "u32",
readMethod: "read32",
writeMethod: "write32",
size: 4,
maxValue: 2 ** 32 - 1,
...options
});
},
/**
* Creates a BcsType that can be used to read and write a 64-bit unsigned integer.
* @example
* bcs.u64().serialize(1).toBytes() // Uint8Array [ 1, 0, 0, 0, 0, 0, 0, 0 ]
*/
u64(options) {
return bigUIntBcsType({
name: "u64",
readMethod: "read64",
writeMethod: "write64",
size: 8,
maxValue: 2n ** 64n - 1n,
...options
});
},
/**
* Creates a BcsType that can be used to read and write a 128-bit unsigned integer.
* @example
* bcs.u128().serialize(1).toBytes() // Uint8Array [ 1, ..., 0 ]
*/
u128(options) {
return bigUIntBcsType({
name: "u128",
readMethod: "read128",
writeMethod: "write128",
size: 16,
maxValue: 2n ** 128n - 1n,
...options
});
},
/**
* Creates a BcsType that can be used to read and write a 256-bit unsigned integer.
* @example
* bcs.u256().serialize(1).toBytes() // Uint8Array [ 1, ..., 0 ]
*/
u256(options) {
return bigUIntBcsType({
name: "u256",
readMethod: "read256",
writeMethod: "write256",
size: 32,
maxValue: 2n ** 256n - 1n,
...options
});
},
/**
* Creates a BcsType that can be used to read and write boolean values.
* @example
* bcs.bool().serialize(true).toBytes() // Uint8Array [ 1 ]
*/
bool(options) {
return fixedSizeBcsType({
name: "bool",
size: 1,
read: (reader) => reader.read8() === 1,
write: (value, writer) => writer.write8(value ? 1 : 0),
...options,
validate: (value) => {
options?.validate?.(value);
if (typeof value !== "boolean") {
throw new TypeError(`Expected boolean, found ${typeof value}`);
}
}
});
},
/**
* Creates a BcsType that can be used to read and write unsigned LEB encoded integers
* @example
*
*/
uleb128(options) {
return dynamicSizeBcsType({
name: "uleb128",
read: (reader) => reader.readULEB(),
serialize: (value) => {
return Uint8Array.from(ulebEncode(value));
},
...options
});
},
/**
* Creates a BcsType representing a fixed length byte array
* @param size The number of bytes this types represents
* @example
* bcs.bytes(3).serialize(new Uint8Array([1, 2, 3])).toBytes() // Uint8Array [1, 2, 3]
*/
bytes(size, options) {
return fixedSizeBcsType({
name: `bytes[${size}]`,
size,
read: (reader) => reader.readBytes(size),
write: (value, writer) => {
for (let i = 0; i < size; i++) {
writer.write8(value[i] ?? 0);
}
},
...options,
validate: (value) => {
options?.validate?.(value);
if (!("length" in value)) {
throw new TypeError(`Expected array, found ${typeof value}`);
}
if (value.length !== size) {
throw new TypeError(`Expected array of length ${size}, found ${value.length}`);
}
}
});
},
/**
* Creates a BcsType that can ser/de string values. Strings will be UTF-8 encoded
* @example
* bcs.string().serialize('a').toBytes() // Uint8Array [ 1, 97 ]
*/
string(options) {
return stringLikeBcsType({
name: "string",
toBytes: (value) => new TextEncoder().encode(value),
fromBytes: (bytes) => new TextDecoder().decode(bytes),
...options
});
},
/**
* Creates a BcsType that represents a fixed length array of a given type
* @param size The number of elements in the array
* @param type The BcsType of each element in the array
* @example
* bcs.fixedArray(3, bcs.u8()).serialize([1, 2, 3]).toBytes() // Uint8Array [ 1, 2, 3 ]
*/
fixedArray(size, type, options) {
return new BcsType({
name: `${type.name}[${size}]`,
read: (reader) => {
const result = new Array(size);
for (let i = 0; i < size; i++) {
result[i] = type.read(reader);
}
return result;
},
write: (value, writer) => {
for (const item of value) {
type.write(item, writer);
}
},
...options,
validate: (value) => {
options?.validate?.(value);
if (!("length" in value)) {
throw new TypeError(`Expected array, found ${typeof value}`);
}
if (value.length !== size) {
throw new TypeError(`Expected array of length ${size}, found ${value.length}`);
}
}
});
},
/**
* Creates a BcsType representing an optional value
* @param type The BcsType of the optional value
* @example
* bcs.option(bcs.u8()).serialize(null).toBytes() // Uint8Array [ 0 ]
* bcs.option(bcs.u8()).serialize(1).toBytes() // Uint8Array [ 1, 1 ]
*/
option(type) {
return bcs.enum(`Option<${type.name}>`, {
None: null,
Some: type
}).transform({
input: (value) => {
if (value == null) {
return { None: true };
}
return { Some: value };
},
output: (value) => {
if ("Some" in value) {
return value.Some;
}
return null;
}
});
},
/**
* Creates a BcsType representing a variable length vector of a given type
* @param type The BcsType of each element in the vector
*
* @example
* bcs.vector(bcs.u8()).toBytes([1, 2, 3]) // Uint8Array [ 3, 1, 2, 3 ]
*/
vector(type, options) {
return new BcsType({
name: `vector<${type.name}>`,
read: (reader) => {
const length = reader.readULEB();
const result = new Array(length);
for (let i = 0; i < length; i++) {
result[i] = type.read(reader);
}
return result;
},
write: (value, writer) => {
writer.writeULEB(value.length);
for (const item of value) {
type.write(item, writer);
}
},
...options,
validate: (value) => {
options?.validate?.(value);
if (!("length" in value)) {
throw new TypeError(`Expected array, found ${typeof value}`);
}
}
});
},
/**
* Creates a BcsType representing a tuple of a given set of types
* @param types The BcsTypes for each element in the tuple
*
* @example
* const tuple = bcs.tuple([bcs.u8(), bcs.string(), bcs.bool()])
* tuple.serialize([1, 'a', true]).toBytes() // Uint8Array [ 1, 1, 97, 1 ]
*/
tuple(types, options) {
return new BcsType({
name: `(${types.map((t) => t.name).join(", ")})`,
serializedSize: (values) => {
let total = 0;
for (let i = 0; i < types.length; i++) {
const size = types[i].serializedSize(values[i]);
if (size == null) {
return null;
}
total += size;
}
return total;
},
read: (reader) => {
const result = [];
for (const type of types) {
result.push(type.read(reader));
}
return result;
},
write: (value, writer) => {
for (let i = 0; i < types.length; i++) {
types[i].write(value[i], writer);
}
},
...options,
validate: (value) => {
options?.validate?.(value);
if (!Array.isArray(value)) {
throw new TypeError(`Expected array, found ${typeof value}`);
}
if (value.length !== types.length) {
throw new TypeError(`Expected array of length ${types.length}, found ${value.length}`);
}
}
});
},
/**
* Creates a BcsType representing a struct of a given set of fields
* @param name The name of the struct
* @param fields The fields of the struct. The order of the fields affects how data is serialized and deserialized
*
* @example
* const struct = bcs.struct('MyStruct', {
* a: bcs.u8(),
* b: bcs.string(),
* })
* struct.serialize({ a: 1, b: 'a' }).toBytes() // Uint8Array [ 1, 1, 97 ]
*/
struct(name, fields, options) {
const canonicalOrder = Object.entries(fields);
return new BcsType({
name,
serializedSize: (values) => {
let total = 0;
for (const [field, type] of canonicalOrder) {
const size = type.serializedSize(values[field]);
if (size == null) {
return null;
}
total += size;
}
return total;
},
read: (reader) => {
const result = {};
for (const [field, type] of canonicalOrder) {
result[field] = type.read(reader);
}
return result;
},
write: (value, writer) => {
for (const [field, type] of canonicalOrder) {
type.write(value[field], writer);
}
},
...options,
validate: (value) => {
options?.validate?.(value);
if (typeof value !== "object" || value == null) {
throw new TypeError(`Expected object, found ${typeof value}`);
}
}
});
},
/**
* Creates a BcsType representing an enum of a given set of options
* @param name The name of the enum
* @param values The values of the enum. The order of the values affects how data is serialized and deserialized.
* null can be used to represent a variant with no data.
*
* @example
* const enum = bcs.enum('MyEnum', {
* A: bcs.u8(),
* B: bcs.string(),
* C: null,
* })
* enum.serialize({ A: 1 }).toBytes() // Uint8Array [ 0, 1 ]
* enum.serialize({ B: 'a' }).toBytes() // Uint8Array [ 1, 1, 97 ]
* enum.serialize({ C: true }).toBytes() // Uint8Array [ 2 ]
*/
enum(name, values, options) {
const canonicalOrder = Object.entries(values);
return new BcsType({
name,
read: (reader) => {
const index = reader.readULEB();
const [name2, type] = canonicalOrder[index];
return {
[name2]: type?.read(reader) ?? true
};
},
write: (value, writer) => {
const [name2, val] = Object.entries(value)[0];
for (let i = 0; i < canonicalOrder.length; i++) {
const [optionName, optionType] = canonicalOrder[i];
if (optionName === name2) {
writer.writeULEB(i);
optionType?.write(val, writer);
return;
}
}
},
...options,
validate: (value) => {
options?.validate?.(value);
if (typeof value !== "object" || value == null) {
throw new TypeError(`Expected object, found ${typeof value}`);
}
const keys = Object.keys(value);
if (keys.length !== 1) {
throw new TypeError(`Expected object with one key, found ${keys.length}`);
}
const [name2] = keys;
if (!Object.hasOwn(values, name2)) {
throw new TypeError(`Invalid enum variant ${name2}`);
}
}
});
},
/**
* Creates a BcsType representing a map of a given key and value type
* @param keyType The BcsType of the key
* @param valueType The BcsType of the value
* @example
* const map = bcs.map(bcs.u8(), bcs.string())
* map.serialize(new Map([[2, 'a']])).toBytes() // Uint8Array [ 1, 2, 1, 97 ]
*/
map(keyType, valueType) {
return bcs.vector(bcs.tuple([keyType, valueType])).transform({
name: `Map<${keyType.name}, ${valueType.name}>`,
input: (value) => {
return [...value.entries()];
},
output: (value) => {
const result = /* @__PURE__ */ new Map();
for (const [key, val] of value) {
result.set(key, val);
}
return result;
}
});
},
/**
* Creates a helper function representing a generic type. This method returns
* a function that can be used to create concrete version of the generic type.
* @param names The names of the generic parameters
* @param cb A callback that returns the generic type
* @example
* const MyStruct = bcs.generic(['T'], (T) => bcs.struct('MyStruct', { inner: T }))
* MyStruct(bcs.u8()).serialize({ inner: 1 }).toBytes() // Uint8Array [ 1 ]
* MyStruct(bcs.string()).serialize({ inner: 'a' }).toBytes() // Uint8Array [ 1, 97 ]
*/
generic(names, cb) {
return (...types) => {
return cb(...types).transform({
name: `${cb.name}<${types.map((t) => t.name).join(", ")}>`,
input: (value) => value,
output: (value) => value
});
};
},
/**
* Creates a BcsType that wraps another BcsType which is lazily evaluated. This is useful for creating recursive types.
* @param cb A callback that returns the BcsType
*/
lazy(cb) {
return lazyBcsType(cb);
}
};
// src/legacy-registry.ts
var SUI_ADDRESS_LENGTH = 32;
var _BCS = class _BCS {
/**
* Construct a BCS instance with a prepared schema.
*
* @param schema A prepared schema with type definitions
* @param withPrimitives Whether to register primitive types by default
*/
constructor(schema) {
/**
* Map of kind `TypeName => TypeInterface`. Holds all
* callbacks for (de)serialization of every registered type.
*
* If the value stored is a string, it is treated as an alias.
*/
this.types = /* @__PURE__ */ new Map();
/**
* Count temp keys to generate a new one when requested.
*/
this.counter = 0;
if (schema instanceof _BCS) {
this.schema = schema.schema;
this.types = new Map(schema.types);
return;
}
this.schema = schema;
this.registerAddressType(_BCS.ADDRESS, schema.addressLength, schema.addressEncoding);
this.registerVectorType(schema.vectorType);
if (schema.types && schema.types.structs) {
for (let name of Object.keys(schema.types.structs)) {
this.registerStructType(name, schema.types.structs[name]);
}
}
if (schema.types && schema.types.enums) {
for (let name of Object.keys(schema.types.enums)) {
this.registerEnumType(name, schema.types.enums[name]);
}
}
if (schema.types && schema.types.aliases) {
for (let name of Object.keys(schema.types.aliases)) {
this.registerAlias(name, schema.types.aliases[name]);
}
}
if (schema.withPrimitives !== false) {
registerPrimitives(this);
}
}
/**
* Name of the key to use for temporary struct definitions.
* Returns a temp key + index (for a case when multiple temp
* structs are processed).
*/
tempKey() {
return `bcs-struct-${++this.counter}`;
}
/**
* Serialize data into bcs.
*
* @example
* bcs.registerVectorType('vector<u8>', 'u8');
*
* let serialized = BCS
* .set('vector<u8>', [1,2,3,4,5,6])
* .toBytes();
*
* console.assert(toHex(serialized) === '06010203040506');
*
* @param type Name of the type to serialize (must be registered) or a struct type.
* @param data Data to serialize.
* @param size Serialization buffer size. Default 1024 = 1KB.
* @return A BCS reader instance. Usually you'd want to call `.toBytes()`
*/
ser(type, data, options) {
if (typeof type === "string" || Array.isArray(type)) {
const { name, params } = this.parseTypeName(type);
return this.getTypeInterface(name).encode(this, data, options, params);
}
if (typeof type === "object") {
const key = this.tempKey();
const temp = new _BCS(this);
return temp.registerStructType(key, type).ser(key, data, options);
}
throw new Error(`Incorrect type passed into the '.ser()' function.
${JSON.stringify(type)}`);
}
/**
* Deserialize BCS into a JS type.
*
* @example
* let num = bcs.ser('u64', '4294967295').toString('hex');
* let deNum = bcs.de('u64', num, 'hex');
* console.assert(deNum.toString(10) === '4294967295');
*
* @param type Name of the type to deserialize (must be registered) or a struct type definition.
* @param data Data to deserialize.
* @param encoding Optional - encoding to use if data is of type String
* @return Deserialized data.
*/
de(type, data, encoding) {
if (typeof data === "string") {
if (encoding) {
data = decodeStr(data, encoding);
} else {
throw new Error("To pass a string to `bcs.de`, specify encoding");
}
}
if (typeof type === "string" || Array.isArray(type)) {
const { name, params } = this.parseTypeName(type);
return this.getTypeInterface(name).decode(this, data, params);
}
if (typeof type === "object") {
const temp = new _BCS(this);
const key = this.tempKey();
return temp.registerStructType(key, type).de(key, data, encoding);
}
throw new Error(`Incorrect type passed into the '.de()' function.
${JSON.stringify(type)}`);
}
/**
* Check whether a `TypeInterface` has been loaded for a `type`.
* @param type Name of the type to check.
* @returns
*/
hasType(type) {
return this.types.has(type);
}
/**
* Create an alias for a type.
* WARNING: this can potentially lead to recursion
* @param name Alias to use
* @param forType Type to reference
* @returns
*
* @example
* ```
* let bcs = new BCS(getSuiMoveConfig());
* bcs.registerAlias('ObjectDigest', BCS.BASE58);
* let b58_digest = bcs.de('ObjectDigest', '<digest_bytes>', 'base64');
* ```
*/
registerAlias(name, forType) {
this.types.set(name, forType);
return this;
}
/**
* Method to register new types for BCS internal representation.
* For each registered type 2 callbacks must be specified and one is optional:
*
* - encodeCb(writer, data) - write a way to serialize data with BcsWriter;
* - decodeCb(reader) - write a way to deserialize data with BcsReader;
* - validateCb(data) - validate data - either return bool or throw an error
*
* @example
* // our type would be a string that consists only of numbers
* bcs.registerType('number_string',
* (writer, data) => writer.writeVec(data, (w, el) => w.write8(el)),
* (reader) => reader.readVec((r) => r.read8()).join(''), // read each value as u8
* (value) => /[0-9]+/.test(value) // test that it has at least one digit
* );
* console.log(Array.from(bcs.ser('number_string', '12345').toBytes()) == [5,1,2,3,4,5]);
*
* @param name
* @param encodeCb Callback to encode a value.
* @param decodeCb Callback to decode a value.
* @param validateCb Optional validator Callback to check type before serialization.
*/
registerType(typeName, encodeCb, decodeCb, validateCb = () => true) {
const { name, params: generics } = this.parseTypeName(typeName);
this.types.set(name, {
encode(self, data, options, typeParams) {
const typeMap = generics.reduce((acc, value, index) => {
return Object.assign(acc, { [value]: typeParams[index] });
}, {});
return this._encodeRaw.call(self, new BcsWriter(options), data, typeParams, typeMap);
},
decode(self, data, typeParams) {
const typeMap = generics.reduce((acc, value, index) => {
return Object.assign(acc, { [value]: typeParams[index] });
}, {});
return this._decodeRaw.call(self, new BcsReader(data), typeParams, typeMap);
},
// these methods should always be used with caution as they require pre-defined
// reader and writer and mainly exist to allow multi-field (de)serialization;
_encodeRaw(writer, data, typeParams, typeMap) {
if (validateCb(data)) {
return encodeCb.call(this, writer, data, typeParams, typeMap);
} else {
throw new Error(`Validation failed for type ${name}, data: ${data}`);
}
},
_decodeRaw(reader, typeParams, typeMap) {
return decodeCb.call(this, reader, typeParams, typeMap);
}
});
return this;
}
/**
* Method to register BcsType instances to the registry
* Types are registered with a callback that provides BcsType instances for each generic
* passed to the type.
*
* - createType(...generics) - Return a BcsType instance
*
* @example
* // our type would be a string that consists only of numbers
* bcs.registerType('Box<T>', (T) => {
* return bcs.struct({
* value: T
* });
* });
* console.log(Array.from(bcs.ser('Box<string>', '12345').toBytes()) == [5,1,2,3,4,5]);
*
* @param name
* @param createType a Callback to create the BcsType with any passed in generics
*/
registerBcsType(typeName, createType) {
this.registerType(
typeName,
(writer, data, typeParams) => {
const generics = typeParams.map(
(param) => new BcsType({
name: String(param),
write: (data2, writer2) => {
const { name, params } = this.parseTypeName(param);
const typeInterface = this.getTypeInterface(name);
const typeMap = params.reduce((acc, value, index) => {
return Object.assign(acc, { [value]: typeParams[index] });
}, {});
return typeInterface._encodeRaw.call(this, writer2, data2, params, typeMap);
},
read: () => {
throw new Error("Not implemented");
}
})
);
createType(...generics).write(data, writer);
return writer;
},
(reader, typeParams) => {
const generics = typeParams.map(
(param) => new BcsType({
name: String(param),
write: (data, writer) => {
throw new Error("Not implemented");
},
read: (reader2) => {
const { name, params } = this.parseTypeName(param);
const typeInterface = this.getTypeInterface(name);
const typeMap = params.reduce((acc, value, index) => {
return Object.assign(acc, { [value]: typeParams[index] });
}, {});
return typeInterface._decodeRaw.call(this, reader2, params, typeMap);
}
})
);
return createType(...generics).read(reader);
}
);
return this;
}
/**
* Register an address type which is a sequence of U8s of specified length.
* @example
* bcs.registerAddressType('address', SUI_ADDRESS_LENGTH);
* let addr = bcs.de('address', 'c3aca510c785c7094ac99aeaa1e69d493122444df50bb8a99dfa790c654a79af');
*
* @param name Name of the address type.
* @param length Byte length of the address.
* @param encoding Encoding to use for the address type
* @returns
*/
registerAddressType(name, length, encoding = "hex") {
switch (encoding) {
case "base64":
return this.registerType(
name,
function encodeAddress(writer, data) {
return fromB64(data).reduce((writer2, el) => writer2.write8(el), writer);
},
function decodeAddress(reader) {
return toB64(reader.readBytes(length));
}
);
case "hex":
return this.registerType(
name,
function encodeAddress(writer, data) {
return fromHEX(data).reduce((writer2, el) => writer2.write8(el), writer);
},
function decodeAddress(reader) {
return toHEX(reader.readBytes(length));
}
);
default:
throw new Error("Unsupported encoding! Use either hex or base64");
}
}
/**
* Register custom vector type inside the bcs.
*
* @example
* bcs.registerVectorType('vector<T>'); // generic registration
* let array = bcs.de('vector<u8>', '06010203040506', 'hex'); // [1,2,3,4,5,6];
* let again = bcs.ser('vector<u8>', [1,2,3,4,5,6]).toString('hex');
*
* @param name Name of the type to register
* @param elementType Optional name of the inner type of the vector
* @return Returns self for chaining.
*/
registerVectorType(typeName) {
let { name, params } = this.parseTypeName(typeName);
if (params.length > 1) {
throw new Error("Vector can have only one type parameter; got " + name);
}
return this.registerType(
typeName,
function encodeVector(writer, data, typeParams, typeMap) {
return writer.writeVec(data, (writer2, el) => {
let elementType = typeParams[0];
if (!elementType) {
throw new Error(`Incorrect number of type parameters passed a to vector '${typeName}'`);
}
let { name: name2, params: params2 } = this.parseTypeName(elementType);
if (this.hasType(name2)) {
return this.getTypeInterface(name2)._encodeRaw.call(this, writer2, el, params2, typeMap);
}
if (!(name2 in typeMap)) {
throw new Error(
`Unable to find a matching type definition for ${name2} in vector; make sure you passed a generic`
);
}
let { name: innerName, params: innerParams } = this.parseTypeName(typeMap[name2]);
return this.getTypeInterface(innerName)._encodeRaw.call(
this,
writer2,
el,
innerParams,
typeMap
);
});
},
function decodeVector(reader, typeParams, typeMap) {
return reader.readVec((reader2) => {
let elementType = typeParams[0];
if (!elementType) {
throw new Error(`Incorrect number of type parameters passed to a vector '${typeName}'`);
}
let { name: name2, params: params2 } = this.parseTypeName(elementType);
if (this.hasType(name2)) {
return this.getTypeInterface(name2)._decodeRaw.call(this, reader2, params2, typeMap);
}
if (!(name2 in typeMap)) {
throw new Error(
`Unable to find a matching type definition for ${name2} in vector; make sure you passed a generic`
);
}
let { name: innerName, params: innerParams } = this.parseTypeName(typeMap[name2]);
return this.getTypeInterface(innerName)._decodeRaw.call(
this,
reader2,
innerParams,
typeMap
);
});
}
);
}
/**
* Safe method to register a custom Move struct. The first argument is a name of the
* struct which is only used on the FrontEnd and has no affect on serialization results,
* and the second is a struct description passed as an Object.
*
* The description object MUST have the same order on all of the platforms (ie in Move
* or in Rust).
*
* @example
* // Move / Rust struct
* // struct Coin {
* // value: u64,
* // owner: vector<u8>, // name // Vec<u8> in Rust
* // is_locked: bool,
* // }
*
* bcs.registerStructType('Coin', {
* value: bcs.U64,
* owner: bcs.STRING,
* is_locked: bcs.BOOL
* });
*
* // Created in Rust with diem/bcs
* // let rust_bcs_str = '80d1b105600000000e4269672057616c6c65742047757900';
* let rust_bcs_str = [ // using an Array here as BCS works with Uint8Array
* 128, 209, 177, 5, 96, 0, 0,
* 0, 14, 66, 105, 103, 32, 87,
* 97, 108, 108, 101, 116, 32, 71,
* 117, 121, 0
* ];
*
* // Let's encode the value as well
* let test_set = bcs.ser('Coin', {
* owner: 'Big Wallet Guy',
* value: '412412400000',
* is_locked: false,
* });
*
* console.assert(Array.from(test_set.toBytes()) === rust_bcs_str, 'Whoopsie, result mismatch');
*
* @param name Name of the type to register.
* @param fields Fields of the struct. Must be in the correct order.
* @return Returns BCS for chaining.
*/
registerStructType(typeName, fields) {
for (let key in fields) {
let internalName = this.tempKey();
let value = fields[key];
if (!Array.isArray(value) && typeof value !== "string") {
fields[key] = internalName;
this.registerStructType(internalName, value);
}
}
let struct = Object.freeze(fields);
let canonicalOrder = Object.keys(struct);
let { name: structName, params: generics } = this.parseTypeName(typeName);
return this.registerType(
typeName,
function encodeStruct(writer, data, typeParams, typeMap) {
if (!data || data.constructor !== Object) {
throw new Error(`Expected ${structName} to be an Object, got: ${data}`);
}
if (typeParams.length !== generics.length) {
throw new Error(
`Incorrect number of generic parameters passed; expected: ${generics.length}, got: ${typeParams.length}`
);
}
for (let key of canonicalOrder) {
if (!(key in data)) {
throw new Error(`Struct ${structName} requires field ${key}:${struct[key]}`);
}
const { name: fieldType, params: fieldParams } = this.parseTypeName(
struct[key]
);
if (!generics.includes(fieldType)) {
this.getTypeInterface(fieldType)._encodeRaw.call(
this,
writer,
data[key],
fieldParams,
typeMap
);
} else {
const paramIdx = generics.indexOf(fieldType);
let { name, params } = this.parseTypeName(typeParams[paramIdx]);
if (this.hasType(name)) {
this.getTypeInterface(name)._encodeRaw.call(
this,
writer,
data[key],
params,
typeMap
);
continue;
}
if (!(name in typeMap)) {
throw new Error(
`Unable to find a matching type definition for ${name} in ${structName}; make sure you passed a generic`
);
}
let { name: innerName, params: innerParams } = this.parseTypeName(typeMap[name]);
this.getTypeInterface(innerName)._encodeRaw.call(
this,
writer,
data[key],
innerParams,
typeMap
);
}
}
return writer;
},
function decodeStruct(reader, typeParams, typeMap) {
if (typeParams.length !== generics.length) {
throw new Error(
`Incorrect number of generic parameters passed; expected: ${generics.length}, got: ${typeParams.length}`
);
}
let result = {};
for (let key of canonicalOrder) {
const { name: fieldName, params: fieldParams } = this.parseTypeName(
struct[key]
);
if (!generics.includes(fieldName)) {
result[key] = this.getTypeInterface(fieldName)._decodeRaw.call(
this,
reader,
fieldParams,
typeMap
);
} else {
const paramIdx = generics.indexOf(fieldName);
let { name, params } = this.parseTypeName(typeParams[paramIdx]);
if (this.hasType(name)) {
result[key] = this.getTypeInterface(name)._decodeRaw.call(
this,
reader,
params,
typeMap
);
continue;
}
if (!(name in typeMap)) {
throw new Error(
`Unable to find a matching type definition for ${name} in ${structName}; make sure you passed a generic`
);
}
let { name: innerName, params: innerParams } = this.parseTypeName(typeMap[name]);
result[key] = this.getTypeInterface(innerName)._decodeRaw.call(
this,
reader,
innerParams,
typeMap
);
}
}
return result;
}
);
}
/**
* Safe method to register custom enum type where each invariant holds the value of another type.
* @example
* bcs.registerStructType('Coin', { value: 'u64' });
* bcs.registerEnumType('MyEnum', {
* single: 'Coin',
* multi: 'vector<Coin>',
* empty: null
* });
*
* console.log(
* bcs.de('MyEnum', 'AICWmAAAAAAA', 'base64'), // { single: { value: 10000000 } }
* bcs.de('MyEnum', 'AQIBAAAAAAAAAAIAAAAAAAAA', 'base64') // { multi: [ { value: 1 }, { value: 2 } ] }
* )
*
* // and serialization
* bcs.ser('MyEnum', { single: { value: 10000000 } }).toBytes();
* bcs.ser('MyEnum', { multi: [ { value: 1 }, { value: 2 } ] });
*
* @param name
* @param variants
*/
registerEnumType(typeName, variants) {
for (let key in variants) {
let internalName = this.tempKey();
let value = variants[key];
if (value !== null && !Array.isArray(value) && typeof value !== "string") {
variants[key] = internalName;
this.registerStructType(internalName, value);
}
}
let struct = Object.freeze(variants);
let canonicalOrder = Object.keys(struct);
let { name, params: canonicalTypeParams } = this.parseTypeName(typeName);
return this.registerType(
typeName,
function encodeEnum(writer, data, typeParams, typeMap) {
if (!data) {
throw new Error(`Unable to write enum "${name}", missing data.
Received: "${data}"`);
}
if (typeof data !== "object") {
throw new Error(
`Incorrect data passed into enum "${name}", expected object with properties: "${canonicalOrder.join(
" | "
)}".
Received: "${JSON.stringify(data)}"`
);
}
let key = Object.keys(data)[0];
if (key === void 0) {
throw new Error(`Empty object passed as invariant of the enum "${name}"`);
}
let orderByte = canonicalOrder.indexOf(key);
if (orderByte === -1) {
throw new Error(
`Unknown invariant of the enum "${name}", allowed values: "${canonicalOrder.join(
" | "
)}"; received "${key}"`
);
}
let invariant = canonicalOrder[orderByte];
let invariantType = struct[invariant];
writer.write8(orderByte);
if (invariantType === null) {
return writer;
}
let paramIndex = canonicalTypeParams.indexOf(invariantType);
let typeOrParam = paramIndex === -1 ? invariantType : typeParams[paramIndex];
{
let { name: name2, params } = this.parseTypeName(typeOrParam);
return this.getTypeInterface(name2)._encodeRaw.call(
this,
writer,
data[key],
params,
typeMap
);
}
},
function decodeEnum(reader, typeParams, typeMap) {
let orderByte = reader.readULEB();
let invariant = canonicalOrder[orderByte];
let invariantType = struct[invariant];
if (orderByte === -1) {
throw new Error(
`Decoding type mismatch, expected enum "${name}" invariant index, received "${orderByte}"`
);
}
if (invariantType === null) {
return { [invariant]: true };
}
let paramIndex = canonicalTypeParams.indexOf(invariantType);
let typeOrParam = paramIndex === -1 ? invariantType : typeParams[paramIndex];
{
let { name: name2, params } = this.parseTypeName(typeOrParam);
return {
[invariant]: this.getTypeInterface(name2)._decodeRaw.call(this, reader, params, typeMap)
};
}
}
);
}
/**
* Get a set of encoders/decoders for specific type.
* Mainly used to define custom type de/serialization logic.
*
* @param type
* @returns {TypeInterface}
*/
getTypeInterface(type) {
let typeInterface = this.types.get(type);
if (typeof typeInterface === "string") {
let chain = [];
while (typeof typeInterface === "string") {
if (chain.includes(typeInterface)) {
throw new Error(`Recursive definition found: ${chain.join(" -> ")} -> ${typeInterface}`);
}
chain.push(typeInterface);
typeInterface = this.types.get(typeInterface);
}
}
if (typeInterface === void 0) {
throw new Error(`Type ${type} is not registered`);
}
return typeInterface;
}
/**
* Parse a type name and get the type's generics.
* @example
* let { typeName, typeParams } = parseTypeName('Option<Coin<SUI>>');
* // typeName: Option
* // typeParams: [ 'Coin<SUI>' ]
*
* @param name Name of the type to process
* @returns Object with typeName and typeParams listed as Array
*/
parseTypeName(name) {
if (Array.isArray(name)) {
let [typeName2, ...params2] = name;
return { name: typeName2, params: params2 };
}
if (typeof name !== "string") {
throw new Error(`Illegal type passed as a name of the type: ${name}`);
}
let [left, right] = this.schema.genericSeparators || ["<", ">"];
let l_bound = name.indexOf(left);
let r_bound = Array.from(name).reverse().indexOf(right);
if (l_bound === -1 && r_bound === -1) {
return { name, params: [] };
}
if (l_bound === -1 || r_bound === -1) {
throw new Error(`Unclosed generic in name '${name}'`);
}
let typeName = name.slice(0, l_bound);
let params = splitGenericParameters(
name.slice(l_bound + 1, name.length - r_bound - 1),
this.schema.genericSeparators
);
return { name: typeName, params };
}
};
// Predefined types constants
_BCS.U8 = "u8";
_BCS.U16 = "u16";
_BCS.U32 = "u32";
_BCS.U64 = "u64";
_BCS.U128 = "u128";
_BCS.U256 = "u256";
_BCS.BOOL = "bool";
_BCS.VECTOR = "vector";
_BCS.ADDRESS = "address";
_BCS.STRING = "string";
_BCS.HEX = "hex-string";
_BCS.BASE58 = "base58-string";
_BCS.BASE64 = "base64-string";
var BCS = _BCS;
function registerPrimitives(bcs2) {
bcs2.registerType(
BCS.U8,
function(writer, data) {
return writer.write8(data);
},
function(reader) {
return reader.read8();
},
(u8) => u8 < 256
);
bcs2.registerType(
BCS.U16,
function(writer, data) {
return writer.write16(data);
},
function(reader) {
return reader.read16();
},
(u16) => u16 < 65536
);
bcs2.registerType(
BCS.U32,
function(writer, data) {
return writer.write32(data);
},
function(reader) {
return reader.read32();
},
(u32) => u32 <= 4294967296n
);
bcs2.registerType(
BCS.U64,
function(writer, data) {
return writer.write64(data);
},
function(reader) {
return reader.read64();
}
);
bcs2.registerType(
BCS.U128,
function(writer, data) {
return writer.write128(data);
},
function(reader) {
return reader.read128();
}
);
bcs2.registerType(
BCS.U256,
function(writer, data) {
return writer.write256(data);
},
function(reader) {
return reader.read256();
}
);
bcs2.registerType(
BCS.BOOL,
function(writer, data) {
return writer.write8(data);
},
function(reader) {
return reader.read8().toString(10) === "1";
}
);
bcs2.registerType(
BCS.STRING,
function(writer, data) {
return writer.writeVec(Array.from(data), (writer2, el) => writer2.write8(el.charCodeAt(0)));
},
function(reader) {
return reader.readVec((reader2) => reader2.read8()).map((el) => String.fromCharCode(Number(el))).join("");
},
(_str) => true
);
bcs2.registerType(
BCS.HEX,
function(writer, data) {
return writer.writeVec(Array.from(fromHEX(data)), (writer2, el) => writer2.write8(el));
},
function(reader) {
let bytes = reader.readVec((reader2) => reader2.read8());
return toHEX(new Uint8Array(bytes));
}
);
bcs2.registerType(
BCS.BASE58,
function(writer, data) {
return writer.writeVec(Array.from(fromB58(data)), (writer2, el) => writer2.write8(el));
},
function(reader) {
let bytes = reader.readVec((reader2) => reader2.read8());
return toB58(new Uint8Array(bytes));
}
);
bcs2.registerType(
BCS.BASE64,
function(writer, data) {
return writer.writeVec(Array.from(fromB64(data)), (writer2, el) => writer2.write8(el));
},
function(reader) {
let bytes = reader.readVec((reader2) => reader2.read8());
return toB64(new Uint8Array(bytes));
}
);
}
function getRustConfig() {
return {
genericSeparators: ["<", ">"],
vectorType: "Vec",
addressLength: SUI_ADDRESS_LENGTH,
addressEncoding: "hex"
};
}
function getSuiMoveConfig() {
return {
genericSeparators: ["<", ">"],
vectorType: "vector",
addressLength: SUI_ADDRESS_LENGTH,
addressEncoding: "hex"
};
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
BCS,
BcsReader,
BcsType,
BcsWriter,
SerializedBcs,
bcs,
decodeStr,
encodeStr,
fromB58,
fromB64,
fromHEX,
getRustConfig,
getSuiMoveConfig,
registerPrimitives,
splitGenericParameters,
toB58,
toB64,
toHEX
});
//# sourceMappingURL=index.js.map
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0
/*
* BCS implementation {@see https://github.com/diem/bcs } for JavaScript.
* Intended to be used for Move applications; supports both NodeJS and browser.
*
* For more details and examples {@see README.md }.
*
* @module bcs
* @property {BcsReader}
*/
import { fromB58, toB58 } from './b58.js';
import { fromB64, toB64 } from './b64.js';
import { BcsType, SerializedBcs } from './bcs-type.js';
import { bcs } from './bcs.js';
import { fromHEX, toHEX } from './hex.js';
import { BcsReader } from './reader.js';
import { decodeStr, encodeStr, splitGenericParameters } from './utils.js';
import { BcsWriter } from './writer.js';
export * from './legacy-registry.js';
// Re-export all encoding dependencies.
export { bcs, BcsType, SerializedBcs, toB58, fromB58, toB64, fromB64, fromHEX, toHEX, encodeStr, decodeStr, splitGenericParameters, BcsReader, BcsWriter, };
{
"name": "@mysten/bcs",
"version": "0.0.0-experimental-20230929052502",
"version": "0.0.0-experimental-20230929184743",
"description": "BCS - Canonical Binary Serialization implementation for JavaScript",

@@ -5,0 +5,0 @@ "license": "Apache-2.0",

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc