diff --git a/src.ts/abi/fragments.ts b/src.ts/abi/fragments.ts index 910a24ece..771ae0e5f 100644 --- a/src.ts/abi/fragments.ts +++ b/src.ts/abi/fragments.ts @@ -10,30 +10,89 @@ import { } from "../utils/index.js"; import { id } from "../hash/index.js"; +/** + * A type description in a JSON API. + */ export interface JsonFragmentType { + /** + * The parameter name. + */ readonly name?: string; + + /** + * If the parameter is indexed. + */ readonly indexed?: boolean; + + /** + * The type of the parameter. + */ readonly type?: string; + + /** + * The internal Solidity type. + */ readonly internalType?: string; + + /** + * The components for a tuple. + */ readonly components?: ReadonlyArray; } +/** + * A fragment for a method, event or error in a JSON API. + */ export interface JsonFragment { + /** + * The name of the error, event, function, etc. + */ readonly name?: string; + + /** + * The type of the fragment (e.g. ``event``, ``"function"``, etc.) + */ readonly type?: string; + /** + * If the event is anonymous. + */ readonly anonymous?: boolean; + /** + * If the function is payable. + */ readonly payable?: boolean; + + /** + * If the function is constant. + */ readonly constant?: boolean; + + /** + * The mutability state of the function. + */ readonly stateMutability?: string; + /** + * The input parameters. + */ readonly inputs?: ReadonlyArray; + + /** + * The output parameters. + */ readonly outputs?: ReadonlyArray; + /** + * The gas limit to use when sending a transaction for this function. + */ readonly gas?: string; }; +/** + * The format to serialize the output as. + */ export type FormatType = // Bare formatting, as is needed for computing a sighash of an event or function "sighash" | @@ -429,8 +488,17 @@ function verifyBasicType(type: string): string { const _guard = { }; -export type FragmentWalkFunc = (type: string, value: any) => any; -export type FragmentWalkAsyncFunc = (type: string, value: any) => any | Promise; +/** + * When [walking](ParamType-walk) a [[ParamType]], this is called + * on each component. + */ +export type ParamTypeWalkFunc = (type: string, value: any) => any; + +/** + * When [walking asynchronously](ParamType-walkAsync) a [[ParamType]], + * this is called on each component. + */ +export type ParamTypeWalkAsyncFunc = (type: string, value: any) => any | Promise; const internal = Symbol.for("_ethers_internal"); @@ -441,28 +509,54 @@ const ConstructorFragmentInternal = "_ConstructorInternal"; const FunctionFragmentInternal = "_FunctionInternal"; const StructFragmentInternal = "_StructInternal"; +/** + * Each input and output of a [[Fragment]] is an Array of **PAramType**. + */ export class ParamType { - // The local name of the parameter (of "" if unbound) + /** + * The local name of the parameter (or ``""`` if unbound) + */ readonly name!: string; - // The fully qualified type (e.g. "address", "tuple(address)", "uint256[3][]" + /** + * The fully qualified type (e.g. ``"address"``, ``"tuple(address)"``, + * ``"uint256[3][]"``) + */ readonly type!: string; - // The base type (e.g. "address", "tuple", "array") + /** + * The base type (e.g. ``"address"``, ``"tuple"``, ``"array"``) + */ readonly baseType!: string; - // Indexable Paramters ONLY (otherwise null) + /** + * True if the parameters is indexed. + * + * For non-indexable types (see [[ParamType_isIndexable]]) this + * is ``null``. + */ readonly indexed!: null | boolean; - // Tuples ONLY: (otherwise null) - // - sub-components + /** + * The components for the tuple. + * + * For non-tuple types (see [[ParamType_isTuple]]) this is ``null``. + */ readonly components!: null | ReadonlyArray; - // Arrays ONLY: (otherwise null) - // - length of the array (-1 for dynamic length) - // - child type + /** + * The array length, or ``-1`` for dynamic-lengthed arrays. + * + * For non-array types (see [[ParamType_isArray]]) this is ``null``. + */ readonly arrayLength!: null | number; + + /** + * The type of each child in the array. + * + * For non-array types (see [[ParamType_isArray]]) this is ``null``. + */ readonly arrayChildren!: null | ParamType; @@ -494,10 +588,17 @@ export class ParamType { }); } - // Format the parameter fragment - // - sighash: "(uint256,address)" - // - minimal: "tuple(uint256,address) indexed" - // - full: "tuple(uint256 foo, address bar) indexed baz" + /** + * Return a string representation of this type. + * + * For example, + * + * ``sighash" => "(uint256,address)"`` + * + * ``"minimal" => "tuple(uint256,address) indexed"`` + * + * ``"full" => "tuple(uint256 foo, address bar) indexed baz"`` + */ format(format?: FormatType): string { if (format == null) { format = "sighash"; } if (format === "json") { @@ -539,23 +640,51 @@ export class ParamType { return result; } - static isArray(value: any): value is { arrayChildren: ParamType } { - return value && (value.baseType === "array") - } + /* + * Returns true if %%value%% is an Array type. + * + * This provides a type gaurd ensuring that the + * [[arrayChildren]] and [[arrayLength]] are non-null. + */ + //static isArray(value: any): value is { arrayChildren: ParamType, arrayLength: number } { + // return value && (value.baseType === "array") + //} - isArray(): this is (ParamType & { arrayLength: number, arrayChildren: ParamType }) { + /** + * Returns true if %%this%% is an Array type. + * + * This provides a type gaurd ensuring that [[arrayChildren]] + * and [[arrayLength]] are non-null. + */ + isArray(): this is (ParamType & { arrayChildren: ParamType, arrayLength: number }) { return (this.baseType === "array") } + /** + * Returns true if %%this%% is a Tuple type. + * + * This provides a type gaurd ensuring that [[components]] + * is non-null. + */ isTuple(): this is (ParamType & { components: ReadonlyArray }) { return (this.baseType === "tuple"); } + /** + * Returns true if %%this%% is an Indexable type. + * + * This provides a type gaurd ensuring that [[indexed]] + * is non-null. + */ isIndexable(): this is (ParamType & { indexed: boolean }) { return (this.indexed != null); } - walk(value: any, process: FragmentWalkFunc): any { + /** + * Walks the **ParamType** with %%value%%, calling %%process%% + * on each type, destructing the %%value%% recursively. + */ + walk(value: any, process: ParamTypeWalkFunc): any { if (this.isArray()) { if (!Array.isArray(value)) { throw new Error("invlaid array value"); } if (this.arrayLength !== -1 && value.length !== this.arrayLength) { @@ -577,7 +706,7 @@ export class ParamType { return process(this.type, value); } - #walkAsync(promises: Array>, value: any, process: FragmentWalkAsyncFunc, setValue: (value: any) => void): void { + #walkAsync(promises: Array>, value: any, process: ParamTypeWalkAsyncFunc, setValue: (value: any) => void): void { if (this.isArray()) { if (!Array.isArray(value)) { throw new Error("invlaid array value"); } @@ -639,7 +768,14 @@ export class ParamType { } } - async walkAsync(value: any, process: FragmentWalkAsyncFunc): Promise { + /** + * Walks the **ParamType** with %%value%%, asynchronously calling + * %%process%% on each type, destructing the %%value%% recursively. + * + * This can be used to resolve ENS naes by walking and resolving each + * ``"address"`` type. + */ + async walkAsync(value: any, process: ParamTypeWalkAsyncFunc): Promise { const promises: Array> = [ ]; const result: [ any ] = [ value ]; this.#walkAsync(promises, value, process, (value: any) => { @@ -649,6 +785,12 @@ export class ParamType { return result[0]; } + /** + * Creates a new **ParamType** for %%obj%%. + * + * If %%allowIndexed%% then the ``indexed`` keyword is permitted, + * otherwise the ``indexed`` keyword will throw an error. + */ static from(obj: any, allowIndexed?: boolean): ParamType { if (ParamType.isParamType(obj)) { return obj; } @@ -732,15 +874,31 @@ export class ParamType { return new ParamType(_guard, name, type, type, indexed, null, null, null); } + /** + * Returns true if %%value%% is a **ParamType**. + */ static isParamType(value: any): value is ParamType { return (value && value[internal] === ParamTypeInternal); } } +/** + * The type of a [[Fragment]]. + */ export type FragmentType = "constructor" | "error" | "event" | "function" | "struct"; +/** + * An abstract class to represent An individual fragment from a parse ABI. + */ export abstract class Fragment { + /** + * The type of the fragment. + */ readonly type!: FragmentType; + + /** + * The inputs for the fragment. + */ readonly inputs!: ReadonlyArray; /** @@ -752,8 +910,15 @@ export abstract class Fragment { defineProperties(this, { type, inputs }); } + /** + * Returns a string representation of this fragment. + */ abstract format(format?: FormatType): string; + /** + * Creates a new **Fragment** for %%obj%%, wich can be any supported + * ABI frgament type. + */ static from(obj: any): Fragment { if (typeof(obj) === "string") { try { @@ -791,28 +956,50 @@ export abstract class Fragment { throw new Error(`unsupported type: ${ obj }`); } + /** + * Returns true if %%value%% is a [[ConstructorFragment]]. + */ static isConstructor(value: any): value is ConstructorFragment { return ConstructorFragment.isFragment(value); } + /** + * Returns true if %%value%% is an [[ErrorFragment]]. + */ static isError(value: any): value is ErrorFragment { return ErrorFragment.isFragment(value); } + /** + * Returns true if %%value%% is an [[EventFragment]]. + */ static isEvent(value: any): value is EventFragment { return EventFragment.isFragment(value); } + /** + * Returns true if %%value%% is a [[FunctionFragment]]. + */ static isFunction(value: any): value is FunctionFragment { return FunctionFragment.isFragment(value); } + /** + * Returns true if %%value%% is a [[StructFragment]]. + */ static isStruct(value: any): value is StructFragment { return StructFragment.isFragment(value); } } +/** + * An abstract class to represent An individual fragment + * which has a name from a parse ABI. + */ export abstract class NamedFragment extends Fragment { + /** + * The name of the fragment. + */ readonly name!: string; /** @@ -831,6 +1018,9 @@ function joinParams(format: FormatType, params: ReadonlyArray): strin return "(" + params.map((p) => p.format(format)).join((format === "full") ? ", ": ",") + ")"; } +/** + * A Fragment which represents a //Custom Error//. + */ export class ErrorFragment extends NamedFragment { /** * @private @@ -840,6 +1030,9 @@ export class ErrorFragment extends NamedFragment { Object.defineProperty(this, internal, { value: ErrorFragmentInternal }); } + /** + * The Custom Error selector. + */ get selector(): string { return id(this.format("sighash")).substring(0, 10); } @@ -883,7 +1076,9 @@ export class ErrorFragment extends NamedFragment { } } - +/** + * A Fragment which represents an Event. + */ export class EventFragment extends NamedFragment { readonly anonymous!: boolean; @@ -896,6 +1091,9 @@ export class EventFragment extends NamedFragment { defineProperties(this, { anonymous }); } + /** + * The Event topic hash. + */ get topicHash(): string { return id(this.format("sighash")); } @@ -942,7 +1140,9 @@ export class EventFragment extends NamedFragment { } } - +/** + * A Fragment which represents a constructor. + */ export class ConstructorFragment extends Fragment { readonly payable!: boolean; readonly gas!: null | bigint; @@ -1002,12 +1202,34 @@ export class ConstructorFragment extends Fragment { } } +/** + * A Fragment which represents a method. + */ export class FunctionFragment extends NamedFragment { + /** + * If the function is constant (e.g. ``pure`` or ``view`` functions). + */ readonly constant!: boolean; + + /** + * The returned types for the result of calling this function. + */ readonly outputs!: ReadonlyArray; + + /** + * The state mutability (e.g. ``payable``, ``nonpayable``, ``view`` + * or ``pure``) + */ readonly stateMutability!: string; + /** + * If the function can be send a value during invocation. + */ readonly payable!: boolean; + + /** + * The amount of gas to send when calling this function + */ readonly gas!: null | bigint; /** @@ -1022,6 +1244,9 @@ export class FunctionFragment extends NamedFragment { defineProperties(this, { constant, gas, outputs, payable, stateMutability }); } + /** + * The Function selector. + */ get selector(): string { return id(this.format("sighash")).substring(0, 10); } @@ -1098,6 +1323,9 @@ export class FunctionFragment extends NamedFragment { } } +/** + * A Fragment which represents a structure. + */ export class StructFragment extends NamedFragment { /** diff --git a/src.ts/abi/index.ts b/src.ts/abi/index.ts index 7586df459..1c352862e 100644 --- a/src.ts/abi/index.ts +++ b/src.ts/abi/index.ts @@ -28,7 +28,7 @@ export { Typed } from "./typed.js"; export type { JsonFragment, JsonFragmentType, - FormatType, FragmentType, FragmentWalkAsyncFunc, FragmentWalkFunc + FormatType, FragmentType, ParamTypeWalkAsyncFunc, ParamTypeWalkFunc } from "./fragments.js"; export type { diff --git a/src.ts/crypto/keccak.ts b/src.ts/crypto/keccak.ts index 1ff05e7cb..ab2ba9db7 100644 --- a/src.ts/crypto/keccak.ts +++ b/src.ts/crypto/keccak.ts @@ -36,6 +36,10 @@ let __keccak256: (data: Uint8Array) => BytesLike = _keccak256; * keccak256(new Uint8Array([ 0x13, 0x37 ])) * //_result: * + * // Strings are assumed to be DataHexString, otherwise it will + * // throw. To hash UTF-8 data, see the note above. + * keccak256("Hello World") + * //_error: */ export function keccak256(_data: BytesLike): string { const data = getBytes(_data, "data"); diff --git a/src.ts/ethers.ts b/src.ts/ethers.ts index e7de9b50b..0e9c3fb76 100644 --- a/src.ts/ethers.ts +++ b/src.ts/ethers.ts @@ -127,6 +127,7 @@ export { export type { JsonFragment, JsonFragmentType, InterfaceAbi, + ParamTypeWalkFunc, ParamTypeWalkAsyncFunc } from "./abi/index.js"; export type { Addressable } from "./address/index.js"; diff --git a/src.ts/index.ts b/src.ts/index.ts index d2f4476d8..40496f1f8 100644 --- a/src.ts/index.ts +++ b/src.ts/index.ts @@ -2,7 +2,7 @@ * The Application Programming Interface (API) is the collection of * functions, classes and types offered by the Ethers library. * - * @_section: api:API Specification [about-api] + * @_section: api:Application Programming Interface [about-api] * @_navTitle: API */ import * as ethers from "./ethers.js"; diff --git a/src.ts/utils/base64.ts b/src.ts/utils/base64.ts index 2863fc027..2919ba5c0 100644 --- a/src.ts/utils/base64.ts +++ b/src.ts/utils/base64.ts @@ -1,5 +1,5 @@ /** - * [Base64 encoding](link-base64) using 6-bit words to encode + * [Base64 encoding](link-wiki-base64) using 6-bit words to encode * arbitrary bytes into a string using 65 printable symbols, the * upper-case and lower-case alphabet, the digits ``0`` through ``9``, * ``"+"`` and ``"/"`` with the ``"="`` used for padding. diff --git a/src.ts/utils/data.ts b/src.ts/utils/data.ts index 0ca6f49d9..dd7b8d7de 100644 --- a/src.ts/utils/data.ts +++ b/src.ts/utils/data.ts @@ -173,6 +173,12 @@ function zeroPad(data: BytesLike, length: number, left: boolean): string { /** * Return the [[DataHexString]] of %%data%% padded on the **left** * to %%length%% bytes. + * + * If %%data%% already exceeds %%length%%, a [[BufferOverrun]] is + * thrown. + * + * This pads data the same as **values** are in Solidity + * (e.g. ``uint128``). */ export function zeroPadValue(data: BytesLike, length: number): string { return zeroPad(data, length, true); @@ -181,6 +187,12 @@ export function zeroPadValue(data: BytesLike, length: number): string { /** * Return the [[DataHexString]] of %%data%% padded on the **right** * to %%length%% bytes. + * + * If %%data%% already exceeds %%length%%, a [[BufferOverrun]] is + * thrown. + * + * This pads data the same as **bytes** are in Solidity + * (e.g. ``bytes16``). */ export function zeroPadBytes(data: BytesLike, length: number): string { return zeroPad(data, length, false); diff --git a/src.ts/utils/uuid.ts b/src.ts/utils/uuid.ts index 18f987527..d82a2d5c8 100644 --- a/src.ts/utils/uuid.ts +++ b/src.ts/utils/uuid.ts @@ -1,3 +1,8 @@ +/** + * Explain UUID and link to RFC here. + * + * @_subsection: api/utils:UUID [about-uuid] + */ import { getBytes, hexlify } from "./data.js"; import type { BytesLike } from "./index.js"; diff --git a/src.ts/wordlists/lang-cz.ts b/src.ts/wordlists/lang-cz.ts index ea9326d05..c00bbf4ed 100644 --- a/src.ts/wordlists/lang-cz.ts +++ b/src.ts/wordlists/lang-cz.ts @@ -17,6 +17,8 @@ export class LangCz extends WordlistOwl { * * Using the constructor should be unnecessary, instead use the * [[wordlist]] singleton method. + * + * @_ignore: */ constructor() { super("cz", words, checksum); } diff --git a/src.ts/wordlists/lang-en.ts b/src.ts/wordlists/lang-en.ts index 06ef91f43..88aacb6d8 100644 --- a/src.ts/wordlists/lang-en.ts +++ b/src.ts/wordlists/lang-en.ts @@ -17,6 +17,8 @@ export class LangEn extends WordlistOwl { * * This should be unnecessary most of the time as the exported * [[langEn]] should suffice. + * + * @_ignore: */ constructor() { super("en", words, checksum); } diff --git a/src.ts/wordlists/lang-es.ts b/src.ts/wordlists/lang-es.ts index 6803693db..785cbfbfb 100644 --- a/src.ts/wordlists/lang-es.ts +++ b/src.ts/wordlists/lang-es.ts @@ -18,6 +18,8 @@ export class LangEs extends WordlistOwlA { * * This should be unnecessary most of the time as the exported * [[langEs]] should suffice. + * + * @_ignore: */ constructor() { super("es", words, accents, checksum); } diff --git a/src.ts/wordlists/lang-fr.ts b/src.ts/wordlists/lang-fr.ts index bc0bfaf77..8d3c0a86d 100644 --- a/src.ts/wordlists/lang-fr.ts +++ b/src.ts/wordlists/lang-fr.ts @@ -18,6 +18,8 @@ export class LangFr extends WordlistOwlA { * * This should be unnecessary most of the time as the exported * [[langFr]] should suffice. + * + * @_ignore: */ constructor() { super("fr", words, accents, checksum); } diff --git a/src.ts/wordlists/lang-it.ts b/src.ts/wordlists/lang-it.ts index 2d2c8a123..982e0611c 100644 --- a/src.ts/wordlists/lang-it.ts +++ b/src.ts/wordlists/lang-it.ts @@ -17,6 +17,8 @@ export class LangIt extends WordlistOwl { * * This should be unnecessary most of the time as the exported * [[langIt]] should suffice. + * + * @_ignore: */ constructor() { super("it", words, checksum); } diff --git a/src.ts/wordlists/lang-ja.ts b/src.ts/wordlists/lang-ja.ts index 59e975fad..7b1f2aaf3 100644 --- a/src.ts/wordlists/lang-ja.ts +++ b/src.ts/wordlists/lang-ja.ts @@ -145,6 +145,8 @@ export class LangJa extends Wordlist { * * This should be unnecessary most of the time as the exported * [[langJa]] should suffice. + * + * @_ignore: */ constructor() { super("ja"); } diff --git a/src.ts/wordlists/lang-ko.ts b/src.ts/wordlists/lang-ko.ts index b677bff49..097213865 100644 --- a/src.ts/wordlists/lang-ko.ts +++ b/src.ts/wordlists/lang-ko.ts @@ -75,6 +75,8 @@ export class LangKo extends Wordlist { * * This should be unnecessary most of the time as the exported * [[langKo]] should suffice. + * + * @_ignore: */ constructor() { super("ko"); diff --git a/src.ts/wordlists/lang-pt.ts b/src.ts/wordlists/lang-pt.ts index 5e880ac41..7448a01e4 100644 --- a/src.ts/wordlists/lang-pt.ts +++ b/src.ts/wordlists/lang-pt.ts @@ -17,6 +17,8 @@ export class LangPt extends WordlistOwl { * * This should be unnecessary most of the time as the exported * [[langPt]] should suffice. + * + * @_ignore: */ constructor() { super("pt", words, checksum); } diff --git a/src.ts/wordlists/lang-zh.ts b/src.ts/wordlists/lang-zh.ts index acad865a6..048115bce 100644 --- a/src.ts/wordlists/lang-zh.ts +++ b/src.ts/wordlists/lang-zh.ts @@ -75,6 +75,8 @@ export class LangZh extends Wordlist { * * This should be unnecessary most of the time as the exported * [[langZhCn]] and [[langZhTw]] should suffice. + * + * @_ignore: */ constructor(dialect: string) { super("zh_" + dialect); } @@ -97,6 +99,9 @@ export class LangZh extends Wordlist { /** * Returns a singleton instance of a ``LangZh`` for %%dialect%%, * creating it if this is the first time being called. + * + * Use the %%dialect%% ``"cn"`` or ``"tw"`` for simplified or + * traditional, respectively. */ static wordlist(dialect: string): LangZh { if (wordlists[dialect] == null) { diff --git a/src.ts/wordlists/wordlists.ts b/src.ts/wordlists/wordlists.ts index 767c6a9e7..1a3b12f18 100644 --- a/src.ts/wordlists/wordlists.ts +++ b/src.ts/wordlists/wordlists.ts @@ -11,6 +11,19 @@ import { LangZh } from "./lang-zh.js"; import type { Wordlist } from "./wordlist.js"; +/** + * The available Wordlists by their + * [ISO 639-1 Language Code](link-wiki-iso639). + * + * (**i.e.** [cz](LangCz), [en](LangEn), [es](LangEs), [fr](LangFr), + * [ja](LangJa), [ko](LangKo), [it](LangIt), [pt](LangPt), + * [zh_cn](LangZh), [zh_tw](LangZh)) + * + * The dist files (in the ``/dist`` folder) have had all languages + * except English stripped out, which reduces the library size by + * about 80kb. If required, they are available by importing the + * included ``wordlists-extra.min.js`` file. + */ export const wordlists: Record = { cz: LangCz.wordlist(), en: LangEn.wordlist(),