docs: added jsdocs to abi
This commit is contained in:
parent
16f3c44daa
commit
b7750cf098
@ -1,3 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* When sending values to or receiving values from a [[Contract]], the
|
||||||
|
* data is generally encoded using the [ABI standard](solc-abi-standard).
|
||||||
|
*
|
||||||
|
* The AbiCoder provides a utility to encode values to ABI data and
|
||||||
|
* decode values from ABI data.
|
||||||
|
*
|
||||||
|
* Most of the time, developers should favour the [[Contract]] class,
|
||||||
|
* which further abstracts a lot of the finer details of ABI data.
|
||||||
|
*
|
||||||
|
* @_section api/abi/abi-coder:ABI Encoding
|
||||||
|
*/
|
||||||
|
|
||||||
// See: https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
|
// See: https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
|
||||||
|
|
||||||
import { assertArgumentCount, assertArgument } from "../utils/index.js";
|
import { assertArgumentCount, assertArgument } from "../utils/index.js";
|
||||||
@ -22,10 +35,92 @@ import type {
|
|||||||
CallExceptionAction, CallExceptionError, CallExceptionTransaction
|
CallExceptionAction, CallExceptionError, CallExceptionTransaction
|
||||||
} from "../utils/index.js";
|
} from "../utils/index.js";
|
||||||
|
|
||||||
|
// https://docs.soliditylang.org/en/v0.8.17/control-structures.html
|
||||||
|
const PanicReasons: Map<number, string> = new Map();
|
||||||
|
PanicReasons.set(0x00, "GENERIC_PANIC");
|
||||||
|
PanicReasons.set(0x01, "ASSERT_FALSE");
|
||||||
|
PanicReasons.set(0x11, "OVERFLOW");
|
||||||
|
PanicReasons.set(0x12, "DIVIDE_BY_ZERO");
|
||||||
|
PanicReasons.set(0x21, "ENUM_RANGE_ERROR");
|
||||||
|
PanicReasons.set(0x22, "BAD_STORAGE_DATA");
|
||||||
|
PanicReasons.set(0x31, "STACK_UNDERFLOW");
|
||||||
|
PanicReasons.set(0x32, "ARRAY_RANGE_ERROR");
|
||||||
|
PanicReasons.set(0x41, "OUT_OF_MEMORY");
|
||||||
|
PanicReasons.set(0x51, "UNINITIALIZED_FUNCTION_CALL");
|
||||||
|
|
||||||
const paramTypeBytes = new RegExp(/^bytes([0-9]*)$/);
|
const paramTypeBytes = new RegExp(/^bytes([0-9]*)$/);
|
||||||
const paramTypeNumber = new RegExp(/^(u?int)([0-9]*)$/);
|
const paramTypeNumber = new RegExp(/^(u?int)([0-9]*)$/);
|
||||||
|
|
||||||
|
|
||||||
|
let defaultCoder: null | AbiCoder = null;
|
||||||
|
|
||||||
|
|
||||||
|
function getBuiltinCallException(action: CallExceptionAction, tx: { to?: null | string, from?: null | string, data?: string }, data: null | BytesLike, abiCoder: AbiCoder): CallExceptionError {
|
||||||
|
let message = "missing revert data";
|
||||||
|
|
||||||
|
let reason: null | string = null;
|
||||||
|
const invocation = null;
|
||||||
|
let revert: null | { signature: string, name: string, args: Array<any> } = null;
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
message = "execution reverted";
|
||||||
|
|
||||||
|
const bytes = getBytes(data);
|
||||||
|
data = hexlify(data);
|
||||||
|
|
||||||
|
if (bytes.length % 32 !== 4) {
|
||||||
|
message += " (could not decode reason; invalid data length)";
|
||||||
|
|
||||||
|
} else if (hexlify(bytes.slice(0, 4)) === "0x08c379a0") {
|
||||||
|
// Error(string)
|
||||||
|
try {
|
||||||
|
reason = abiCoder.decode([ "string" ], bytes.slice(4))[0]
|
||||||
|
revert = {
|
||||||
|
signature: "Error(string)",
|
||||||
|
name: "Error",
|
||||||
|
args: [ reason ]
|
||||||
|
};
|
||||||
|
message += `: ${ JSON.stringify(reason) }`;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
message += " (could not decode reason; invalid data)";
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (hexlify(bytes.slice(0, 4)) === "0x4e487b71") {
|
||||||
|
// Panic(uint256)
|
||||||
|
try {
|
||||||
|
const code = Number(abiCoder.decode([ "uint256" ], bytes.slice(4))[0]);
|
||||||
|
revert = {
|
||||||
|
signature: "Panic(uint256)",
|
||||||
|
name: "Panic",
|
||||||
|
args: [ code ]
|
||||||
|
};
|
||||||
|
reason = `Panic due to ${ PanicReasons.get(code) || "UNKNOWN" }(${ code })`;
|
||||||
|
message += `: ${ reason }`;
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
message += " (could not decode panic reason)";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
message += " (unknown custom error)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const transaction: CallExceptionTransaction = {
|
||||||
|
to: (tx.to ? getAddress(tx.to): null),
|
||||||
|
data: (tx.data || "0x")
|
||||||
|
};
|
||||||
|
if (tx.from) { transaction.from = getAddress(tx.from); }
|
||||||
|
|
||||||
|
return makeError(message, "CALL_EXCEPTION", {
|
||||||
|
action, data, reason, transaction, invocation, revert
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* About AbiCoder
|
||||||
|
*/
|
||||||
export class AbiCoder {
|
export class AbiCoder {
|
||||||
|
|
||||||
#getCoder(param: ParamType): Coder {
|
#getCoder(param: ParamType): Coder {
|
||||||
@ -70,12 +165,23 @@ export class AbiCoder {
|
|||||||
assertArgument(false, "invalid type", "type", param.type);
|
assertArgument(false, "invalid type", "type", param.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the default values for the given %%types%%.
|
||||||
|
*
|
||||||
|
* For example, a ``uint`` is by default ``0`` and ``bool``
|
||||||
|
* is by default ``false``.
|
||||||
|
*/
|
||||||
getDefaultValue(types: ReadonlyArray<string | ParamType>): Result {
|
getDefaultValue(types: ReadonlyArray<string | ParamType>): Result {
|
||||||
const coders: Array<Coder> = types.map((type) => this.#getCoder(ParamType.from(type)));
|
const coders: Array<Coder> = types.map((type) => this.#getCoder(ParamType.from(type)));
|
||||||
const coder = new TupleCoder(coders, "_");
|
const coder = new TupleCoder(coders, "_");
|
||||||
return coder.defaultValue();
|
return coder.defaultValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encode the %%values%% as the %%types%% into ABI data.
|
||||||
|
*
|
||||||
|
* @returns DataHexstring
|
||||||
|
*/
|
||||||
encode(types: ReadonlyArray<string | ParamType>, values: ReadonlyArray<any>): string {
|
encode(types: ReadonlyArray<string | ParamType>, values: ReadonlyArray<any>): string {
|
||||||
assertArgumentCount(values.length, types.length, "types/values length mismatch");
|
assertArgumentCount(values.length, types.length, "types/values length mismatch");
|
||||||
|
|
||||||
@ -87,87 +193,37 @@ export class AbiCoder {
|
|||||||
return writer.data;
|
return writer.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decode the ABI %%data%% as the %%types%% into values.
|
||||||
|
*
|
||||||
|
* If %%loose%% decoding is enabled, then strict padding is
|
||||||
|
* not enforced. Some older versions of Solidity incorrectly
|
||||||
|
* padded event data emitted from ``external`` functions.
|
||||||
|
*/
|
||||||
decode(types: ReadonlyArray<string | ParamType>, data: BytesLike, loose?: boolean): Result {
|
decode(types: ReadonlyArray<string | ParamType>, data: BytesLike, loose?: boolean): Result {
|
||||||
const coders: Array<Coder> = types.map((type) => this.#getCoder(ParamType.from(type)));
|
const coders: Array<Coder> = types.map((type) => this.#getCoder(ParamType.from(type)));
|
||||||
const coder = new TupleCoder(coders, "_");
|
const coder = new TupleCoder(coders, "_");
|
||||||
return coder.decode(new Reader(data, loose));
|
return coder.decode(new Reader(data, loose));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// https://docs.soliditylang.org/en/v0.8.17/control-structures.html
|
/**
|
||||||
const PanicReasons: Map<number, string> = new Map();
|
* Returns the shared singleton instance of a default [[AbiCoder]].
|
||||||
PanicReasons.set(0x00, "GENERIC_PANIC");
|
*
|
||||||
PanicReasons.set(0x01, "ASSERT_FALSE");
|
* On the first call, the instance is created internally.
|
||||||
PanicReasons.set(0x11, "OVERFLOW");
|
*/
|
||||||
PanicReasons.set(0x12, "DIVIDE_BY_ZERO");
|
static defaultAbiCoder(): AbiCoder {
|
||||||
PanicReasons.set(0x21, "ENUM_RANGE_ERROR");
|
if (defaultCoder == null) {
|
||||||
PanicReasons.set(0x22, "BAD_STORAGE_DATA");
|
defaultCoder = new AbiCoder();
|
||||||
PanicReasons.set(0x31, "STACK_UNDERFLOW");
|
|
||||||
PanicReasons.set(0x32, "ARRAY_RANGE_ERROR");
|
|
||||||
PanicReasons.set(0x41, "OUT_OF_MEMORY");
|
|
||||||
PanicReasons.set(0x51, "UNINITIALIZED_FUNCTION_CALL");
|
|
||||||
|
|
||||||
export function getBuiltinCallException(action: CallExceptionAction, tx: { to?: null | string, from?: null | string, data?: string }, data: null | BytesLike): CallExceptionError {
|
|
||||||
let message = "missing revert data";
|
|
||||||
|
|
||||||
let reason: null | string = null;
|
|
||||||
const invocation = null;
|
|
||||||
let revert: null | { signature: string, name: string, args: Array<any> } = null;
|
|
||||||
|
|
||||||
if (data) {
|
|
||||||
message = "execution reverted";
|
|
||||||
|
|
||||||
const bytes = getBytes(data);
|
|
||||||
data = hexlify(data);
|
|
||||||
|
|
||||||
if (bytes.length % 32 !== 4) {
|
|
||||||
message += " (could not decode reason; invalid data length)";
|
|
||||||
|
|
||||||
} else if (hexlify(bytes.slice(0, 4)) === "0x08c379a0") {
|
|
||||||
// Error(string)
|
|
||||||
try {
|
|
||||||
reason = defaultAbiCoder.decode([ "string" ], bytes.slice(4))[0]
|
|
||||||
revert = {
|
|
||||||
signature: "Error(string)",
|
|
||||||
name: "Error",
|
|
||||||
args: [ reason ]
|
|
||||||
};
|
|
||||||
message += `: ${ JSON.stringify(reason) }`;
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.log(error);
|
|
||||||
message += " (could not decode reason; invalid data)";
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (hexlify(bytes.slice(0, 4)) === "0x4e487b71") {
|
|
||||||
// Panic(uint256)
|
|
||||||
try {
|
|
||||||
const code = Number(defaultAbiCoder.decode([ "uint256" ], bytes.slice(4))[0]);
|
|
||||||
revert = {
|
|
||||||
signature: "Panic(uint256)",
|
|
||||||
name: "Panic",
|
|
||||||
args: [ code ]
|
|
||||||
};
|
|
||||||
reason = `Panic due to ${ PanicReasons.get(code) || "UNKNOWN" }(${ code })`;
|
|
||||||
message += `: ${ reason }`;
|
|
||||||
} catch (error) {
|
|
||||||
console.log(error);
|
|
||||||
message += " (could not decode panic reason)";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
message += " (unknown custom error)";
|
|
||||||
}
|
}
|
||||||
|
return defaultCoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
const transaction: CallExceptionTransaction = {
|
/**
|
||||||
to: (tx.to ? getAddress(tx.to): null),
|
* Returns an ethers-compatible [[CALL_EXCEPTION]] Error for the given
|
||||||
data: (tx.data || "0x")
|
* result %%data%% for the [[CallExceptionAction]] %%action%% against
|
||||||
};
|
* the Transaction %%tx%%.
|
||||||
if (tx.from) { transaction.from = getAddress(tx.from); }
|
*/
|
||||||
|
static getBuiltinCallException(action: CallExceptionAction, tx: { to?: null | string, from?: null | string, data?: string }, data: null | BytesLike): CallExceptionError {
|
||||||
return makeError(message, "CALL_EXCEPTION", {
|
return getBuiltinCallException(action, tx, data, AbiCoder.defaultAbiCoder());
|
||||||
action, data, reason, transaction, invocation, revert
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const defaultAbiCoder: AbiCoder = new AbiCoder();
|
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
/**
|
||||||
|
* About bytes32 strings...
|
||||||
|
*
|
||||||
|
* @_docloc: api/utils:Bytes32 Strings
|
||||||
|
*/
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getBytes, toUtf8Bytes, toUtf8String, zeroPadBytes
|
getBytes, toUtf8Bytes, toUtf8String, zeroPadBytes
|
||||||
@ -5,7 +10,9 @@ import {
|
|||||||
|
|
||||||
import type { BytesLike } from "../utils/index.js";
|
import type { BytesLike } from "../utils/index.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes %%text%% as a Bytes32 string.
|
||||||
|
*/
|
||||||
export function encodeBytes32String(text: string): string {
|
export function encodeBytes32String(text: string): string {
|
||||||
|
|
||||||
// Get the bytes
|
// Get the bytes
|
||||||
@ -18,6 +25,9 @@ export function encodeBytes32String(text: string): string {
|
|||||||
return zeroPadBytes(bytes, 32);
|
return zeroPadBytes(bytes, 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes the Bytes32-encoded %%bytes%% into a string.
|
||||||
|
*/
|
||||||
export function decodeBytes32String(_bytes: BytesLike): string {
|
export function decodeBytes32String(_bytes: BytesLike): string {
|
||||||
const data = getBytes(_bytes, "bytes");
|
const data = getBytes(_bytes, "bytes");
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import {
|
|||||||
|
|
||||||
import type { BigNumberish, BytesLike } from "../../utils/index.js";
|
import type { BigNumberish, BytesLike } from "../../utils/index.js";
|
||||||
|
|
||||||
export const WordSize = 32;
|
export const WordSize: number = 32;
|
||||||
const Padding = new Uint8Array(WordSize);
|
const Padding = new Uint8Array(WordSize);
|
||||||
|
|
||||||
// Properties used to immediate pass through to the underlying object
|
// Properties used to immediate pass through to the underlying object
|
||||||
@ -16,11 +16,21 @@ const passProperties = [ "then" ];
|
|||||||
|
|
||||||
const _guard = { };
|
const _guard = { };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A [[Result]] is a sub-class of Array, which allows accessing any
|
||||||
|
* of its values either positionally by its index or, if keys are
|
||||||
|
* provided by its name.
|
||||||
|
*
|
||||||
|
* @_docloc: api/abi
|
||||||
|
*/
|
||||||
export class Result extends Array<any> {
|
export class Result extends Array<any> {
|
||||||
#indices: Map<string, Array<number>>;
|
#indices: Map<string, Array<number>>;
|
||||||
|
|
||||||
[ K: string | number ]: any
|
[ K: string | number ]: any
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
constructor(guard: any, items: Array<any>, keys?: Array<null | string>) {
|
constructor(guard: any, items: Array<any>, keys?: Array<null | string>) {
|
||||||
assertPrivate(guard, _guard, "Result");
|
assertPrivate(guard, _guard, "Result");
|
||||||
super(...items);
|
super(...items);
|
||||||
@ -85,6 +95,9 @@ export class Result extends Array<any> {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @_ignore
|
||||||
|
*/
|
||||||
slice(start?: number | undefined, end?: number | undefined): Array<any> {
|
slice(start?: number | undefined, end?: number | undefined): Array<any> {
|
||||||
if (start == null) { start = 0; }
|
if (start == null) { start = 0; }
|
||||||
if (end == null) { end = this.length; }
|
if (end == null) { end = this.length; }
|
||||||
@ -108,6 +121,14 @@ export class Result extends Array<any> {
|
|||||||
throw wrapped;
|
throw wrapped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value for %%name%%.
|
||||||
|
*
|
||||||
|
* Since it is possible to have a key whose name conflicts with
|
||||||
|
* a method on a [[Result]] or its superclass Array, or any
|
||||||
|
* JavaScript keyword, this ensures all named values are still
|
||||||
|
* accessible by name.
|
||||||
|
*/
|
||||||
getValue(name: string): any {
|
getValue(name: string): any {
|
||||||
const index = this.#indices.get(name);
|
const index = this.#indices.get(name);
|
||||||
if (index != null && index.length === 1) {
|
if (index != null && index.length === 1) {
|
||||||
@ -121,11 +142,28 @@ export class Result extends Array<any> {
|
|||||||
throw new Error(`no named parameter: ${ JSON.stringify(name) }`);
|
throw new Error(`no named parameter: ${ JSON.stringify(name) }`);
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromItems(items: Array<any>, keys?: Array<null | string>) {
|
/**
|
||||||
|
* Creates a new [[Result]] for %%items%% with each entry
|
||||||
|
* also accessible by its corresponding name in %%keys%%.
|
||||||
|
*/
|
||||||
|
static fromItems(items: Array<any>, keys?: Array<null | string>): Result {
|
||||||
return new Result(_guard, items, keys);
|
return new Result(_guard, items, keys);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all errors found in a [[Result]].
|
||||||
|
*
|
||||||
|
* Since certain errors encountered when creating a [[Result]] do
|
||||||
|
* not impact the ability to continue parsing data, they are
|
||||||
|
* deferred until they are actually accessed. Hence a faulty string
|
||||||
|
* in an Event that is never used does not impact the program flow.
|
||||||
|
*
|
||||||
|
* However, sometimes it may be useful to access, identify or
|
||||||
|
* validate correctness of a [[Result]].
|
||||||
|
*
|
||||||
|
* @_docloc api/abi
|
||||||
|
*/
|
||||||
export function checkResultErrors(result: Result): Array<{ path: Array<string | number>, error: Error }> {
|
export function checkResultErrors(result: Result): Array<{ path: Array<string | number>, error: Error }> {
|
||||||
// Find the first error (if any)
|
// Find the first error (if any)
|
||||||
const errors: Array<{ path: Array<string | number>, error: Error }> = [ ];
|
const errors: Array<{ path: Array<string | number>, error: Error }> = [ ];
|
||||||
@ -162,7 +200,9 @@ function getValue(value: BigNumberish): Uint8Array {
|
|||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @_ignore
|
||||||
|
*/
|
||||||
export abstract class Coder {
|
export abstract class Coder {
|
||||||
|
|
||||||
// The coder name:
|
// The coder name:
|
||||||
@ -198,6 +238,9 @@ export abstract class Coder {
|
|||||||
abstract defaultValue(): any;
|
abstract defaultValue(): any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @_ignore
|
||||||
|
*/
|
||||||
export class Writer {
|
export class Writer {
|
||||||
// An array of WordSize lengthed objects to concatenation
|
// An array of WordSize lengthed objects to concatenation
|
||||||
#data: Array<Uint8Array>;
|
#data: Array<Uint8Array>;
|
||||||
@ -250,6 +293,9 @@ export class Writer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @_ignore
|
||||||
|
*/
|
||||||
export class Reader {
|
export class Reader {
|
||||||
// Allows incomplete unpadded data to be read; otherwise an error
|
// Allows incomplete unpadded data to be read; otherwise an error
|
||||||
// is raised if attempting to overrun the buffer. This is required
|
// is raised if attempting to overrun the buffer. This is required
|
||||||
|
@ -7,6 +7,9 @@ import { Coder } from "./abstract-coder.js";
|
|||||||
import type { Reader, Writer } from "./abstract-coder.js";
|
import type { Reader, Writer } from "./abstract-coder.js";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @_ignore
|
||||||
|
*/
|
||||||
export class AddressCoder extends Coder {
|
export class AddressCoder extends Coder {
|
||||||
|
|
||||||
constructor(localName: string) {
|
constructor(localName: string) {
|
||||||
|
@ -2,7 +2,11 @@ import { Coder } from "./abstract-coder.js";
|
|||||||
|
|
||||||
import type { Reader, Writer } from "./abstract-coder.js";
|
import type { Reader, Writer } from "./abstract-coder.js";
|
||||||
|
|
||||||
// Clones the functionality of an existing Coder, but without a localName
|
/**
|
||||||
|
* Clones the functionality of an existing Coder, but without a localName
|
||||||
|
*
|
||||||
|
* @_ignore
|
||||||
|
*/
|
||||||
export class AnonymousCoder extends Coder {
|
export class AnonymousCoder extends Coder {
|
||||||
private coder: Coder;
|
private coder: Coder;
|
||||||
|
|
||||||
|
@ -9,7 +9,9 @@ import { AnonymousCoder } from "./anonymous.js";
|
|||||||
|
|
||||||
import type { Reader } from "./abstract-coder.js";
|
import type { Reader } from "./abstract-coder.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @_ignore
|
||||||
|
*/
|
||||||
export function pack(writer: Writer, coders: ReadonlyArray<Coder>, values: Array<any> | { [ name: string ]: any }): number {
|
export function pack(writer: Writer, coders: ReadonlyArray<Coder>, values: Array<any> | { [ name: string ]: any }): number {
|
||||||
let arrayValues: Array<any> = [ ];
|
let arrayValues: Array<any> = [ ];
|
||||||
|
|
||||||
@ -71,6 +73,9 @@ export function pack(writer: Writer, coders: ReadonlyArray<Coder>, values: Array
|
|||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @_ignore
|
||||||
|
*/
|
||||||
export function unpack(reader: Reader, coders: ReadonlyArray<Coder>): Result {
|
export function unpack(reader: Reader, coders: ReadonlyArray<Coder>): Result {
|
||||||
let values: Array<any> = [];
|
let values: Array<any> = [];
|
||||||
let keys: Array<null | string> = [ ];
|
let keys: Array<null | string> = [ ];
|
||||||
@ -125,7 +130,9 @@ export function unpack(reader: Reader, coders: ReadonlyArray<Coder>): Result {
|
|||||||
return Result.fromItems(values, keys);
|
return Result.fromItems(values, keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @_ignore
|
||||||
|
*/
|
||||||
export class ArrayCoder extends Coder {
|
export class ArrayCoder extends Coder {
|
||||||
readonly coder!: Coder;
|
readonly coder!: Coder;
|
||||||
readonly length!: number;
|
readonly length!: number;
|
||||||
|
@ -3,7 +3,9 @@ import { Coder } from "./abstract-coder.js";
|
|||||||
|
|
||||||
import type { Reader, Writer } from "./abstract-coder.js";
|
import type { Reader, Writer } from "./abstract-coder.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @_ignore
|
||||||
|
*/
|
||||||
export class BooleanCoder extends Coder {
|
export class BooleanCoder extends Coder {
|
||||||
|
|
||||||
constructor(localName: string) {
|
constructor(localName: string) {
|
||||||
|
@ -5,6 +5,9 @@ import { Coder } from "./abstract-coder.js";
|
|||||||
import type { Reader, Writer } from "./abstract-coder.js";
|
import type { Reader, Writer } from "./abstract-coder.js";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @_ignore
|
||||||
|
*/
|
||||||
export class DynamicBytesCoder extends Coder {
|
export class DynamicBytesCoder extends Coder {
|
||||||
constructor(type: string, localName: string) {
|
constructor(type: string, localName: string) {
|
||||||
super(type, type, localName, true);
|
super(type, type, localName, true);
|
||||||
@ -26,6 +29,9 @@ export class DynamicBytesCoder extends Coder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @_ignore
|
||||||
|
*/
|
||||||
export class BytesCoder extends DynamicBytesCoder {
|
export class BytesCoder extends DynamicBytesCoder {
|
||||||
constructor(localName: string) {
|
constructor(localName: string) {
|
||||||
super("bytes", localName);
|
super("bytes", localName);
|
||||||
|
@ -9,6 +9,9 @@ import type { BytesLike } from "../../utils/index.js";
|
|||||||
import type { Reader, Writer } from "./abstract-coder.js";
|
import type { Reader, Writer } from "./abstract-coder.js";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @_ignore
|
||||||
|
*/
|
||||||
export class FixedBytesCoder extends Coder {
|
export class FixedBytesCoder extends Coder {
|
||||||
readonly size!: number;
|
readonly size!: number;
|
||||||
|
|
||||||
|
@ -3,6 +3,9 @@ import type { Reader, Writer } from "./abstract-coder.js";
|
|||||||
|
|
||||||
const Empty = new Uint8Array([ ]);
|
const Empty = new Uint8Array([ ]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @_ignore
|
||||||
|
*/
|
||||||
export class NullCoder extends Coder {
|
export class NullCoder extends Coder {
|
||||||
|
|
||||||
constructor(localName: string) {
|
constructor(localName: string) {
|
||||||
|
@ -14,6 +14,9 @@ const BN_0 = BigInt(0);
|
|||||||
const BN_1 = BigInt(1);
|
const BN_1 = BigInt(1);
|
||||||
const BN_MAX_UINT256 = BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
|
const BN_MAX_UINT256 = BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @_ignore
|
||||||
|
*/
|
||||||
export class NumberCoder extends Coder {
|
export class NumberCoder extends Coder {
|
||||||
readonly size!: number;
|
readonly size!: number;
|
||||||
readonly signed!: boolean;
|
readonly signed!: boolean;
|
||||||
|
@ -6,6 +6,9 @@ import { DynamicBytesCoder } from "./bytes.js";
|
|||||||
import type { Reader, Writer } from "./abstract-coder.js";
|
import type { Reader, Writer } from "./abstract-coder.js";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @_ignore
|
||||||
|
*/
|
||||||
export class StringCoder extends DynamicBytesCoder {
|
export class StringCoder extends DynamicBytesCoder {
|
||||||
|
|
||||||
constructor(localName: string) {
|
constructor(localName: string) {
|
||||||
|
@ -7,6 +7,9 @@ import { pack, unpack } from "./array.js";
|
|||||||
|
|
||||||
import type { Reader, Writer } from "./abstract-coder.js";
|
import type { Reader, Writer } from "./abstract-coder.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @_ignore
|
||||||
|
*/
|
||||||
export class TupleCoder extends Coder {
|
export class TupleCoder extends Coder {
|
||||||
readonly coders!: ReadonlyArray<Coder>;
|
readonly coders!: ReadonlyArray<Coder>;
|
||||||
|
|
||||||
|
@ -1,3 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* About frgaments...
|
||||||
|
*
|
||||||
|
* @_subsection api/abi/abi-coder:Fragments
|
||||||
|
*/
|
||||||
|
|
||||||
import {
|
import {
|
||||||
defineProperties, getBigInt, getNumber,
|
defineProperties, getBigInt, getNumber,
|
||||||
assert, assertPrivate, assertArgument
|
assert, assertPrivate, assertArgument
|
||||||
@ -460,6 +466,9 @@ export class ParamType {
|
|||||||
readonly arrayChildren!: null | ParamType;
|
readonly arrayChildren!: null | ParamType;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
constructor(guard: any, name: string, type: string, baseType: string, indexed: null | boolean, components: null | ReadonlyArray<ParamType>, arrayLength: null | number, arrayChildren: null | ParamType) {
|
constructor(guard: any, name: string, type: string, baseType: string, indexed: null | boolean, components: null | ReadonlyArray<ParamType>, arrayLength: null | number, arrayChildren: null | ParamType) {
|
||||||
assertPrivate(guard, _guard, "ParamType");
|
assertPrivate(guard, _guard, "ParamType");
|
||||||
Object.defineProperty(this, internal, { value: ParamTypeInternal });
|
Object.defineProperty(this, internal, { value: ParamTypeInternal });
|
||||||
@ -489,7 +498,8 @@ export class ParamType {
|
|||||||
// - sighash: "(uint256,address)"
|
// - sighash: "(uint256,address)"
|
||||||
// - minimal: "tuple(uint256,address) indexed"
|
// - minimal: "tuple(uint256,address) indexed"
|
||||||
// - full: "tuple(uint256 foo, address bar) indexed baz"
|
// - full: "tuple(uint256 foo, address bar) indexed baz"
|
||||||
format(format: FormatType = "sighash"): string {
|
format(format?: FormatType): string {
|
||||||
|
if (format == null) { format = "sighash"; }
|
||||||
if (format === "json") {
|
if (format === "json") {
|
||||||
let result: any = {
|
let result: any = {
|
||||||
type: ((this.baseType === "tuple") ? "tuple": this.type),
|
type: ((this.baseType === "tuple") ? "tuple": this.type),
|
||||||
@ -629,7 +639,7 @@ export class ParamType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async walkAsync(value: any, process: (type: string, value: any) => any | Promise<any>): Promise<any> {
|
async walkAsync(value: any, process: FragmentWalkAsyncFunc): Promise<any> {
|
||||||
const promises: Array<Promise<void>> = [ ];
|
const promises: Array<Promise<void>> = [ ];
|
||||||
const result: [ any ] = [ value ];
|
const result: [ any ] = [ value ];
|
||||||
this.#walkAsync(promises, value, process, (value: any) => {
|
this.#walkAsync(promises, value, process, (value: any) => {
|
||||||
@ -733,6 +743,9 @@ export abstract class Fragment {
|
|||||||
readonly type!: FragmentType;
|
readonly type!: FragmentType;
|
||||||
readonly inputs!: ReadonlyArray<ParamType>;
|
readonly inputs!: ReadonlyArray<ParamType>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
constructor(guard: any, type: FragmentType, inputs: ReadonlyArray<ParamType>) {
|
constructor(guard: any, type: FragmentType, inputs: ReadonlyArray<ParamType>) {
|
||||||
assertPrivate(guard, _guard, "Fragment");
|
assertPrivate(guard, _guard, "Fragment");
|
||||||
inputs = Object.freeze(inputs.slice());
|
inputs = Object.freeze(inputs.slice());
|
||||||
@ -802,6 +815,9 @@ export abstract class Fragment {
|
|||||||
export abstract class NamedFragment extends Fragment {
|
export abstract class NamedFragment extends Fragment {
|
||||||
readonly name!: string;
|
readonly name!: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
constructor(guard: any, type: FragmentType, name: string, inputs: ReadonlyArray<ParamType>) {
|
constructor(guard: any, type: FragmentType, name: string, inputs: ReadonlyArray<ParamType>) {
|
||||||
super(guard, type, inputs);
|
super(guard, type, inputs);
|
||||||
assertArgument(typeof(name) === "string" && name.match(regexIdentifier),
|
assertArgument(typeof(name) === "string" && name.match(regexIdentifier),
|
||||||
@ -816,6 +832,9 @@ function joinParams(format: FormatType, params: ReadonlyArray<ParamType>): strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class ErrorFragment extends NamedFragment {
|
export class ErrorFragment extends NamedFragment {
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
constructor(guard: any, name: string, inputs: ReadonlyArray<ParamType>) {
|
constructor(guard: any, name: string, inputs: ReadonlyArray<ParamType>) {
|
||||||
super(guard, "error", name, inputs);
|
super(guard, "error", name, inputs);
|
||||||
Object.defineProperty(this, internal, { value: ErrorFragmentInternal });
|
Object.defineProperty(this, internal, { value: ErrorFragmentInternal });
|
||||||
@ -825,7 +844,8 @@ export class ErrorFragment extends NamedFragment {
|
|||||||
return id(this.format("sighash")).substring(0, 10);
|
return id(this.format("sighash")).substring(0, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
format(format: FormatType = "sighash"): string {
|
format(format?: FormatType): string {
|
||||||
|
if (format == null) { format = "sighash"; }
|
||||||
if (format === "json") {
|
if (format === "json") {
|
||||||
return JSON.stringify({
|
return JSON.stringify({
|
||||||
type: "error",
|
type: "error",
|
||||||
@ -867,6 +887,9 @@ export class ErrorFragment extends NamedFragment {
|
|||||||
export class EventFragment extends NamedFragment {
|
export class EventFragment extends NamedFragment {
|
||||||
readonly anonymous!: boolean;
|
readonly anonymous!: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
constructor(guard: any, name: string, inputs: ReadonlyArray<ParamType>, anonymous: boolean) {
|
constructor(guard: any, name: string, inputs: ReadonlyArray<ParamType>, anonymous: boolean) {
|
||||||
super(guard, "event", name, inputs);
|
super(guard, "event", name, inputs);
|
||||||
Object.defineProperty(this, internal, { value: EventFragmentInternal });
|
Object.defineProperty(this, internal, { value: EventFragmentInternal });
|
||||||
@ -877,7 +900,8 @@ export class EventFragment extends NamedFragment {
|
|||||||
return id(this.format("sighash"));
|
return id(this.format("sighash"));
|
||||||
}
|
}
|
||||||
|
|
||||||
format(format: FormatType = "sighash"): string {
|
format(format?: FormatType): string {
|
||||||
|
if (format == null) { format = "sighash"; }
|
||||||
if (format === "json") {
|
if (format === "json") {
|
||||||
return JSON.stringify({
|
return JSON.stringify({
|
||||||
type: "event",
|
type: "event",
|
||||||
@ -923,14 +947,17 @@ export class ConstructorFragment extends Fragment {
|
|||||||
readonly payable!: boolean;
|
readonly payable!: boolean;
|
||||||
readonly gas!: null | bigint;
|
readonly gas!: null | bigint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
constructor(guard: any, type: FragmentType, inputs: ReadonlyArray<ParamType>, payable: boolean, gas: null | bigint) {
|
constructor(guard: any, type: FragmentType, inputs: ReadonlyArray<ParamType>, payable: boolean, gas: null | bigint) {
|
||||||
super(guard, type, inputs);
|
super(guard, type, inputs);
|
||||||
Object.defineProperty(this, internal, { value: ConstructorFragmentInternal });
|
Object.defineProperty(this, internal, { value: ConstructorFragmentInternal });
|
||||||
defineProperties<ConstructorFragment>(this, { payable, gas });
|
defineProperties<ConstructorFragment>(this, { payable, gas });
|
||||||
}
|
}
|
||||||
|
|
||||||
format(format: FormatType = "sighash"): string {
|
format(format?: FormatType): string {
|
||||||
assert(format !== "sighash", "cannot format a constructor for sighash",
|
assert(format != null && format !== "sighash", "cannot format a constructor for sighash",
|
||||||
"UNSUPPORTED_OPERATION", { operation: "format(sighash)" });
|
"UNSUPPORTED_OPERATION", { operation: "format(sighash)" });
|
||||||
|
|
||||||
if (format === "json") {
|
if (format === "json") {
|
||||||
@ -983,6 +1010,9 @@ export class FunctionFragment extends NamedFragment {
|
|||||||
readonly payable!: boolean;
|
readonly payable!: boolean;
|
||||||
readonly gas!: null | bigint;
|
readonly gas!: null | bigint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
constructor(guard: any, name: string, stateMutability: string, inputs: ReadonlyArray<ParamType>, outputs: ReadonlyArray<ParamType>, gas: null | bigint) {
|
constructor(guard: any, name: string, stateMutability: string, inputs: ReadonlyArray<ParamType>, outputs: ReadonlyArray<ParamType>, gas: null | bigint) {
|
||||||
super(guard, "function", name, inputs);
|
super(guard, "function", name, inputs);
|
||||||
Object.defineProperty(this, internal, { value: FunctionFragmentInternal });
|
Object.defineProperty(this, internal, { value: FunctionFragmentInternal });
|
||||||
@ -996,7 +1026,8 @@ export class FunctionFragment extends NamedFragment {
|
|||||||
return id(this.format("sighash")).substring(0, 10);
|
return id(this.format("sighash")).substring(0, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
format(format: FormatType = "sighash"): string {
|
format(format?: FormatType): string {
|
||||||
|
if (format == null) { format = "sighash"; }
|
||||||
if (format === "json") {
|
if (format === "json") {
|
||||||
return JSON.stringify({
|
return JSON.stringify({
|
||||||
type: "function",
|
type: "function",
|
||||||
@ -1068,6 +1099,10 @@ export class FunctionFragment extends NamedFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class StructFragment extends NamedFragment {
|
export class StructFragment extends NamedFragment {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
constructor(guard: any, name: string, inputs: ReadonlyArray<ParamType>) {
|
constructor(guard: any, name: string, inputs: ReadonlyArray<ParamType>) {
|
||||||
super(guard, "struct", name, inputs);
|
super(guard, "struct", name, inputs);
|
||||||
Object.defineProperty(this, internal, { value: StructFragmentInternal });
|
Object.defineProperty(this, internal, { value: StructFragmentInternal });
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
|
/**
|
||||||
|
* Explain about ABI here...
|
||||||
|
*
|
||||||
|
* @_section api/abi:Application Binary Interface [abi]
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
//////
|
//////
|
||||||
export {
|
export { AbiCoder } from "./abi-coder.js";
|
||||||
AbiCoder,
|
|
||||||
defaultAbiCoder,
|
|
||||||
getBuiltinCallException
|
|
||||||
} from "./abi-coder.js";
|
|
||||||
|
|
||||||
export { decodeBytes32String, encodeBytes32String } from "./bytes32.js";
|
export { decodeBytes32String, encodeBytes32String } from "./bytes32.js";
|
||||||
|
|
||||||
|
@ -1,3 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* About Interface
|
||||||
|
*
|
||||||
|
* @_subsection api/abi:Interfaces [interfaces]
|
||||||
|
*/
|
||||||
|
|
||||||
import { keccak256 } from "../crypto/index.js"
|
import { keccak256 } from "../crypto/index.js"
|
||||||
import { id } from "../hash/index.js"
|
import { id } from "../hash/index.js"
|
||||||
import {
|
import {
|
||||||
@ -6,7 +12,7 @@ import {
|
|||||||
assert
|
assert
|
||||||
} from "../utils/index.js";
|
} from "../utils/index.js";
|
||||||
|
|
||||||
import { AbiCoder, defaultAbiCoder, getBuiltinCallException } from "./abi-coder.js";
|
import { AbiCoder } from "./abi-coder.js";
|
||||||
import { checkResultErrors, Result } from "./coders/abstract-coder.js";
|
import { checkResultErrors, Result } from "./coders/abstract-coder.js";
|
||||||
import { ConstructorFragment, ErrorFragment, EventFragment, Fragment, FunctionFragment, ParamType } from "./fragments.js";
|
import { ConstructorFragment, ErrorFragment, EventFragment, Fragment, FunctionFragment, ParamType } from "./fragments.js";
|
||||||
import { Typed } from "./typed.js";
|
import { Typed } from "./typed.js";
|
||||||
@ -144,9 +150,23 @@ function checkNames(fragment: Fragment, type: "input" | "output", params: Array<
|
|||||||
//export type AbiCoder = any;
|
//export type AbiCoder = any;
|
||||||
//const defaultAbiCoder: AbiCoder = { };
|
//const defaultAbiCoder: AbiCoder = { };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @TODO
|
||||||
|
*/
|
||||||
export type InterfaceAbi = string | ReadonlyArray<Fragment | JsonFragment | string>;
|
export type InterfaceAbi = string | ReadonlyArray<Fragment | JsonFragment | string>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An Interface abstracts many of the low-level details for
|
||||||
|
* encoding and decoding the data on the blockchain.
|
||||||
|
*
|
||||||
|
* An ABI provides information on how to encode data to send to
|
||||||
|
* a Contract, how to decode the results and events and how to
|
||||||
|
* interpret revert errors.
|
||||||
|
*
|
||||||
|
* The ABI can be specified by [any supported format](InterfaceAbi).
|
||||||
|
*/
|
||||||
export class Interface {
|
export class Interface {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All the Contract ABI members (i.e. methods, events, errors, etc).
|
* All the Contract ABI members (i.e. methods, events, errors, etc).
|
||||||
*/
|
*/
|
||||||
@ -164,6 +184,9 @@ export class Interface {
|
|||||||
|
|
||||||
#abiCoder: AbiCoder;
|
#abiCoder: AbiCoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new Interface for the %%fragments%%.
|
||||||
|
*/
|
||||||
constructor(fragments: InterfaceAbi) {
|
constructor(fragments: InterfaceAbi) {
|
||||||
let abi: ReadonlyArray<Fragment | JsonFragment | string> = [ ];
|
let abi: ReadonlyArray<Fragment | JsonFragment | string> = [ ];
|
||||||
if (typeof(fragments) === "string") {
|
if (typeof(fragments) === "string") {
|
||||||
@ -267,7 +290,7 @@ export class Interface {
|
|||||||
* data.
|
* data.
|
||||||
*/
|
*/
|
||||||
getAbiCoder(): AbiCoder {
|
getAbiCoder(): AbiCoder {
|
||||||
return defaultAbiCoder;
|
return AbiCoder.defaultAbiCoder();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find a function definition by any means necessary (unless it is ambiguous)
|
// Find a function definition by any means necessary (unless it is ambiguous)
|
||||||
@ -661,7 +684,7 @@ export class Interface {
|
|||||||
makeError(_data: BytesLike, tx: CallExceptionTransaction): CallExceptionError {
|
makeError(_data: BytesLike, tx: CallExceptionTransaction): CallExceptionError {
|
||||||
const data = getBytes(_data, "data");
|
const data = getBytes(_data, "data");
|
||||||
|
|
||||||
const error = getBuiltinCallException("call", tx, data);
|
const error = AbiCoder.getBuiltinCallException("call", tx, data);
|
||||||
|
|
||||||
// Not a built-in error; try finding a custom error
|
// Not a built-in error; try finding a custom error
|
||||||
if (!error.message.match(/could not decode/)) {
|
if (!error.message.match(/could not decode/)) {
|
||||||
@ -980,7 +1003,7 @@ export class Interface {
|
|||||||
* The %%value%% may be provided as an existing [[Interface]] object,
|
* The %%value%% may be provided as an existing [[Interface]] object,
|
||||||
* a JSON-encoded ABI or any Human-Readable ABI format.
|
* a JSON-encoded ABI or any Human-Readable ABI format.
|
||||||
*/
|
*/
|
||||||
static from(value: ReadonlyArray<Fragment | string | JsonFragment> | string | Interface): Interface {
|
static from(value: InterfaceAbi | Interface): Interface {
|
||||||
// Already an Interface, which is immutable
|
// Already an Interface, which is immutable
|
||||||
if (value instanceof Interface) { return value; }
|
if (value instanceof Interface) { return value; }
|
||||||
|
|
||||||
|
@ -1,3 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* About typed...
|
||||||
|
*
|
||||||
|
* @_subsection: api/abi:Typed Values
|
||||||
|
*/
|
||||||
|
|
||||||
import { assertPrivate, defineProperties } from "../utils/index.js";
|
import { assertPrivate, defineProperties } from "../utils/index.js";
|
||||||
|
|
||||||
import type { Addressable } from "../address/index.js";
|
import type { Addressable } from "../address/index.js";
|
||||||
@ -24,22 +30,26 @@ function b(value: BytesLike, size?: number): Typed {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface TypedNumber extends Typed {
|
export interface TypedNumber extends Typed {
|
||||||
|
value: number;
|
||||||
defaultValue(): number;
|
defaultValue(): number;
|
||||||
minValue(): number;
|
minValue(): number;
|
||||||
maxValue(): number;
|
maxValue(): number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TypedBigInt extends Typed {
|
export interface TypedBigInt extends Typed {
|
||||||
|
value: bigint;
|
||||||
defaultValue(): bigint;
|
defaultValue(): bigint;
|
||||||
minValue(): bigint;
|
minValue(): bigint;
|
||||||
maxValue(): bigint;
|
maxValue(): bigint;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TypedData extends Typed {
|
export interface TypedData extends Typed {
|
||||||
|
value: string;
|
||||||
defaultValue(): string;
|
defaultValue(): string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TypedString extends Typed {
|
export interface TypedString extends Typed {
|
||||||
|
value: string;
|
||||||
defaultValue(): string;
|
defaultValue(): string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,7 +63,8 @@ export class Typed {
|
|||||||
|
|
||||||
readonly _typedSymbol!: Symbol;
|
readonly _typedSymbol!: Symbol;
|
||||||
|
|
||||||
constructor(gaurd: any, type: string, value: any, options: any = null) {
|
constructor(gaurd: any, type: string, value: any, options?: any) {
|
||||||
|
if (options == null) { options = null; }
|
||||||
assertPrivate(_gaurd, gaurd, "Typed");
|
assertPrivate(_gaurd, gaurd, "Typed");
|
||||||
defineProperties<Typed>(this, { _typedSymbol, type, value });
|
defineProperties<Typed>(this, { _typedSymbol, type, value });
|
||||||
this.#options = options;
|
this.#options = options;
|
||||||
@ -238,10 +249,20 @@ export class Typed {
|
|||||||
return new Typed(_gaurd, "overrides", Object.assign({ }, v));
|
return new Typed(_gaurd, "overrides", Object.assign({ }, v));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true only if %%value%% is a [[Typed]] instance.
|
||||||
|
*/
|
||||||
static isTyped(value: any): value is Typed {
|
static isTyped(value: any): value is Typed {
|
||||||
return (value && value._typedSymbol === _typedSymbol);
|
return (value && value._typedSymbol === _typedSymbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the value is a [[Typed]] instance, validates the underlying value
|
||||||
|
* and returns it, otherwise returns value directly.
|
||||||
|
*
|
||||||
|
* This is useful for functions that with to accept either a [[Typed]]
|
||||||
|
* object or values.
|
||||||
|
*/
|
||||||
static dereference<T>(value: Typed | T, type: string): T {
|
static dereference<T>(value: Typed | T, type: string): T {
|
||||||
if (Typed.isTyped(value)) {
|
if (Typed.isTyped(value)) {
|
||||||
if (value.type !== type) {
|
if (value.type !== type) {
|
||||||
|
Loading…
Reference in New Issue
Block a user