From f8cd9c9eafc3839849da73b1467f8b4b5133a2fe Mon Sep 17 00:00:00 2001 From: Richard Moore Date: Sat, 28 Jan 2023 01:52:20 -0500 Subject: [PATCH] docs: added more documentation --- docs.wrm/links/projects.txt | 13 +- src.ts/_version.ts | 2 +- src.ts/providers/provider-alchemy.ts | 14 +- src.ts/providers/provider-ankr.ts | 35 ++++- src.ts/providers/provider-cloudflare.ts | 10 +- src.ts/providers/provider-etherscan-base.ts | 87 ++++++++++--- src.ts/providers/provider-etherscan.ts | 31 ++++- src.ts/providers/provider-infura.ts | 67 +++++++++- src.ts/providers/provider-quicknode.ts | 35 ++++- src.ts/transaction/address.ts | 9 ++ src.ts/utils/errors.ts | 137 ++++++++++++++++++-- src.ts/utils/events.ts | 66 +++++++++- 12 files changed, 447 insertions(+), 59 deletions(-) diff --git a/docs.wrm/links/projects.txt b/docs.wrm/links/projects.txt index 6e46ed8f9..be070bdf5 100644 --- a/docs.wrm/links/projects.txt +++ b/docs.wrm/links/projects.txt @@ -5,28 +5,29 @@ link-ens [ENS](https://ens.domains/) link-ethereum [Ethereum](https://ethereumorg) link-etherscan [Etherscan](https://etherscan.io) link-expo [Expo](https://expo.io) -link-etherscan-api [link-etherscan-api](https://etherscan.io/apis) +link-etherscan-api [Etherscan API](https://etherscan.io/apis) link-flatworm [Flatworm](https://github.com/ricmoo/flatworm) link-geth [Geth](https://geth.ethereum.org) link-infura [INFURA](https://infura.io) link-javascriptcore [JavaScriptCore](https://developer.apple.com/documentation/javascriptcore?language=objc) -link-ledger [link-ledger](https://www.ledger.com) +link-ledger [Ledger](https://www.ledger.com) link-metamask [MetaMask](https://metamask.io/) -link-otto [link-otto](https://github.com/robertkrimen/otto) +link-otto [Otto](https://github.com/robertkrimen/otto) link-parity [Parity](https://www.parity.io) link-pocket [Pocket Network](https://pokt.network) +link-quicknode [QuickNode](https://www.quicknode.com/ethers) link-react-native [React Native](https://reactnative.dev) link-semver [semver](https://semver.org) link-solidity [Solidity](https://solidity.readthedocs.io/) link-tally [Tally](https://tallyho.org) # Project-specific -link-alchemy-signup [link-alchemy-signup](https://dashboard.alchemyapi.io/signup?referral=55a35117-028e-4b7c-9e47-e275ad0acc6d) +link-alchemy-signup [Alchemy Signup](https://dashboard.alchemyapi.io/signup?referral=55a35117-028e-4b7c-9e47-e275ad0acc6d) link-ankr-public [link-ankr-public](https://www.ankr.com/protocol/public/) link-ankr-premium [link-ankr-premium](https://www.ankr.com/protocol/plan/) -link-etherscan-signup [link-etherscan-signup](https://etherscan.io/apis) +link-etherscan-signup [Etherscan Signup](https://etherscan.io/apis) link-etherscan-ratelimit [link-etherscan-ratelimit](https://info.etherscan.com/api-return-errors/) -link-infura-signup [link-infura-signup](https://infura.io/register) +link-infura-signup [INFURA Signup](https://infura.io/register) link-geth-debug [link-geth-debug](https://github.com/ethereum/go-ethereum/wiki/Management-APIs#debug) link-geth-rpc [link-geth-rpc](https://github.com/ethereum/go-ethereum/wiki/Management-APIs) link-infura-secret [link-infura-secret](https://infura.io/docs/gettingStarted/authentication) diff --git a/src.ts/_version.ts b/src.ts/_version.ts index 48967a99f..6d30975ad 100644 --- a/src.ts/_version.ts +++ b/src.ts/_version.ts @@ -1 +1 @@ -export const version: string = "6.0.0-beta-exports.14"; +export const version: string = "6.0.0-beta-exports.15"; diff --git a/src.ts/providers/provider-alchemy.ts b/src.ts/providers/provider-alchemy.ts index 5f27947de..48bc7b364 100644 --- a/src.ts/providers/provider-alchemy.ts +++ b/src.ts/providers/provider-alchemy.ts @@ -1,4 +1,8 @@ - +/** + * About Alchemy + * + * @_subsection: api/providers/thirdparty:Alchemy [providers-alchemy] + */ import { defineProperties, resolveProperties, assert, assertArgument, FetchRequest @@ -40,7 +44,13 @@ function getHost(name: string): string { } /** - * The AlchemyProvider is backed by the [[alchemyapu]] API. + * The **AlchemyProvider** connects to the [[link-alchemy]] + * JSON-RPC end-points. + * + * By default, a highly-throttled API key is used, which is + * appropriate for quick prototypes and simple scripts. To + * gain access to an increased rate-limit, it is highly + * recommended to [sign up here](link-alchemy-signup). * * @_docloc: api/providers/thirdparty */ diff --git a/src.ts/providers/provider-ankr.ts b/src.ts/providers/provider-ankr.ts index f1c10d7e8..1a604f2ef 100644 --- a/src.ts/providers/provider-ankr.ts +++ b/src.ts/providers/provider-ankr.ts @@ -1,3 +1,16 @@ +/** + * [[link-ankr]] provides a third-party service for connecting to + * various blockchains over JSON-RPC. + * + * **Supported Networks** + * + * - Ethereum Mainnet (``mainnet``) + * - Goerli Testnet (``goerli``) + * - Polygon (``matic``) + * - Arbitrum (``arbitrum``) + * + * @_subsection: api/providers/thirdparty:Ankr [providers-ankr] + */ import { defineProperties, FetchRequest, assertArgument } from "../utils/index.js"; @@ -31,13 +44,27 @@ function getHost(name: string): string { /** - * About Ankr... + * The **AnkrProvider** connects to the [[link-ankr]] + * JSON-RPC end-points. * - * @_docloc: api/providers/thirdparty + * By default, a highly-throttled API key is used, which is + * appropriate for quick prototypes and simple scripts. To + * gain access to an increased rate-limit, it is highly + * recommended to [sign up here](link-ankr-signup). */ export class AnkrProvider extends JsonRpcProvider implements CommunityResourcable { + + /** + * The API key for the Ankr connection. + */ readonly apiKey!: string; + /** + * Create a new **AnkrProvider**. + * + * By default connecting to ``mainnet`` with a highly throttled + * API key. + */ constructor(_network?: Networkish, apiKey?: null | string) { if (_network == null) { _network = "mainnet"; } const network = Network.from(_network); @@ -59,6 +86,10 @@ export class AnkrProvider extends JsonRpcProvider implements CommunityResourcabl return super._getProvider(chainId); } + /** + * Returns a prepared request for connecting to %%network%% with + * %%apiKey%%. + */ static getRequest(network: Network, apiKey?: null | string): FetchRequest { if (apiKey == null) { apiKey = defaultApiKey; } diff --git a/src.ts/providers/provider-cloudflare.ts b/src.ts/providers/provider-cloudflare.ts index c8de01dfb..7e0d87e6b 100644 --- a/src.ts/providers/provider-cloudflare.ts +++ b/src.ts/providers/provider-cloudflare.ts @@ -1,3 +1,9 @@ +/** + * About Cloudflare + * + * @_subsection: api/providers/thirdparty:Cloudflare [providers-cloudflare] + */ + import { assertArgument } from "../utils/index.js"; import { Network } from "./network.js"; @@ -6,9 +12,7 @@ import { JsonRpcProvider } from "./provider-jsonrpc.js"; import type { Networkish } from "./network.js"; /** - * Aboud Cloudflare... - * - * @_docloc: api/providers/thirdparty + * About Cloudflare... */ export class CloudflareProvider extends JsonRpcProvider { constructor(_network?: Networkish) { diff --git a/src.ts/providers/provider-etherscan-base.ts b/src.ts/providers/provider-etherscan-base.ts index e85b218ef..d7ba1b1f7 100644 --- a/src.ts/providers/provider-etherscan-base.ts +++ b/src.ts/providers/provider-etherscan-base.ts @@ -21,7 +21,9 @@ import type { TransactionRequest } from "./provider.js"; const THROTTLE = 2000; /** - * Aboud Etherscan Debug... + * When subscribing to the ``"debug"`` event on an Etherscan-based + * provider, the events receive a **DebugEventEtherscanProvider** + * payload. * * @_docloc: api/providers/thirdparty:Etherscan */ @@ -43,55 +45,82 @@ export type DebugEventEtherscanProvider = { const EtherscanPluginId = "org.ethers.plugins.Etherscan"; /** - * Aboud Cloudflare... + * A Network can include an **EtherscanPlugin** to provide + * a custom base URL. * * @_docloc: api/providers/thirdparty:Etherscan */ export class EtherscanPlugin extends NetworkPlugin { + /** + * The Etherscan API base URL. + */ readonly baseUrl!: string; - readonly communityApiKey!: string; - constructor(baseUrl: string, communityApiKey: string) { + /** + * Creates a new **EtherscanProvider** which will use + * %%baseUrl%%. + */ + constructor(baseUrl: string) { super(EtherscanPluginId); - //if (communityApiKey == null) { communityApiKey = null; } - defineProperties(this, { baseUrl, communityApiKey }); + defineProperties(this, { baseUrl }); } clone(): EtherscanPlugin { - return new EtherscanPlugin(this.baseUrl, this.communityApiKey); + return new EtherscanPlugin(this.baseUrl); } } let nextId = 1; /** - * Aboud Etherscan... + * The **EtherscanBaseProvider** is the super-class of + * [[EtherscanProvider]], which should generally be used instead. + * + * Since the **EtherscanProvider** includes additional code for + * [[Contract]] access, in //rare cases// that contracts are not + * used, this class can reduce code size. * * @_docloc: api/providers/thirdparty:Etherscan */ export class BaseEtherscanProvider extends AbstractProvider { + + /** + * The connected network. + */ readonly network!: Network; - readonly apiKey!: string; + + /** + * The API key or null if using the community provided bandwidth. + */ + readonly apiKey!: null | string; readonly #plugin: null | EtherscanPlugin; - constructor(_network?: Networkish, apiKey?: string) { + /** + * Creates a new **EtherscanBaseProvider**. + */ + constructor(_network?: Networkish, _apiKey?: string) { + const apiKey = (_apiKey != null) ? _apiKey: null; + super(); const network = Network.from(_network); this.#plugin = network.getPlugin(EtherscanPluginId); - if (apiKey == null && this.#plugin) { - apiKey = this.#plugin.communityApiKey; - } - defineProperties(this, { apiKey, network }); // Test that the network is supported by Etherscan this.getBaseUrl(); } + /** + * Returns the base URL. + * + * If an [[EtherscanPlugin]] is configured on the + * [[EtherscanBaseProvider_network]], returns the plugin's + * baseUrl. + */ getBaseUrl(): string { if (this.#plugin) { return this.#plugin.baseUrl; } @@ -121,6 +150,9 @@ export class BaseEtherscanProvider extends AbstractProvider { assertArgument(false, "unsupported network", "network", this.network); } + /** + * Returns the URL for the %%module%% and %%params%%. + */ getUrl(module: string, params: Record): string { const query = Object.keys(params).reduce((accum, key) => { const value = params[key]; @@ -133,10 +165,16 @@ export class BaseEtherscanProvider extends AbstractProvider { return `${ this.getBaseUrl() }/api?module=${ module }${ query }${ apiKey }`; } + /** + * Returns the URL for using POST requests. + */ getPostUrl(): string { return `${ this.getBaseUrl() }/api`; } + /** + * Returns the parameters for using POST requests. + */ getPostData(module: string, params: Record): Record { params.module = module; params.apikey = this.apiKey; @@ -147,6 +185,11 @@ export class BaseEtherscanProvider extends AbstractProvider { return this.network; } + /** + * Resolves to the result of calling %%module%% with %%params%%. + * + * If %%post%%, the request is made as a POST request. + */ async fetch(module: string, params: Record, post?: boolean): Promise { const id = nextId++; @@ -233,7 +276,9 @@ export class BaseEtherscanProvider extends AbstractProvider { } } - // The transaction has already been sanitized by the calls in Provider + /** + * Returns %%transaction%% normalized for the Etherscan API. + */ _getTransactionPostData(transaction: TransactionRequest): Record { const result: Record = { }; for (let key in transaction) { @@ -256,7 +301,9 @@ export class BaseEtherscanProvider extends AbstractProvider { return result; } - + /** + * Throws the normalized Etherscan error. + */ _checkError(req: PerformActionRequest, error: Error, transaction: any): never { // Pull any message out if, possible @@ -491,15 +538,17 @@ export class BaseEtherscanProvider extends AbstractProvider { return this.network; } + /** + * Resolves to the current price of ether. + * + * This returns ``0`` on any network other than ``mainnet``. + */ async getEtherPrice(): Promise { if (this.network.name !== "mainnet") { return 0.0; } return parseFloat((await this.fetch("stats", { action: "ethprice" })).ethusd); } isCommunityResource(): boolean { - const plugin = this.network.getPlugin(EtherscanPluginId); - if (plugin) { return (plugin.communityApiKey === this.apiKey); } - return (this.apiKey == null); } } diff --git a/src.ts/providers/provider-etherscan.ts b/src.ts/providers/provider-etherscan.ts index 0e03aaf32..e71d228f2 100644 --- a/src.ts/providers/provider-etherscan.ts +++ b/src.ts/providers/provider-etherscan.ts @@ -1,7 +1,21 @@ /** - * Aboud Etherscan... + * [[link-etherscan]] provides a third-party service for connecting to + * various blockchains over a combination of JSON-RPC and custom API + * endpoints. * - * @_subsection api/providers/thirdparty:Etherscan [etherscan] + * **Supported Networks** + * + * - Ethereum Mainnet (``mainnet``) + * - Goerli Testnet (``goerli``) + * - Sepolia Testnet (``sepolia``) + * - Arbitrum (``arbitrum``) + * - Arbitrum Goerli Testnet (``arbitrum-goerli``) + * - Optimism (``optimism``) + * - Optimism Goerli Testnet (``optimism-goerli``) + * - Polygon (``matic``) + * - Polygon Mumbai Testnet (``maticmum``) + * + * @_subsection api/providers/thirdparty:Etherscan [providers-etherscan] */ import { BaseEtherscanProvider } from "./provider-etherscan-base.js"; @@ -12,9 +26,20 @@ function isPromise(value: any): value is Promise { } /** - * Aboud EtherscanProvider... + * The **EtherscanProvider** connects to the [[link-etherscan]] + * JSON-RPC end-points. + * + * By default, requests are highly-throttled, which is + * appropriate for quick prototypes and simple scripts. To + * gain access to an increased rate-limit, it is highly + * recommended to [sign up here](link-etherscan-signup). */ export class EtherscanProvider extends BaseEtherscanProvider { + + /** + * Resolves to a [Contract]] for %%address%%, using the + * Etherscan API to retreive the Contract ABI. + */ async getContract(_address: string): Promise { let address = this._getAddress(_address); if (isPromise(address)) { address = await address; } diff --git a/src.ts/providers/provider-infura.ts b/src.ts/providers/provider-infura.ts index beba2da2e..4205c1150 100644 --- a/src.ts/providers/provider-infura.ts +++ b/src.ts/providers/provider-infura.ts @@ -1,7 +1,20 @@ /** - * About INFURA + * [[link-infura]] provides a third-party service for connecting to + * various blockchains over JSON-RPC. * - * @_subsection: api/providers/thirdparty:INFURA [infura] + * **Supported Networks** + * + * - Ethereum Mainnet (``mainnet``) + * - Goerli Testnet (``goerli``) + * - Sepolia Testnet (``sepolia``) + * - Arbitrum (``arbitrum``) + * - Arbitrum Goerli Testnet (``arbitrum-goerli``) + * - Optimism (``optimism``) + * - Optimism Goerli Testnet (``optimism-goerli``) + * - Polygon (``matic``) + * - Polygon Mumbai Testnet (``maticmum``) + * + * @_subsection: api/providers/thirdparty:INFURA [providers-infura] */ import { defineProperties, FetchRequest, assert, assertArgument @@ -46,12 +59,32 @@ function getHost(name: string): string { } /** - * INFURA... + * The **InfuraWebSocketProvider** connects to the [[link-infura]] + * WebSocket end-points. + * + * By default, a highly-throttled API key is used, which is + * appropriate for quick prototypes and simple scripts. To + * gain access to an increased rate-limit, it is highly + * recommended to [sign up here](link-infura-signup). */ export class InfuraWebSocketProvider extends WebSocketProvider implements CommunityResourcable { + + /** + * The Project ID for the INFURA connection. + */ readonly projectId!: string; + + /** + * The Project Secret. + * + * If null, no authenticated requests are made. This should not + * be used outside of private contexts. + */ readonly projectSecret!: null | string; + /** + * Creates a new **InfuraWebSocketProvider**. + */ constructor(network?: Networkish, projectId?: string) { const provider = new InfuraProvider(network, projectId); @@ -74,12 +107,31 @@ export class InfuraWebSocketProvider extends WebSocketProvider implements Commun } /** - * Aboud Cloudflare... + * The **InfuraProvider** connects to the [[link-infura]] + * JSON-RPC end-points. + * + * By default, a highly-throttled API key is used, which is + * appropriate for quick prototypes and simple scripts. To + * gain access to an increased rate-limit, it is highly + * recommended to [sign up here](link-infura-signup). */ export class InfuraProvider extends JsonRpcProvider implements CommunityResourcable { + /** + * The Project ID for the INFURA connection. + */ readonly projectId!: string; + + /** + * The Project Secret. + * + * If null, no authenticated requests are made. This should not + * be used outside of private contexts. + */ readonly projectSecret!: null | string; + /** + * Creates a new **InfuraProvider**. + */ constructor(_network?: Networkish, projectId?: null | string, projectSecret?: null | string) { if (_network == null) { _network = "mainnet"; } const network = Network.from(_network); @@ -103,10 +155,17 @@ export class InfuraProvider extends JsonRpcProvider implements CommunityResourca return (this.projectId === defaultProjectId); } + /** + * Creates a new **InfuraWebSocketProvider**. + */ static getWebSocketProvider(network?: Networkish, projectId?: string): InfuraWebSocketProvider { return new InfuraWebSocketProvider(network, projectId); } + /** + * Returns a prepared request for connecting to %%network%% + * with %%projectId%% and %%projectSecret%%. + */ static getRequest(network: Network, projectId?: null | string, projectSecret?: null | string): FetchRequest { if (projectId == null) { projectId = defaultProjectId; } if (projectSecret == null) { projectSecret = null; } diff --git a/src.ts/providers/provider-quicknode.ts b/src.ts/providers/provider-quicknode.ts index d28e4fb56..87e7b9fee 100644 --- a/src.ts/providers/provider-quicknode.ts +++ b/src.ts/providers/provider-quicknode.ts @@ -1,8 +1,21 @@ /** - * About Quicknode + * [[link-quicknode]] provides a third-party service for connecting to + * various blockchains over JSON-RPC. * - * @_subsection: api/providers/thirdparty:QuickNode [backend-quicknode] + * **Supported Networks** + * + * - Ethereum Mainnet (``mainnet``) + * - Goerli Testnet (``goerli``) + * - Arbitrum (``arbitrum``) + * - Arbitrum Goerli Testnet (``arbitrum-goerli``) + * - Optimism (``optimism``) + * - Optimism Goerli Testnet (``optimism-goerli``) + * - Polygon (``matic``) + * - Polygon Mumbai Testnet (``maticmum``) + * + * @_subsection: api/providers/thirdparty:QuickNode [providers-quicknode] */ + import { defineProperties, FetchRequest, assertArgument } from "../utils/index.js"; @@ -46,11 +59,23 @@ function getHost(name: string): string { /** - * About QuickNode + * The **QuickNodeProvider** connects to the [[link-quicknode]] + * JSON-RPC end-points. + * + * By default, a highly-throttled API token is used, which is + * appropriate for quick prototypes and simple scripts. To + * gain access to an increased rate-limit, it is highly + * recommended to [sign up here](link-quicknode). */ export class QuickNodeProvider extends JsonRpcProvider implements CommunityResourcable { + /** + * The API token. + */ readonly token!: string; + /** + * Creates a new **QuickNodeProvider**. + */ constructor(_network?: Networkish, token?: null | string) { if (_network == null) { _network = "mainnet"; } const network = Network.from(_network); @@ -73,6 +98,10 @@ export class QuickNodeProvider extends JsonRpcProvider implements CommunityResou return (this.token === defaultToken); } + /** + * Returns a new request prepared for %%network%% and the + * %%token%%. + */ static getRequest(network: Network, token?: null | string): FetchRequest { if (token == null) { token = defaultToken; } diff --git a/src.ts/transaction/address.ts b/src.ts/transaction/address.ts index f159dd156..a5cf92bf9 100644 --- a/src.ts/transaction/address.ts +++ b/src.ts/transaction/address.ts @@ -4,6 +4,11 @@ import { keccak256, SigningKey } from "../crypto/index.js"; import type { SignatureLike } from "../crypto/index.js"; import type { BytesLike } from "../utils/index.js"; +/** + * Returns the address for the %%key%%. + * + * The key may be any standard form of public key or a private key. + */ export function computeAddress(key: string | SigningKey): string { let pubkey: string; if (typeof(key) === "string") { @@ -14,6 +19,10 @@ export function computeAddress(key: string | SigningKey): string { return getAddress(keccak256("0x" + pubkey.substring(4)).substring(26)); } +/** + * Returns the recovered address for the private key that was + * used to sign %%digest%% that resulted in %%signature%%. + */ export function recoverAddress(digest: BytesLike, signature: SignatureLike): string { return computeAddress(SigningKey.recoverPublicKey(digest, signature)); } diff --git a/src.ts/utils/errors.ts b/src.ts/utils/errors.ts index 2bf010c2a..6cd53e830 100644 --- a/src.ts/utils/errors.ts +++ b/src.ts/utils/errors.ts @@ -14,7 +14,6 @@ import type { import type { FetchRequest, FetchResponse } from "./fetch.js"; - export type ErrorInfo = Omit; @@ -91,10 +90,26 @@ export type ErrorCode = "ACTION_REJECTED" ; +/** + * All errors in Ethers include properties to assist in + * machine-readable errors. + */ export interface EthersError extends Error { + /** + * The string error code. + */ code: ErrorCode; -// recover?: (...args: Array) => any; + + /** + * Additional info regarding the error that may be useful. + * + * This is generally helpful mostly for human-based debugging. + */ info?: Record; + + /** + * Any related error. + */ error?: Error; } @@ -271,45 +286,89 @@ export interface InvalidArgumentError extends EthersError<"INVALID_ARGUMENT"> { info?: Record } +/** + * This Error indicates there were too few arguments were provided. + */ export interface MissingArgumentError extends EthersError<"MISSING_ARGUMENT"> { + /** + * The number of arguments received. + */ count: number; + + /** + * The number of arguments expected. + */ expectedCount: number; } +/** + * This Error indicates too many arguments were provided. + */ export interface UnexpectedArgumentError extends EthersError<"UNEXPECTED_ARGUMENT"> { + /** + * The number of arguments received. + */ count: number; + + /** + * The number of arguments expected. + */ expectedCount: number; } // Blockchain Errors + +/** + * The action that resulted in the error. + */ export type CallExceptionAction = "call" | "estimateGas" | "getTransactionResult" | "unknown"; + +/** + * The related transaction that caused the error. + */ export type CallExceptionTransaction = { to: null | string; from?: string; data: string; }; + +/** + * This **Error** indicates a transaction reverted. + */ export interface CallExceptionError extends EthersError<"CALL_EXCEPTION"> { - // What was being performed when the call exception occurred + /** + * The action being performed when the revert was encountered. + */ action: CallExceptionAction; - // The revert data + /** + * The revert data returned. + */ data: null | string; - // If possible, a human-readable representation of data + /** + * A human-readable representation of data, if possible. + */ reason: null | string; - // The transaction that triggered the exception + /** + * The transaction that triggered the exception. + */ transaction: CallExceptionTransaction, - // If avaiable, the contract invocation details + /** + * The contract invocation details, if available. + */ invocation: null | { method: string; signature: string; args: Array; } - // The built-in or custom revert error if available + /** + * The built-in or custom revert error, if available + */ revert: null | { signature: string; name: string; @@ -317,34 +376,84 @@ export interface CallExceptionError extends EthersError<"CALL_EXCEPTION"> { } } -//export interface ContractCallExceptionError extends CallExceptionError { - // The transaction call -// transaction: any;//ErrorTransaction; -//} - - +/** + * The sending account has insufficient funds to cover the + * entire transaction cost. + */ export interface InsufficientFundsError extends EthersError<"INSUFFICIENT_FUNDS"> { + /** + * The transaction. + */ transaction: TransactionRequest; } +/** + * The sending account has already used this nonce in a + * transaction that has been included. + */ export interface NonceExpiredError extends EthersError<"NONCE_EXPIRED"> { + /** + * The transaction. + */ transaction: TransactionRequest; } +/** + * A CCIP-read exception, which cannot be recovered from or + * be further processed. + */ export interface OffchainFaultError extends EthersError<"OFFCHAIN_FAULT"> { + /** + * The transaction. + */ transaction?: TransactionRequest; + + /** + * The reason the CCIP-read failed. + */ reason: string; } +/** + * An attempt was made to replace a transaction, but with an + * insufficient additional fee to afford evicting the old + * transaction from the memory pool. + */ export interface ReplacementUnderpricedError extends EthersError<"REPLACEMENT_UNDERPRICED"> { + /** + * The transaction. + */ transaction: TransactionRequest; } +/** + * A pending transaction was replaced by another. + */ export interface TransactionReplacedError extends EthersError<"TRANSACTION_REPLACED"> { + /** + * If the transaction was cancelled, such that the original + * effects of the transaction cannot be assured. + */ cancelled: boolean; + + /** + * The reason the transaction was replaced. + */ reason: "repriced" | "cancelled" | "replaced"; + + /** + * The hash of the replaced transaction. + */ hash: string; + + /** + * The transaction that replaced the transaction. + */ replacement: TransactionResponse; + + /** + * The receipt of the transaction that replace the transaction. + */ receipt: TransactionReceipt; } diff --git a/src.ts/utils/events.ts b/src.ts/utils/events.ts index a68289824..ac8fb7aed 100644 --- a/src.ts/utils/events.ts +++ b/src.ts/utils/events.ts @@ -5,35 +5,97 @@ */ import { defineProperties } from "./properties.js"; +/** + * A callback function called when a an event is triggered. + */ export type Listener = (...args: Array) => void; +/** + * An **EventEmitterable** behaves similar to an EventEmitter + * except provides async access to its methods. + * + * An EventEmitter implements the observer pattern. + */ export interface EventEmitterable { + /** + * Registers a %%listener%% that is called whenever the + * %%event%% occurs until unregistered. + */ on(event: T, listener: Listener): Promise; + + /** + * Registers a %%listener%% that is called the next time + * %%event%% occurs. + */ once(event: T, listener: Listener): Promise; + + /** + * Triggers each listener for %%event%% with the %%args%%. + */ emit(event: T, ...args: Array): Promise; + + /** + * Resolves to the number of listeners for %%event%%. + */ listenerCount(event?: T): Promise; + + /** + * Resolves to the listeners for %%event%%. + */ listeners(event?: T): Promise>; + + /** + * Unregister the %%listener%% for %%event%%. If %%listener%% + * is unspecified, all listeners are unregistered. + */ off(event: T, listener?: Listener): Promise; + + /** + * Unregister all listeners for %%event%%. + */ removeAllListeners(event?: T): Promise; - // Alias for "on" + /** + * Alias for [[on]]. + */ addListener(event: T, listener: Listener): Promise; - // Alias for "off" + /** + * Alias for [[off]]. + */ removeListener(event: T, listener: Listener): Promise; } +/** + * When an [[EventEmitterable]] triggers a [[Listener]], the + * callback always ahas one additional argument passed, which is + * an **EventPayload**. + */ export class EventPayload { + /** + * The event filter. + */ readonly filter!: T; + /** + * The **EventEmitterable**. + */ readonly emitter!: EventEmitterable; + readonly #listener: null | Listener; + /** + * Create a new **EventPayload** for %%emitter%% with + * the %%listener%% and for %%filter%%. + */ constructor(emitter: EventEmitterable, listener: null | Listener, filter: T) { this.#listener = listener; defineProperties>(this, { emitter, filter }); } + /** + * Unregister the triggered listener for future events. + */ async removeListener(): Promise { if (this.#listener == null) { return; } await this.emitter.off(this.filter, this.#listener);