UNPKG

envio

Version:

A latency and sync speed optimized, developer friendly blockchain data indexer.

1,586 lines (1,542 loc) • 57.3 kB
"use strict"; // Copyright (C) Fuel Labs <contact@fuel.sh> (https://fuel.network/) // This is a vendored compiled file from @fuel-ts/abi-coder@0.86.0 package // We want to change a few decoding functions, to avoid having our own decoders // and optimise the decodign process as much as possible. // As a more maintainable option we might consider forking the repo and publishing // a patched version under the @envio-dev org. // Initially I've tried using pnpm patch, // but it didn't work for us, since it include patch in the root of the repo, which is user's indexer. // Here's the list of the changes: // 1. Changed enum decoder to always return data in a format {case: <Variant name>, payload: <Payload data>}. // Where Payload data should be unit if it's not provided. // 1.1. Adjust OptionCoder to return variant with payload instead of T | undefined // 2. Changed BigNumberCoder to return BigInt instead of BN.js // 3. Exposed AbiCoder and added getLogDecoder static method, to do all prep work once // 4. Added transpileAbi function to convert json abi to old fuel abi // Here's the generated diff from pnpm patch // diff --git a/dist/index.js b/dist/index.js // index bbb0bdfd7d506d311d2160f81b22a59ded3e4f70..653e0b400358e2e67c84c27bb2e120a2e4115717 100644 // --- a/dist/index.js // +++ b/dist/index.js // @@ -25,6 +25,7 @@ var __publicField = (obj, key, value) => { // // src/index.ts // var src_exports = {}; // __export(src_exports, { // + AbiCoder: () => AbiCoder, // + transpileAbi: () => transpileAbi, // ASSET_ID_LEN: () => ASSET_ID_LEN, // ArrayCoder: () => ArrayCoder, // B256Coder: () => B256Coder, // @@ -272,7 +273,7 @@ var BigNumberCoder = class extends Coder { // if (bytes.length !== this.encodedLength) { // throw new import_errors4.FuelError(import_errors4.ErrorCode.DECODE_ERROR, `Invalid ${this.type} byte data size.`); // } // - return [(0, import_math3.bn)(bytes), offset + this.encodedLength]; // + return [BigInt(import_math3.bn(bytes)), offset + this.encodedLength]; // } // }; // @@ -408,7 +409,7 @@ var EnumCoder = class extends Coder { // - if (this.#isNativeEnum(this.coders[caseKey])) { // - return this.#decodeNativeEnum(caseKey, newOffset); // - } // - return [{ [caseKey]: decoded }, newOffset]; // + return [{ case: caseKey, payload: decoded }, newOffset]; // } // }; // @@ -1035,6 +1036,20 @@ var AbiCoder = class { // const resolvedAbiType = new ResolvedAbiType(abi, argument); // return getCoderForEncoding(options.encoding)(resolvedAbiType, options); // } // + static getLogDecoder(abi, logId, options = { // + padToWordSize: false // + }) { // + const loggedType = abi.loggedTypes.find((type) => type.logId === logId); // + if (!loggedType) { // + throw new import_errors20.FuelError( // + import_errors20.ErrorCode.LOG_TYPE_NOT_FOUND, // + `Log type with logId '${logId}' doesn't exist in the ABI.` // + ); // + } // + const resolvedAbiType = new ResolvedAbiType(abi, loggedType.loggedType); // + const internalCoder = getCoderForEncoding(options.encoding)(resolvedAbiType, options); // + return (data) => internalCoder.decode(import_utils12.arrayify(data), 0)[0]; // + } // static encode(abi, argument, value, options) { // return this.getCoder(abi, argument, options).encode(value); // } // @@ -1239,8 +1254,10 @@ var Interface = class { // return findTypeById(this.jsonAbi, typeId); // } // }; // + // // Annotate the CommonJS export names for ESM import in node: // 0 && (module.exports = { // + transpileAbi, // + AbiCoder, // ASSET_ID_LEN, // ArrayCoder, // B256Coder, var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value, }) : (obj[key] = value); 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 __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var __publicField = (obj, key, value) => { __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; // src/index.ts var src_exports = {}; __export(src_exports, { ASSET_ID_LEN: () => ASSET_ID_LEN, AbiCoder: () => AbiCoder, transpileAbi: () => transpileAbi, ArrayCoder: () => ArrayCoder, B256Coder: () => B256Coder, B512Coder: () => B512Coder, BYTES_32: () => BYTES_32, BigNumberCoder: () => BigNumberCoder, BooleanCoder: () => BooleanCoder, ByteCoder: () => ByteCoder, CONTRACT_ID_LEN: () => CONTRACT_ID_LEN, Coder: () => Coder, ENCODING_V1: () => ENCODING_V1, EnumCoder: () => EnumCoder, INPUT_COIN_FIXED_SIZE: () => INPUT_COIN_FIXED_SIZE, Interface: () => Interface, NumberCoder: () => NumberCoder, OptionCoder: () => OptionCoder, RawSliceCoder: () => RawSliceCoder, SCRIPT_FIXED_SIZE: () => SCRIPT_FIXED_SIZE, StdStringCoder: () => StdStringCoder, StrSliceCoder: () => StrSliceCoder, StringCoder: () => StringCoder, StructCoder: () => StructCoder, TupleCoder: () => TupleCoder, UTXO_ID_LEN: () => UTXO_ID_LEN, VecCoder: () => VecCoder, WORD_SIZE: () => WORD_SIZE, calculateVmTxMemory: () => calculateVmTxMemory, }); module.exports = __toCommonJS(src_exports); // src/encoding/coders/AbstractCoder.ts var Coder = class { name; type; encodedLength; constructor(name, type, encodedLength) { this.name = name; this.type = type; this.encodedLength = encodedLength; } }; // src/encoding/coders/ArrayCoder.ts var import_errors = require("@fuel-ts/errors"); var import_utils = require("@fuel-ts/utils"); // src/utils/constants.ts var U8_CODER_TYPE = "u8"; var U16_CODER_TYPE = "u16"; var U32_CODER_TYPE = "u32"; var U64_CODER_TYPE = "u64"; var U256_CODER_TYPE = "u256"; var RAW_PTR_CODER_TYPE = "raw untyped ptr"; var RAW_SLICE_CODER_TYPE = "raw untyped slice"; var BOOL_CODER_TYPE = "bool"; var B256_CODER_TYPE = "b256"; var B512_CODER_TYPE = "struct std::b512::B512"; var OPTION_CODER_TYPE = "enum std::option::Option"; var VEC_CODER_TYPE = "struct std::vec::Vec"; var BYTES_CODER_TYPE = "struct std::bytes::Bytes"; var STD_STRING_CODER_TYPE = "struct std::string::String"; var STR_SLICE_CODER_TYPE = "str"; var VOID_TYPE = "()"; var optionRegEx = /^enum (std::option::)?Option$/m; var stringRegEx = /^str\[(?<length>[0-9]+)\]/; var arrayRegEx = /^\[(?<item>[\w\s\\[\]]+);\s*(?<length>[0-9]+)\]/; var structRegEx = /^struct.+/; var enumRegEx = /^enum.+$/; var tupleRegEx = /^\((?<items>.*)\)$/; var genericRegEx = /^generic.+$/; var fullNameRegExMatch = /([^\s]+)$/m; var ENCODING_V1 = "1"; var WORD_SIZE = 8; var BYTES_32 = 32; var UTXO_ID_LEN = BYTES_32 + 2; var ASSET_ID_LEN = BYTES_32; var CONTRACT_ID_LEN = BYTES_32; var ADDRESS_LEN = BYTES_32; var NONCE_LEN = BYTES_32; var TX_LEN = WORD_SIZE * 4; var TX_POINTER_LEN = WORD_SIZE * 2; var MAX_BYTES = 2 ** 32 - 1; var calculateVmTxMemory = ({ maxInputs }) => BYTES_32 + // Tx ID ASSET_ID_LEN + // Base asset ID // Asset ID/Balance coin input pairs maxInputs * (ASSET_ID_LEN + WORD_SIZE) + WORD_SIZE; var SCRIPT_FIXED_SIZE = WORD_SIZE + // Identifier WORD_SIZE + // Gas limit WORD_SIZE + // Script size WORD_SIZE + // Script data size WORD_SIZE + // Policies WORD_SIZE + // Inputs size WORD_SIZE + // Outputs size WORD_SIZE + // Witnesses size BYTES_32; var INPUT_COIN_FIXED_SIZE = WORD_SIZE + // Identifier TX_LEN + // Utxo Length WORD_SIZE + // Output Index ADDRESS_LEN + // Owner WORD_SIZE + // Amount ASSET_ID_LEN + // Asset id TX_POINTER_LEN + // TxPointer WORD_SIZE + // Witnesses index WORD_SIZE + // Predicate size WORD_SIZE + // Predicate data size WORD_SIZE; var INPUT_MESSAGE_FIXED_SIZE = WORD_SIZE + // Identifier ADDRESS_LEN + // Sender ADDRESS_LEN + // Recipient WORD_SIZE + // Amount NONCE_LEN + // Nonce WORD_SIZE + // witness_index WORD_SIZE + // Data size WORD_SIZE + // Predicate size WORD_SIZE + // Predicate data size WORD_SIZE; // src/utils/utilities.ts var isUint8Array = (value) => value instanceof Uint8Array; var hasNestedOption = (coders) => { const array = Array.isArray(coders) ? coders : Object.values(coders); for (const node of array) { if (node.type === OPTION_CODER_TYPE) { return true; } if ("coder" in node && node.coder.type === OPTION_CODER_TYPE) { return true; } if ("coders" in node) { const child = hasNestedOption(node.coders); if (child) { return true; } } } return false; }; // src/encoding/coders/ArrayCoder.ts var ArrayCoder = class extends Coder { coder; length; #hasNestedOption; constructor(coder, length) { super("array", `[${coder.type}; ${length}]`, length * coder.encodedLength); this.coder = coder; this.length = length; this.#hasNestedOption = hasNestedOption([coder]); } encode(value) { if (!Array.isArray(value)) { throw new import_errors.FuelError( import_errors.ErrorCode.ENCODE_ERROR, `Expected array value.` ); } if (this.length !== value.length) { throw new import_errors.FuelError( import_errors.ErrorCode.ENCODE_ERROR, `Types/values length mismatch.` ); } return (0, import_utils.concat)( Array.from(value).map((v) => this.coder.encode(v)) ); } decode(data, offset) { if ( (!this.#hasNestedOption && data.length < this.encodedLength) || data.length > MAX_BYTES ) { throw new import_errors.FuelError( import_errors.ErrorCode.DECODE_ERROR, `Invalid array data size.` ); } let newOffset = offset; const decodedValue = Array(this.length) .fill(0) .map(() => { let decoded; [decoded, newOffset] = this.coder.decode(data, newOffset); return decoded; }); return [decodedValue, newOffset]; } }; // src/encoding/coders/B256Coder.ts var import_errors2 = require("@fuel-ts/errors"); var import_math = require("@fuel-ts/math"); var import_utils2 = require("@fuel-ts/utils"); var B256Coder = class extends Coder { constructor() { super("b256", "b256", WORD_SIZE * 4); } encode(value) { let encodedValue; try { encodedValue = (0, import_utils2.arrayify)(value); } catch (error) { throw new import_errors2.FuelError( import_errors2.ErrorCode.ENCODE_ERROR, `Invalid ${this.type}.` ); } if (encodedValue.length !== this.encodedLength) { throw new import_errors2.FuelError( import_errors2.ErrorCode.ENCODE_ERROR, `Invalid ${this.type}.` ); } return encodedValue; } decode(data, offset) { if (data.length < this.encodedLength) { throw new import_errors2.FuelError( import_errors2.ErrorCode.DECODE_ERROR, `Invalid b256 data size.` ); } let bytes = data.slice(offset, offset + this.encodedLength); const decoded = (0, import_math.bn)(bytes); if (decoded.isZero()) { bytes = new Uint8Array(32); } if (bytes.length !== this.encodedLength) { throw new import_errors2.FuelError( import_errors2.ErrorCode.DECODE_ERROR, `Invalid b256 byte data size.` ); } return [(0, import_math.toHex)(bytes, 32), offset + 32]; } }; // src/encoding/coders/B512Coder.ts var import_errors3 = require("@fuel-ts/errors"); var import_math2 = require("@fuel-ts/math"); var import_utils3 = require("@fuel-ts/utils"); var B512Coder = class extends Coder { constructor() { super("b512", "struct B512", WORD_SIZE * 8); } encode(value) { let encodedValue; try { encodedValue = (0, import_utils3.arrayify)(value); } catch (error) { throw new import_errors3.FuelError( import_errors3.ErrorCode.ENCODE_ERROR, `Invalid ${this.type}.` ); } if (encodedValue.length !== this.encodedLength) { throw new import_errors3.FuelError( import_errors3.ErrorCode.ENCODE_ERROR, `Invalid ${this.type}.` ); } return encodedValue; } decode(data, offset) { if (data.length < this.encodedLength) { throw new import_errors3.FuelError( import_errors3.ErrorCode.DECODE_ERROR, `Invalid b512 data size.` ); } let bytes = data.slice(offset, offset + this.encodedLength); const decoded = (0, import_math2.bn)(bytes); if (decoded.isZero()) { bytes = new Uint8Array(64); } if (bytes.length !== this.encodedLength) { throw new import_errors3.FuelError( import_errors3.ErrorCode.DECODE_ERROR, `Invalid b512 byte data size.` ); } return [ (0, import_math2.toHex)(bytes, this.encodedLength), offset + this.encodedLength, ]; } }; // src/encoding/coders/BigNumberCoder.ts var import_errors4 = require("@fuel-ts/errors"); var import_math3 = require("@fuel-ts/math"); var encodedLengths = { u64: WORD_SIZE, u256: WORD_SIZE * 4, }; var BigNumberCoder = class extends Coder { constructor(baseType) { super("bigNumber", baseType, encodedLengths[baseType]); } encode(value) { let bytes; try { bytes = (0, import_math3.toBytes)(value, this.encodedLength); } catch (error) { throw new import_errors4.FuelError( import_errors4.ErrorCode.ENCODE_ERROR, `Invalid ${this.type}.` ); } return bytes; } decode(data, offset) { if (data.length < this.encodedLength) { throw new import_errors4.FuelError( import_errors4.ErrorCode.DECODE_ERROR, `Invalid ${this.type} data size.` ); } let bytes = data.slice(offset, offset + this.encodedLength); bytes = bytes.slice(0, this.encodedLength); if (bytes.length !== this.encodedLength) { throw new import_errors4.FuelError( import_errors4.ErrorCode.DECODE_ERROR, `Invalid ${this.type} byte data size.` ); } return [BigInt(import_math3.bn(bytes)), offset + this.encodedLength]; } }; // src/encoding/coders/BooleanCoder.ts var import_errors5 = require("@fuel-ts/errors"); var import_math4 = require("@fuel-ts/math"); var BooleanCoder = class extends Coder { options; constructor( options = { padToWordSize: false, } ) { const encodedLength = options.padToWordSize ? WORD_SIZE : 1; super("boolean", "boolean", encodedLength); this.options = options; } encode(value) { const isTrueBool = value === true || value === false; if (!isTrueBool) { throw new import_errors5.FuelError( import_errors5.ErrorCode.ENCODE_ERROR, `Invalid boolean value.` ); } return (0, import_math4.toBytes)(value ? 1 : 0, this.encodedLength); } decode(data, offset) { if (data.length < this.encodedLength) { throw new import_errors5.FuelError( import_errors5.ErrorCode.DECODE_ERROR, `Invalid boolean data size.` ); } const bytes = (0, import_math4.bn)( data.slice(offset, offset + this.encodedLength) ); if (bytes.isZero()) { return [false, offset + this.encodedLength]; } if (!bytes.eq((0, import_math4.bn)(1))) { throw new import_errors5.FuelError( import_errors5.ErrorCode.DECODE_ERROR, `Invalid boolean value.` ); } return [true, offset + this.encodedLength]; } }; // src/encoding/coders/ByteCoder.ts var import_errors6 = require("@fuel-ts/errors"); var import_math5 = require("@fuel-ts/math"); var ByteCoder = class extends Coder { constructor() { super("struct", "struct Bytes", WORD_SIZE); } encode(value) { const bytes = value instanceof Uint8Array ? value : new Uint8Array(value); const lengthBytes = new BigNumberCoder("u64").encode(bytes.length); return new Uint8Array([...lengthBytes, ...bytes]); } decode(data, offset) { if (data.length < WORD_SIZE) { throw new import_errors6.FuelError( import_errors6.ErrorCode.DECODE_ERROR, `Invalid byte data size.` ); } const offsetAndLength = offset + WORD_SIZE; const lengthBytes = data.slice(offset, offsetAndLength); const length = (0, import_math5.bn)( new BigNumberCoder("u64").decode(lengthBytes, 0)[0] ).toNumber(); const dataBytes = data.slice(offsetAndLength, offsetAndLength + length); if (dataBytes.length !== length) { throw new import_errors6.FuelError( import_errors6.ErrorCode.DECODE_ERROR, `Invalid bytes byte data size.` ); } return [dataBytes, offsetAndLength + length]; } }; __publicField(ByteCoder, "memorySize", 1); // src/encoding/coders/EnumCoder.ts var import_errors7 = require("@fuel-ts/errors"); var import_math6 = require("@fuel-ts/math"); var import_utils4 = require("@fuel-ts/utils"); var EnumCoder = class extends Coder { name; coders; #caseIndexCoder; #encodedValueSize; #shouldValidateLength; constructor(name, coders) { const caseIndexCoder = new BigNumberCoder("u64"); const encodedValueSize = Object.values(coders).reduce( (min, coder) => Math.min(min, coder.encodedLength), 0 ); super( `enum ${name}`, `enum ${name}`, caseIndexCoder.encodedLength + encodedValueSize ); this.name = name; this.coders = coders; this.#caseIndexCoder = caseIndexCoder; this.#encodedValueSize = encodedValueSize; this.#shouldValidateLength = !( optionRegEx.test(this.type) || hasNestedOption(coders) ); } // Checks that we're handling a native enum that is of type void. #isNativeEnum(coder) { return this.type !== OPTION_CODER_TYPE && coder.type === VOID_TYPE; } #encodeNativeEnum(value) { const valueCoder = this.coders[value]; const encodedValue = valueCoder.encode([]); const caseIndex = Object.keys(this.coders).indexOf(value); const padding = new Uint8Array( this.#encodedValueSize - valueCoder.encodedLength ); return (0, import_utils4.concat)([ this.#caseIndexCoder.encode(caseIndex), padding, encodedValue, ]); } encode(value) { if (typeof value === "string" && this.coders[value]) { return this.#encodeNativeEnum(value); } const [caseKey, ...empty] = Object.keys(value); if (!caseKey) { throw new import_errors7.FuelError( import_errors7.ErrorCode.INVALID_DECODE_VALUE, "A field for the case must be provided." ); } if (empty.length !== 0) { throw new import_errors7.FuelError( import_errors7.ErrorCode.INVALID_DECODE_VALUE, "Only one field must be provided." ); } const valueCoder = this.coders[caseKey]; const caseIndex = Object.keys(this.coders).indexOf(caseKey); if (caseIndex === -1) { const validCases = Object.keys(this.coders) .map((v) => `'${v}'`) .join(", "); throw new import_errors7.FuelError( import_errors7.ErrorCode.INVALID_DECODE_VALUE, `Invalid case '${caseKey}'. Valid cases: ${validCases}.` ); } const encodedValue = valueCoder.encode(value[caseKey]); return new Uint8Array([ ...this.#caseIndexCoder.encode(caseIndex), ...encodedValue, ]); } #decodeNativeEnum(caseKey, newOffset) { return [caseKey, newOffset]; } decode(data, offset) { if (this.#shouldValidateLength && data.length < this.encodedLength) { throw new import_errors7.FuelError( import_errors7.ErrorCode.DECODE_ERROR, `Invalid enum data size.` ); } const caseBytes = new BigNumberCoder("u64").decode(data, offset)[0]; const caseIndex = (0, import_math6.toNumber)(caseBytes); const caseKey = Object.keys(this.coders)[caseIndex]; if (!caseKey) { throw new import_errors7.FuelError( import_errors7.ErrorCode.INVALID_DECODE_VALUE, `Invalid caseIndex "${caseIndex}". Valid cases: ${Object.keys( this.coders )}.` ); } const valueCoder = this.coders[caseKey]; const offsetAndCase = offset + this.#caseIndexCoder.encodedLength; if ( this.#shouldValidateLength && data.length < offsetAndCase + valueCoder.encodedLength ) { throw new import_errors7.FuelError( import_errors7.ErrorCode.DECODE_ERROR, `Invalid enum data size.` ); } const [decoded, newOffset] = valueCoder.decode(data, offsetAndCase); return [{ case: caseKey, payload: decoded }, newOffset]; } }; // src/encoding/coders/NumberCoder.ts var import_errors8 = require("@fuel-ts/errors"); var import_math7 = require("@fuel-ts/math"); var getLength = (baseType) => { switch (baseType) { case "u8": return 1; case "u16": return 2; case "u32": return 4; default: throw new import_errors8.FuelError( import_errors8.ErrorCode.TYPE_NOT_SUPPORTED, `Invalid number type: ${baseType}` ); } }; var NumberCoder = class extends Coder { baseType; options; constructor( baseType, options = { padToWordSize: false, } ) { const length = options.padToWordSize ? WORD_SIZE : getLength(baseType); super("number", baseType, length); this.baseType = baseType; this.options = options; } encode(value) { let bytes; try { bytes = (0, import_math7.toBytes)(value); } catch (error) { throw new import_errors8.FuelError( import_errors8.ErrorCode.ENCODE_ERROR, `Invalid ${this.baseType}.` ); } if (bytes.length > this.encodedLength) { throw new import_errors8.FuelError( import_errors8.ErrorCode.ENCODE_ERROR, `Invalid ${this.baseType}, too many bytes.` ); } return (0, import_math7.toBytes)(bytes, this.encodedLength); } decode(data, offset) { if (data.length < this.encodedLength) { throw new import_errors8.FuelError( import_errors8.ErrorCode.DECODE_ERROR, `Invalid number data size.` ); } const bytes = data.slice(offset, offset + this.encodedLength); if (bytes.length !== this.encodedLength) { throw new import_errors8.FuelError( import_errors8.ErrorCode.DECODE_ERROR, `Invalid number byte data size.` ); } return [(0, import_math7.toNumber)(bytes), offset + this.encodedLength]; } }; // src/encoding/coders/OptionCoder.ts var OptionCoder = class extends EnumCoder { encode(value) { const result = super.encode(this.toSwayOption(value)); return result; } toSwayOption(input) { if (input !== void 0) { return { Some: input }; } return { None: [] }; } }; // src/encoding/coders/RawSliceCoder.ts var import_errors9 = require("@fuel-ts/errors"); var import_math8 = require("@fuel-ts/math"); var RawSliceCoder = class extends Coder { constructor() { super("raw untyped slice", "raw untyped slice", WORD_SIZE); } encode(value) { if (!Array.isArray(value)) { throw new import_errors9.FuelError( import_errors9.ErrorCode.ENCODE_ERROR, `Expected array value.` ); } const internalCoder = new ArrayCoder(new NumberCoder("u8"), value.length); const bytes = internalCoder.encode(value); const lengthBytes = new BigNumberCoder("u64").encode(bytes.length); return new Uint8Array([...lengthBytes, ...bytes]); } decode(data, offset) { if (data.length < this.encodedLength) { throw new import_errors9.FuelError( import_errors9.ErrorCode.DECODE_ERROR, `Invalid raw slice data size.` ); } const offsetAndLength = offset + WORD_SIZE; const lengthBytes = data.slice(offset, offsetAndLength); const length = (0, import_math8.bn)( new BigNumberCoder("u64").decode(lengthBytes, 0)[0] ).toNumber(); const dataBytes = data.slice(offsetAndLength, offsetAndLength + length); if (dataBytes.length !== length) { throw new import_errors9.FuelError( import_errors9.ErrorCode.DECODE_ERROR, `Invalid raw slice byte data size.` ); } const internalCoder = new ArrayCoder(new NumberCoder("u8"), length); const [decodedValue] = internalCoder.decode(dataBytes, 0); return [decodedValue, offsetAndLength + length]; } }; // src/encoding/coders/StdStringCoder.ts var import_errors10 = require("@fuel-ts/errors"); var import_math9 = require("@fuel-ts/math"); var import_utils5 = require("@fuel-ts/utils"); var StdStringCoder = class extends Coder { constructor() { super("struct", "struct String", WORD_SIZE); } encode(value) { const bytes = (0, import_utils5.toUtf8Bytes)(value); const lengthBytes = new BigNumberCoder("u64").encode(value.length); return new Uint8Array([...lengthBytes, ...bytes]); } decode(data, offset) { if (data.length < this.encodedLength) { throw new import_errors10.FuelError( import_errors10.ErrorCode.DECODE_ERROR, `Invalid std string data size.` ); } const offsetAndLength = offset + WORD_SIZE; const lengthBytes = data.slice(offset, offsetAndLength); const length = (0, import_math9.bn)( new BigNumberCoder("u64").decode(lengthBytes, 0)[0] ).toNumber(); const dataBytes = data.slice(offsetAndLength, offsetAndLength + length); if (dataBytes.length !== length) { throw new import_errors10.FuelError( import_errors10.ErrorCode.DECODE_ERROR, `Invalid std string byte data size.` ); } return [ (0, import_utils5.toUtf8String)(dataBytes), offsetAndLength + length, ]; } }; __publicField(StdStringCoder, "memorySize", 1); // src/encoding/coders/StrSliceCoder.ts var import_errors11 = require("@fuel-ts/errors"); var import_math10 = require("@fuel-ts/math"); var import_utils6 = require("@fuel-ts/utils"); var StrSliceCoder = class extends Coder { constructor() { super("strSlice", "str", WORD_SIZE); } encode(value) { const bytes = (0, import_utils6.toUtf8Bytes)(value); const lengthBytes = new BigNumberCoder("u64").encode(value.length); return new Uint8Array([...lengthBytes, ...bytes]); } decode(data, offset) { if (data.length < this.encodedLength) { throw new import_errors11.FuelError( import_errors11.ErrorCode.DECODE_ERROR, `Invalid string slice data size.` ); } const offsetAndLength = offset + WORD_SIZE; const lengthBytes = data.slice(offset, offsetAndLength); const length = (0, import_math10.bn)( new BigNumberCoder("u64").decode(lengthBytes, 0)[0] ).toNumber(); const bytes = data.slice(offsetAndLength, offsetAndLength + length); if (bytes.length !== length) { throw new import_errors11.FuelError( import_errors11.ErrorCode.DECODE_ERROR, `Invalid string slice byte data size.` ); } return [(0, import_utils6.toUtf8String)(bytes), offsetAndLength + length]; } }; __publicField(StrSliceCoder, "memorySize", 1); // src/encoding/coders/StringCoder.ts var import_errors12 = require("@fuel-ts/errors"); var import_utils7 = require("@fuel-ts/utils"); var StringCoder = class extends Coder { constructor(length) { super("string", `str[${length}]`, length); } encode(value) { if (value.length !== this.encodedLength) { throw new import_errors12.FuelError( import_errors12.ErrorCode.ENCODE_ERROR, `Value length mismatch during encode.` ); } return (0, import_utils7.toUtf8Bytes)(value); } decode(data, offset) { if (data.length < this.encodedLength) { throw new import_errors12.FuelError( import_errors12.ErrorCode.DECODE_ERROR, `Invalid string data size.` ); } const bytes = data.slice(offset, offset + this.encodedLength); if (bytes.length !== this.encodedLength) { throw new import_errors12.FuelError( import_errors12.ErrorCode.DECODE_ERROR, `Invalid string byte data size.` ); } return [ (0, import_utils7.toUtf8String)(bytes), offset + this.encodedLength, ]; } }; // src/encoding/coders/StructCoder.ts var import_errors13 = require("@fuel-ts/errors"); var import_utils8 = require("@fuel-ts/utils"); var StructCoder = class extends Coder { name; coders; #hasNestedOption; constructor(name, coders) { const encodedLength = Object.values(coders).reduce( (acc, coder) => acc + coder.encodedLength, 0 ); super("struct", `struct ${name}`, encodedLength); this.name = name; this.coders = coders; this.#hasNestedOption = hasNestedOption(coders); } encode(value) { return (0, import_utils8.concatBytes)( Object.keys(this.coders).map((fieldName) => { const fieldCoder = this.coders[fieldName]; const fieldValue = value[fieldName]; if (!(fieldCoder instanceof OptionCoder) && fieldValue == null) { throw new import_errors13.FuelError( import_errors13.ErrorCode.ENCODE_ERROR, `Invalid ${this.type}. Field "${fieldName}" not present.` ); } return fieldCoder.encode(fieldValue); }) ); } decode(data, offset) { if (!this.#hasNestedOption && data.length < this.encodedLength) { throw new import_errors13.FuelError( import_errors13.ErrorCode.DECODE_ERROR, `Invalid struct data size.` ); } let newOffset = offset; const decodedValue = Object.keys(this.coders).reduce((obj, fieldName) => { const fieldCoder = this.coders[fieldName]; let decoded; [decoded, newOffset] = fieldCoder.decode(data, newOffset); obj[fieldName] = decoded; return obj; }, {}); return [decodedValue, newOffset]; } }; // src/encoding/coders/TupleCoder.ts var import_errors14 = require("@fuel-ts/errors"); var import_utils9 = require("@fuel-ts/utils"); var TupleCoder = class extends Coder { coders; #hasNestedOption; constructor(coders) { const encodedLength = coders.reduce( (acc, coder) => acc + coder.encodedLength, 0 ); super( "tuple", `(${coders.map((coder) => coder.type).join(", ")})`, encodedLength ); this.coders = coders; this.#hasNestedOption = hasNestedOption(coders); } encode(value) { if (this.coders.length !== value.length) { throw new import_errors14.FuelError( import_errors14.ErrorCode.ENCODE_ERROR, `Types/values length mismatch.` ); } return (0, import_utils9.concatBytes)( this.coders.map((coder, i) => coder.encode(value[i])) ); } decode(data, offset) { if (!this.#hasNestedOption && data.length < this.encodedLength) { throw new import_errors14.FuelError( import_errors14.ErrorCode.DECODE_ERROR, `Invalid tuple data size.` ); } let newOffset = offset; const decodedValue = this.coders.map((coder) => { let decoded; [decoded, newOffset] = coder.decode(data, newOffset); return decoded; }); return [decodedValue, newOffset]; } }; // src/encoding/coders/VecCoder.ts var import_errors15 = require("@fuel-ts/errors"); var import_math11 = require("@fuel-ts/math"); var import_utils10 = require("@fuel-ts/utils"); var VecCoder = class extends Coder { coder; #hasNestedOption; constructor(coder) { super("struct", `struct Vec`, WORD_SIZE); this.coder = coder; this.#hasNestedOption = hasNestedOption([coder]); } encode(value) { if (!Array.isArray(value) && !isUint8Array(value)) { throw new import_errors15.FuelError( import_errors15.ErrorCode.ENCODE_ERROR, `Expected array value, or a Uint8Array. You can use arrayify to convert a value to a Uint8Array.` ); } const lengthCoder = new BigNumberCoder("u64"); if (isUint8Array(value)) { return new Uint8Array([...lengthCoder.encode(value.length), ...value]); } const bytes = value.map((v) => this.coder.encode(v)); const lengthBytes = lengthCoder.encode(value.length); return new Uint8Array([ ...lengthBytes, ...(0, import_utils10.concatBytes)(bytes), ]); } decode(data, offset) { if ( (!this.#hasNestedOption && data.length < this.encodedLength) || data.length > MAX_BYTES ) { throw new import_errors15.FuelError( import_errors15.ErrorCode.DECODE_ERROR, `Invalid vec data size.` ); } const offsetAndLength = offset + WORD_SIZE; const lengthBytes = data.slice(offset, offsetAndLength); const length = (0, import_math11.bn)( new BigNumberCoder("u64").decode(lengthBytes, 0)[0] ).toNumber(); const dataLength = length * this.coder.encodedLength; const dataBytes = data.slice(offsetAndLength, offsetAndLength + dataLength); if (!this.#hasNestedOption && dataBytes.length !== dataLength) { throw new import_errors15.FuelError( import_errors15.ErrorCode.DECODE_ERROR, `Invalid vec byte data size.` ); } let newOffset = offsetAndLength; const chunks = []; for (let i = 0; i < length; i++) { const [decoded, optionOffset] = this.coder.decode(data, newOffset); chunks.push(decoded); newOffset = optionOffset; } return [chunks, newOffset]; } }; // src/Interface.ts var import_errors21 = require("@fuel-ts/errors"); var import_utils12 = require("@fuel-ts/utils"); // src/ResolvedAbiType.ts var import_errors17 = require("@fuel-ts/errors"); // src/utils/json-abi.ts var import_errors16 = require("@fuel-ts/errors"); var getEncodingVersion = (encoding) => { switch (encoding) { case void 0: case ENCODING_V1: return ENCODING_V1; default: throw new import_errors16.FuelError( import_errors16.ErrorCode.UNSUPPORTED_ENCODING_VERSION, `Encoding version '${encoding}' is unsupported.` ); } }; var findTypeById = (abi, typeId) => { const type = abi.types.find((t) => t.typeId === typeId); if (!type) { throw new import_errors16.FuelError( import_errors16.ErrorCode.TYPE_NOT_FOUND, `Type with typeId '${typeId}' doesn't exist in the ABI.` ); } return type; }; var findNonVoidInputs = (abi, inputs) => inputs.filter((input) => findTypeById(abi, input.type).type !== VOID_TYPE); var findVectorBufferArgument = (components) => { const bufferComponent = components.find((c) => c.name === "buf"); const bufferTypeArgument = bufferComponent?.originalTypeArguments?.[0]; if (!bufferComponent || !bufferTypeArgument) { throw new import_errors16.FuelError( import_errors16.ErrorCode.INVALID_COMPONENT, `The Vec type provided is missing or has a malformed 'buf' component.` ); } return bufferTypeArgument; }; // src/ResolvedAbiType.ts var ResolvedAbiType = class { abi; name; type; originalTypeArguments; components; constructor(abi, argument) { this.abi = abi; this.name = argument.name; const jsonABIType = findTypeById(abi, argument.type); if (jsonABIType.type.length > 256) { throw new import_errors17.FuelError( import_errors17.ErrorCode.INVALID_COMPONENT, `The provided ABI type is too long: ${jsonABIType.type}.` ); } this.type = jsonABIType.type; this.originalTypeArguments = argument.typeArguments; this.components = ResolvedAbiType.getResolvedGenericComponents( abi, argument, jsonABIType.components, jsonABIType.typeParameters ?? ResolvedAbiType.getImplicitGenericTypeParameters( abi, jsonABIType.components ) ); } static getResolvedGenericComponents(abi, arg, components, typeParameters) { if (components === null) { return null; } if (typeParameters === null || typeParameters.length === 0) { return components.map((c) => new ResolvedAbiType(abi, c)); } const typeParametersAndArgsMap = typeParameters.reduce( (obj, typeParameter, typeParameterIndex) => { const o = { ...obj }; o[typeParameter] = structuredClone( arg.typeArguments?.[typeParameterIndex] ); return o; }, {} ); const resolvedComponents = this.resolveGenericArgTypes( abi, components, typeParametersAndArgsMap ); return resolvedComponents.map((c) => new ResolvedAbiType(abi, c)); } static resolveGenericArgTypes(abi, args, typeParametersAndArgsMap) { return args.map((arg) => { if (typeParametersAndArgsMap[arg.type] !== void 0) { return { ...typeParametersAndArgsMap[arg.type], name: arg.name, }; } if (arg.typeArguments) { return { ...structuredClone(arg), typeArguments: this.resolveGenericArgTypes( abi, arg.typeArguments, typeParametersAndArgsMap ), }; } const argType = findTypeById(abi, arg.type); const implicitTypeParameters = this.getImplicitGenericTypeParameters( abi, argType.components ); if (implicitTypeParameters && implicitTypeParameters.length > 0) { return { ...structuredClone(arg), typeArguments: implicitTypeParameters.map( (itp) => typeParametersAndArgsMap[itp] ), }; } return arg; }); } static getImplicitGenericTypeParameters( abi, args, implicitGenericParametersParam ) { if (!Array.isArray(args)) { return null; } const implicitGenericParameters = implicitGenericParametersParam ?? []; args.forEach((a) => { const argType = findTypeById(abi, a.type); if (genericRegEx.test(argType.type)) { implicitGenericParameters.push(argType.typeId); return; } if (!Array.isArray(a.typeArguments)) { return; } this.getImplicitGenericTypeParameters( abi, a.typeArguments, implicitGenericParameters ); }); return implicitGenericParameters.length > 0 ? implicitGenericParameters : null; } getSignature() { const prefix = this.getArgSignaturePrefix(); const content = this.getArgSignatureContent(); return `${prefix}${content}`; } getArgSignaturePrefix() { const structMatch = structRegEx.test(this.type); if (structMatch) { return "s"; } const arrayMatch = arrayRegEx.test(this.type); if (arrayMatch) { return "a"; } const enumMatch = enumRegEx.test(this.type); if (enumMatch) { return "e"; } return ""; } getArgSignatureContent() { if (this.type === "raw untyped ptr") { return "rawptr"; } if (this.type === "raw untyped slice") { return "rawslice"; } const strMatch = stringRegEx.exec(this.type)?.groups; if (strMatch) { return `str[${strMatch.length}]`; } if (this.components === null) { return this.type; } const arrayMatch = arrayRegEx.exec(this.type)?.groups; if (arrayMatch) { return `[${this.components[0].getSignature()};${arrayMatch.length}]`; } const typeArgumentsSignature = this.originalTypeArguments !== null ? `<${this.originalTypeArguments .map((a) => new ResolvedAbiType(this.abi, a).getSignature()) .join(",")}>` : ""; const componentsSignature = `(${this.components .map((c) => c.getSignature()) .join(",")})`; return `${typeArgumentsSignature}${componentsSignature}`; } }; // src/encoding/strategies/getCoderForEncoding.ts var import_errors19 = require("@fuel-ts/errors"); // src/encoding/strategies/getCoderV1.ts var import_errors18 = require("@fuel-ts/errors"); // src/encoding/coders/VoidCoder.ts var VoidCoder = class extends Coder { constructor() { super("void", VOID_TYPE, 0); } encode(_value) { return new Uint8Array([]); } decode(_data, offset) { return [void 0, offset]; } }; // src/encoding/strategies/getCoders.ts function getCoders(components, options) { const { getCoder: getCoder2 } = options; return components.reduce((obj, component) => { const o = obj; o[component.name] = getCoder2(component, options); return o; }, {}); } // src/encoding/strategies/getCoderV1.ts var getCoder = (resolvedAbiType, _options) => { switch (resolvedAbiType.type) { case U8_CODER_TYPE: case U16_CODER_TYPE: case U32_CODER_TYPE: return new NumberCoder(resolvedAbiType.type); case U64_CODER_TYPE: case RAW_PTR_CODER_TYPE: return new BigNumberCoder("u64"); case U256_CODER_TYPE: return new BigNumberCoder("u256"); case RAW_SLICE_CODER_TYPE: return new RawSliceCoder(); case BOOL_CODER_TYPE: return new BooleanCoder(); case B256_CODER_TYPE: return new B256Coder(); case B512_CODER_TYPE: return new B512Coder(); case BYTES_CODER_TYPE: return new ByteCoder(); case STD_STRING_CODER_TYPE: return new StdStringCoder(); case STR_SLICE_CODER_TYPE: return new StrSliceCoder(); case VOID_TYPE: return new VoidCoder(); default: break; } const stringMatch = stringRegEx.exec(resolvedAbiType.type)?.groups; if (stringMatch) { const length = parseInt(stringMatch.length, 10); return new StringCoder(length); } const components = resolvedAbiType.components; const arrayMatch = arrayRegEx.exec(resolvedAbiType.type)?.groups; if (arrayMatch) { const length = parseInt(arrayMatch.length, 10); const arg = components[0]; if (!arg) { throw new import_errors18.FuelError( import_errors18.ErrorCode.INVALID_COMPONENT, `The provided Array type is missing an item of 'component'.` ); } const arrayElementCoder = getCoder(arg); return new ArrayCoder(arrayElementCoder, length); } if (resolvedAbiType.type === VEC_CODER_TYPE) { const arg = findVectorBufferArgument(components); const argType = new ResolvedAbiType(resolvedAbiType.abi, arg); const itemCoder = getCoder(argType, { encoding: ENCODING_V1 }); return new VecCoder(itemCoder); } const coderName = resolvedAbiType.type.match(fullNameRegExMatch)?.[0]; const structMatch = structRegEx.test(resolvedAbiType.type); if (structMatch && coderName) { const coders = getCoders(components, { getCoder }); return new StructCoder(coderName, coders); } const enumMatch = enumRegEx.test(resolvedAbiType.type); if (enumMatch && coderName) { const coders = getCoders(components, { getCoder }); const isOptionEnum = resolvedAbiType.type === OPTION_CODER_TYPE; if (isOptionEnum) { return new OptionCoder(coderName, coders); } return new EnumCoder(coderName, coders); } const tupleMatch = tupleRegEx.exec(resolvedAbiType.type)?.groups; if (tupleMatch) { const coders = components.map((component) => getCoder(component, { encoding: ENCODING_V1 }) ); return new TupleCoder(coders); } throw new import_errors18.FuelError( import_errors18.ErrorCode.CODER_NOT_FOUND, `Coder not found: ${JSON.stringify(resolvedAbiType)}.` ); }; // src/encoding/strategies/getCoderForEncoding.ts function getCoderForEncoding(encoding = ENCODING_V1) { switch (encoding) { case ENCODING_V1: return getCoder; default: throw new import_errors19.FuelError( import_errors19.ErrorCode.UNSUPPORTED_ENCODING_VERSION, `Encoding version ${encoding} is unsupported.` ); } } // src/AbiCoder.ts var AbiCoder = class { static getCoder( abi, argument, options = { padToWordSize: false, } ) { const resolvedAbiType = new ResolvedAbiType(abi, argument); return getCoderForEncoding(options.encoding)(resolvedAbiType, options); } static getLogDecoder( abi, logId, options = { padToWordSize: false, } ) { const loggedType = abi.loggedTypes.find((type) => type.logId === logId); if (!loggedType) { throw new import_errors20.FuelError( import_errors20.ErrorCode.LOG_TYPE_NOT_FOUND, `Log type with logId '${logId}' doesn't exist in the ABI.` ); } const resolvedAbiType = new ResolvedAbiType(abi, loggedType.loggedType); const internalCoder = getCoderForEncoding(options.encoding)( resolvedAbiType, options ); return (data) => internalCoder.decode(import_utils12.arrayify(data), 0)[0]; } static encode(abi, argument, value, options) { return this.getCoder(abi, argument, options).encode(value); } static decode(abi, argument, data, offset, options) { return this.getCoder(abi, argument, options).decode(data, offset); } }; // src/FunctionFragment.ts var import_crypto = require("@fuel-ts/crypto"); var import_errors20 = require("@fuel-ts/errors"); var import_hasher = require("@fuel-ts/hasher"); var import_math12 = require("@fuel-ts/math"); var import_utils11 = require("@fuel-ts/utils"); // src/utils/getFunctionInputs.ts var getFunctionInputs = (params) => { const { jsonAbi, inputs } = params; let isMandatory = false; return inputs.reduceRight((result, input) => { const type = findTypeById(jsonAbi, input.type); isMandatory = isMandatory || (type.type !== VOID_TYPE && !optionRegEx.test(type.type)); return [{ ...input, isOptional: !isMandatory }, ...result]; }, []); }; // src/utils/padValuesWithUndefined.ts var padValuesWithUndefined = (values, inputs) => { if (values.length >= inputs.length) { return values; } const paddedValues = values.slice(); paddedValues.length = inputs.length; paddedValues.fill(void 0, values.length); return paddedValues; }; // src/FunctionFragment.ts var FunctionFragment = class { signature; selector; selectorBytes; encoding; name; jsonFn; attributes; jsonAbiOld; jsonFnOld; constructor(jsonAbi, fn) { this.jsonFn = fn; this.jsonAbiOld = jsonAbi; this.jsonFnOld = jsonAbi.functions.find((f) => f.name === fn.name); this.name = fn.name; this.signature = FunctionFragment.getSignature( this.jsonAbiOld, this.jsonFnOld ); this.selector = FunctionFragment.getFunctionSelector(this.signature); this.selectorBytes = new StdStringCoder().encode(this.name); this.encoding = getEncodingVersion(jsonAbi.encoding); this.attributes = this.jsonFn.attributes ?? []; } static getSignature(abi, fn) { const inputsSignatures = fn.inputs.map((input) => new ResolvedAbiType(abi, input).getSignature() ); return `${fn.name}(${inputsSignatures.join(",")})`; } static getFunctionSelector(functionSignature) { const hashedFunctionSignature = (0, import_hasher.sha256)( (0, import_crypto.bufferFromString)(functionSignature, "utf-8") ); return (0, import_math12.bn)(hashedFunctionSignature.slice(0, 10)).toHex(8); } encodeArguments(values) { const inputs = getFunctionInputs({ jsonAbi: this.jsonAbiOld, inputs: this.jsonFnOld.inputs, }); const mandatoryInputLength = inputs.filter((i) => !i.isOptional).length; if (values.length < mandatoryInputLength) { throw new import_errors20.FuelError( import_errors20.ErrorCode.ABI_TYPES_AND_VALUES_MISMATCH, `Invalid number of arguments. Expected a minimum of ${mandatoryInputLength} arguments, received ${values.length}` ); } const coders = this.jsonFnOld.inputs.map((t) => AbiCoder.getCoder(this.jsonAbiOld, t, { encoding: this.encoding, }) ); const argumentValues = padValuesWithUndefined(values, this.jsonFn.inputs); return new TupleCoder(coders).encode(argumentValues); } decodeArguments(data) { const bytes = (0, import_utils11.arrayify)(data); const nonVoidInputs = findNonVoidInputs( this.jsonAbiOld, this.jsonFnOld.inputs ); if (nonVoidInputs.length === 0) { if (bytes.length === 0) { return void 0; } throw new import_errors20.FuelError( import_errors20.ErrorCode.DECODE_ERROR, `Types/values length mismatch during decode. ${JSON.stringify({ count: { types: this.jsonFn.inputs.length, nonVoidInputs: nonVoidInputs.length, values: bytes.length, }, value: { args: this.jsonFn.inputs, nonVoidInputs, values: bytes, }, })}` ); } const result = this.jsonFnOld.inputs.reduce( (obj, input) => { const coder = AbiCoder.getCoder(this.jsonAbiOld, input, { encoding: this.encoding, }); const [decodedValue, decodedValueByteSize] = coder.decode( bytes, obj.offset ); return { decoded: [...obj.decoded, decodedValue], offset: obj.offset + decodedValueByteSize, }; }, { decoded: [], offset: 0 } ); return result.decoded; } decodeOutput(data) { const bytes = (0, import_utils11.arrayify)(data); const coder = AbiCoder.getCoder(this.jsonAbiOld, this.jsonFnOld.output, { encoding: this.encoding, }); return coder.decode(bytes, 0); } /** * Checks if the function is read-only i.e. it only reads from storage, does not write to it. * * @returns True if the function is read-only or pure, false otherwise. */ is