docs: added more jsdocs
This commit is contained in:
parent
12a13c6d56
commit
edcba76366
@ -180,6 +180,9 @@ export class Network implements Freezable<Network> {
|
||||
return gas;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new Network for the %%network%% name or chainId.
|
||||
*/
|
||||
static from(network?: Networkish): Network {
|
||||
// Default network
|
||||
if (network == null) { return Network.from("homestead"); }
|
||||
@ -226,6 +229,10 @@ export class Network implements Freezable<Network> {
|
||||
return throwArgumentError("invalid network", "network", network);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register %%nameOrChainId%% with a function which returns
|
||||
* an instance of a Network representing that chain.
|
||||
*/
|
||||
static register(nameOrChainId: string | number | bigint, networkFunc: () => Network): void {
|
||||
if (typeof(nameOrChainId) === "number") { nameOrChainId = BigInt(nameOrChainId); }
|
||||
const existing = Networks.get(nameOrChainId);
|
||||
|
@ -4,7 +4,7 @@
|
||||
// https://playground.open-rpc.org/?schemaUrl=https://raw.githubusercontent.com/ethereum/eth1.0-apis/assembled-spec/openrpc.json&uiSchema%5BappBar%5D%5Bui:splitView%5D=true&uiSchema%5BappBar%5D%5Bui:input%5D=false&uiSchema%5BappBar%5D%5Bui:examplesDropdown%5D=false
|
||||
|
||||
import { resolveAddress } from "../address/index.js";
|
||||
import { TypedDataEncoder } from "../hash/typed-data.js";
|
||||
import { TypedDataEncoder } from "../hash/index.js";
|
||||
import { accessListify } from "../transaction/index.js";
|
||||
import {
|
||||
defineProperties, getBigInt, hexlify, toQuantity, toUtf8Bytes,
|
||||
@ -26,10 +26,6 @@ import type { Provider, TransactionRequest, TransactionResponse } from "./provid
|
||||
import type { Signer } from "./signer.js";
|
||||
|
||||
|
||||
//function copy<T = any>(value: T): T {
|
||||
// return JSON.parse(JSON.stringify(value));
|
||||
//}
|
||||
|
||||
const Primitive = "bigint,boolean,function,number,string,symbol".split(/,/g);
|
||||
//const Methods = "getAddress,then".split(/,/g);
|
||||
function deepCopy<T = any>(value: T): T {
|
||||
@ -67,6 +63,9 @@ function isPollable(value: any): value is Pollable {
|
||||
return (value && typeof(value.pollingInterval) === "number");
|
||||
}
|
||||
|
||||
/**
|
||||
* A JSON-RPC payload, which are sent to a JSON-RPC server.
|
||||
*/
|
||||
export type JsonRpcPayload = {
|
||||
id: number;
|
||||
method: string;
|
||||
@ -74,11 +73,17 @@ export type JsonRpcPayload = {
|
||||
jsonrpc: "2.0";
|
||||
};
|
||||
|
||||
/**
|
||||
* A JSON-RPC result, which are returned on success from a JSON-RPC server.
|
||||
*/
|
||||
export type JsonRpcResult = {
|
||||
id: number;
|
||||
result: any;
|
||||
};
|
||||
|
||||
/**
|
||||
* A JSON-RPC error, which are returned on failure from a JSON-RPC server.
|
||||
*/
|
||||
export type JsonRpcError = {
|
||||
id: number;
|
||||
error: {
|
||||
@ -88,23 +93,60 @@ export type JsonRpcError = {
|
||||
}
|
||||
};
|
||||
|
||||
export type JsonRpcOptions = {
|
||||
// Whether to immediately fallback onto useing the polling strategy; otherwise
|
||||
// attempt to use filters first, falling back onto polling if filter returns failure
|
||||
export type DebugEventJsonRpcApiProvider = {
|
||||
action: "sendRpcPayload",
|
||||
payload: JsonRpcPayload | Array<JsonRpcPayload>
|
||||
} | {
|
||||
action: "receiveRpcResult",
|
||||
result: Array<JsonRpcResult | JsonRpcError>
|
||||
} | {
|
||||
action: "receiveRpcError",
|
||||
error: Error
|
||||
};
|
||||
|
||||
/**
|
||||
* Options for configuring a [[JsonRpcApiProvider]]. Much of this
|
||||
* is targetted towards sub-classes, which often will not expose
|
||||
* any of these options to their consumers.
|
||||
*
|
||||
* _property: options.polling? => boolean
|
||||
* If true, the polling strategy is used immediately for events.
|
||||
* Otherwise, an attempt to use filters is made and on failure
|
||||
* polling is used for that and all future events. (default: ``false``)
|
||||
*
|
||||
* _property: options.staticNetwork => [[Network]]
|
||||
* If this is set, then there are no requests made for the chainId.
|
||||
* (default: ``null``)
|
||||
*
|
||||
* _warning:
|
||||
* This should **ONLY** be used if it is **certain** that the network
|
||||
* cannot change, such as when using INFURA (since the URL dictates the
|
||||
* network). If the network is assumed static and it does change, this
|
||||
* can have tragic consequences. For example, this **CANNOT** be used
|
||||
* with MetaMask, since the used can select a new network from the
|
||||
* drop-down at any time.
|
||||
*
|
||||
* _property: option.batchStallTime? => number
|
||||
* The amount of time (in ms) to wait, allowing requests to be batched,
|
||||
* before making the request. If ``0``, then batching will only occur
|
||||
* within the same event loop. If the batchSize is ``1``, then this is
|
||||
* ignored. (default: ``10``)
|
||||
*
|
||||
* _property: options.batchMaxSize? => number
|
||||
* The target maximum size (in bytes) to allow a payload within a single
|
||||
* batch. At least one request will be made per request, which may
|
||||
* violate this constraint if it is set too small or a large request is
|
||||
* present. (default: 1Mb)
|
||||
*
|
||||
* _property: options.bstchMaxCount? => number
|
||||
* The maximum number of payloads to allow in a single batch. Set this to
|
||||
* ``1`` to disable batching entirely. (default: ``100``)
|
||||
*/
|
||||
export type JsonRpcApiProviderOptions = {
|
||||
polling?: boolean;
|
||||
|
||||
// Whether to check the network on each call; only set this to true when a backend
|
||||
// **cannot** change otherwise catastrophic errors can occur
|
||||
staticNetwork?: null | Network;
|
||||
|
||||
// How long to wait before draining the payload queue
|
||||
batchStallTime?: number;
|
||||
|
||||
// Maximum estimated size (in bytes) to allow in a batch
|
||||
batchMaxSize?: number;
|
||||
|
||||
// Maximum number of payloads to send per batch; if set to 1, non-batching requests
|
||||
// are made.
|
||||
batchMaxCount?: number;
|
||||
};
|
||||
|
||||
@ -161,26 +203,6 @@ export class JsonRpcSigner extends AbstractSigner<JsonRpcApiProvider> {
|
||||
return await this.populateCall(tx);
|
||||
}
|
||||
|
||||
//async getNetwork(): Promise<Frozen<Network>> {
|
||||
// return await this.provider.getNetwork();
|
||||
//}
|
||||
|
||||
//async estimateGas(tx: TransactionRequest): Promise<bigint> {
|
||||
// return await this.provider.estimateGas(tx);
|
||||
//}
|
||||
|
||||
//async call(tx: TransactionRequest): Promise<string> {
|
||||
// return await this.provider.call(tx);
|
||||
//}
|
||||
|
||||
//async resolveName(name: string | Addressable): Promise<null | string> {
|
||||
// return await this.provider.resolveName(name);
|
||||
//}
|
||||
|
||||
//async getNonce(blockTag?: BlockTag): Promise<number> {
|
||||
// return await this.provider.getTransactionCountOf(this.address);
|
||||
//}
|
||||
|
||||
// Returns just the hash of the transaction after sent, which is what
|
||||
// the bare JSON-RPC API does;
|
||||
async sendUncheckedTransaction(_tx: TransactionRequest): Promise<string> {
|
||||
@ -315,15 +337,21 @@ type RejectFunc = (error: Error) => void;
|
||||
|
||||
type Payload = { payload: JsonRpcPayload, resolve: ResolveFunc, reject: RejectFunc };
|
||||
|
||||
/**
|
||||
* The JsonRpcApiProvider is an abstract class and **MUST** be
|
||||
* sub-classed.
|
||||
*
|
||||
* It provides the base for all JSON-RPC-based Provider interaction.
|
||||
*/
|
||||
export class JsonRpcApiProvider extends AbstractProvider {
|
||||
|
||||
#options: Required<JsonRpcOptions>;
|
||||
#options: Required<JsonRpcApiProviderOptions>;
|
||||
|
||||
#nextId: number;
|
||||
#payloads: Array<Payload>;
|
||||
#drainTimer: null | NodeJS.Timer;
|
||||
|
||||
constructor(network?: Networkish, options?: JsonRpcOptions) {
|
||||
constructor(network?: Networkish, options?: JsonRpcApiProviderOptions) {
|
||||
super(network);
|
||||
|
||||
this.#nextId = 1;
|
||||
@ -339,26 +367,21 @@ export class JsonRpcApiProvider extends AbstractProvider {
|
||||
}
|
||||
}
|
||||
|
||||
_getOption<K extends keyof JsonRpcOptions>(key: K): JsonRpcOptions[K] {
|
||||
/**
|
||||
* Returns the value associated with the option %%key%%.
|
||||
*
|
||||
* Sub-classes can use this to inquire about configuration options.
|
||||
*/
|
||||
_getOption<K extends keyof JsonRpcApiProviderOptions>(key: K): JsonRpcApiProviderOptions[K] {
|
||||
return this.#options[key];
|
||||
}
|
||||
|
||||
// @TODO: Merge this into send
|
||||
//prepareRequest(method: string, params: Array<any>): JsonRpcPayload {
|
||||
// return {
|
||||
// method, params, id: (this.#nextId++), jsonrpc: "2.0"
|
||||
// };
|
||||
//}
|
||||
/*
|
||||
async send<T = any>(method: string, params: Array<any>): Promise<T> {
|
||||
// @TODO: This should construct and queue the payload
|
||||
throw new Error("sub-class must implement this");
|
||||
}
|
||||
*/
|
||||
|
||||
#scheduleDrain(): void {
|
||||
if (this.#drainTimer) { return; }
|
||||
|
||||
// If we aren't using batching, no hard in sending it immeidately
|
||||
const stallTime = (this._getOption("batchMaxCount") === 1) ? 0: this._getOption("batchStallTime");
|
||||
|
||||
this.#drainTimer = setTimeout(() => {
|
||||
this.#drainTimer = null;
|
||||
|
||||
@ -420,10 +443,23 @@ export class JsonRpcApiProvider extends AbstractProvider {
|
||||
}
|
||||
})();
|
||||
}
|
||||
}, this.#options.batchStallTime);
|
||||
}, stallTime);
|
||||
}
|
||||
|
||||
// Sub-classes should **NOT** override this
|
||||
/**
|
||||
* Requests the %%method%% with %%params%% via the JSON-RPC protocol
|
||||
* over the underlying channel. This can be used to call methods
|
||||
* on the backend that do not have a high-level API within the Provider
|
||||
* API.
|
||||
*
|
||||
* This method queues requests according to the batch constraints
|
||||
* in the options, assigns the request a unique ID.
|
||||
*
|
||||
* **Do NOT override** this method in sub-classes; instead
|
||||
* override [[_send]] or force the options values in the
|
||||
* call to the constructor to modify this method's behavior.
|
||||
*/
|
||||
send(method: string, params: Array<any> | Record<string, any>): Promise<any> {
|
||||
// @TODO: cache chainId?? purge on switch_networks
|
||||
|
||||
@ -441,13 +477,29 @@ export class JsonRpcApiProvider extends AbstractProvider {
|
||||
return <Promise<JsonRpcResult>>promise;
|
||||
}
|
||||
|
||||
// Sub-classes MUST override this
|
||||
/**
|
||||
* Sends a JSON-RPC %%payload%% (or a batch) to the underlying channel.
|
||||
*
|
||||
* Sub-classes **MUST** override this.
|
||||
*/
|
||||
_send(payload: JsonRpcPayload | Array<JsonRpcPayload>): Promise<Array<JsonRpcResult | JsonRpcError>> {
|
||||
return throwError("sub-classes must override _send", "UNSUPPORTED_OPERATION", {
|
||||
operation: "jsonRpcApiProvider._send"
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to the [[Signer]] account for %%address%% managed by
|
||||
* the client.
|
||||
*
|
||||
* If the %%address%% is a number, it is used as an index in the
|
||||
* the accounts from [[listAccounts]].
|
||||
*
|
||||
* This can only be used on clients which manage accounts (such as
|
||||
* Geth with imported account or MetaMask).
|
||||
*
|
||||
* Throws if the account doesn't exist.
|
||||
*/
|
||||
async getSigner(address: number | string = 0): Promise<JsonRpcSigner> {
|
||||
|
||||
const accountsPromise = this.send("eth_accounts", [ ]);
|
||||
@ -482,6 +534,12 @@ export class JsonRpcApiProvider extends AbstractProvider {
|
||||
return Network.from(getBigInt(await this._perform({ method: "chainId" })));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Subscriber that will manage the %%sub%%.
|
||||
*
|
||||
* Sub-classes can override this to modify the behavior of
|
||||
* subscription management.
|
||||
*/
|
||||
_getSubscriber(sub: Subscription): Subscriber {
|
||||
// Pending Filters aren't availble via polling
|
||||
if (sub.type === "pending") { return new FilterIdPendingSubscriber(this); }
|
||||
@ -499,7 +557,11 @@ export class JsonRpcApiProvider extends AbstractProvider {
|
||||
return super._getSubscriber(sub);
|
||||
}
|
||||
|
||||
// Normalize a JSON-RPC transaction
|
||||
/**
|
||||
* Returns %%tx%% as a normalized JSON-RPC transaction request,
|
||||
* which has all values hexlified and any numeric values converted
|
||||
* to Quantity values.
|
||||
*/
|
||||
getRpcTransaction(tx: TransactionRequest): JsonRpcTransactionRequest {
|
||||
const result: JsonRpcTransactionRequest = {};
|
||||
|
||||
@ -525,7 +587,10 @@ export class JsonRpcApiProvider extends AbstractProvider {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Get the necessary paramters for making a JSON-RPC request
|
||||
/**
|
||||
* Returns the request method and arguments required to perform
|
||||
* %%req%%.
|
||||
*/
|
||||
getRpcRequest(req: PerformActionRequest): null | { method: string, args: Array<any> } {
|
||||
switch (req.method) {
|
||||
case "chainId":
|
||||
@ -624,6 +689,10 @@ export class JsonRpcApiProvider extends AbstractProvider {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an ethers-style Error for the given JSON-RPC error
|
||||
* %%payload%%.
|
||||
*/
|
||||
getRpcError(payload: JsonRpcPayload, error: JsonRpcError): Error {
|
||||
console.log("getRpcError", payload, error);
|
||||
return new Error(`JSON-RPC badness; @TODO: ${ error }`);
|
||||
@ -686,6 +755,12 @@ export class JsonRpcApiProvider extends AbstractProvider {
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to the non-normalized value by performing %%req%%.
|
||||
*
|
||||
* Sub-classes may override this to modify behavior of actions,
|
||||
* and should generally call ``super._perform`` as a fallback.
|
||||
*/
|
||||
async _perform(req: PerformActionRequest): Promise<any> {
|
||||
// Legacy networks do not like the type field being passed along (which
|
||||
// is fair), so we delete type if it is 0 and a non-EIP-1559 network
|
||||
@ -709,33 +784,26 @@ export class JsonRpcApiProvider extends AbstractProvider {
|
||||
|
||||
if (request != null) {
|
||||
return await this.send(request.method, request.args);
|
||||
|
||||
/*
|
||||
@TODO: Add debug output to send
|
||||
this.emit("debug", { type: "sendRequest", request });
|
||||
try {
|
||||
const result =
|
||||
//console.log("RR", result);
|
||||
this.emit("debug", { type: "getResponse", result });
|
||||
return result;
|
||||
} catch (error) {
|
||||
this.emit("debug", { type: "getError", error });
|
||||
throw error;
|
||||
//throw this.getRpcError(request.method, request.args, <Error>error);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
return super._perform(req);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The JsonRpcProvider is one of the most common Providers,
|
||||
* which performs all operations over HTTP (or HTTPS) requests.
|
||||
*
|
||||
* Events are processed by polling the backend for the current block
|
||||
* number; when it advances, all block-base events are then checked
|
||||
* for updates.
|
||||
*/
|
||||
export class JsonRpcProvider extends JsonRpcApiProvider {
|
||||
#connect: FetchRequest;
|
||||
|
||||
#pollingInterval: number;
|
||||
|
||||
constructor(url?: string | FetchRequest, network?: Networkish, options?: JsonRpcOptions) {
|
||||
constructor(url?: string | FetchRequest, network?: Networkish, options?: JsonRpcApiProviderOptions) {
|
||||
if (url == null) { url = "http:/\/localhost:8545"; }
|
||||
super(network, options);
|
||||
|
||||
@ -762,6 +830,9 @@ export class JsonRpcProvider extends JsonRpcApiProvider {
|
||||
return resp;
|
||||
}
|
||||
|
||||
/**
|
||||
* The polling interval (default: 4000 ms)
|
||||
*/
|
||||
get pollingInterval(): number { return this.#pollingInterval; }
|
||||
set pollingInterval(value: number) {
|
||||
if (!Number.isInteger(value) || value < 0) { throw new Error("invalid interval"); }
|
||||
@ -774,24 +845,6 @@ export class JsonRpcProvider extends JsonRpcApiProvider {
|
||||
}
|
||||
}
|
||||
|
||||
// This class should only be used when it is not possible for the
|
||||
// underlying network to change, such as with INFURA. If you are
|
||||
// using MetaMask or some other client which allows users to change
|
||||
// their network DO NOT USE THIS. Bad things will happen.
|
||||
/*
|
||||
export class StaticJsonRpcProvider extends JsonRpcProvider {
|
||||
readonly network!: Network;
|
||||
|
||||
constructor(url: string | ConnectionInfo, network?: Network, options?: JsonRpcOptions) {
|
||||
super(url, network, options);
|
||||
defineProperties<StaticJsonRpcProvider>(this, { network });
|
||||
}
|
||||
|
||||
async _detectNetwork(): Promise<Network> {
|
||||
return this.network;
|
||||
}
|
||||
}
|
||||
*/
|
||||
/*
|
||||
function spelunkData(value: any): null | { message: string, data: string } {
|
||||
if (value == null) { return null; }
|
||||
|
@ -64,6 +64,7 @@ export interface Signer extends Addressable, ContractRunner, NameResolver {
|
||||
* - if ``from`` is specified , check that it matches this Signer
|
||||
* - populates ``nonce`` via ``signer.getNonce("pending")``
|
||||
* - populates ``gasLimit`` via ``signer.estimateGas(tx)``
|
||||
* - populates ``chainId`` via ``signer.provider.getNetwork()``
|
||||
* - populates ``type`` and relevant fee data for that type (``gasPrice``
|
||||
* for legacy transactions, ``maxFeePerGas`` for EIP-1559, etc)
|
||||
*
|
||||
@ -109,7 +110,7 @@ export interface Signer extends Addressable, ContractRunner, NameResolver {
|
||||
call(tx: CallRequest): Promise<string>;
|
||||
|
||||
/**
|
||||
* Resolves an [[Address]], ENS Name or [[Addressable]] to an [[Address]].
|
||||
* Resolves an [[Address]] or ENS Name to an [[Address]].
|
||||
*/
|
||||
resolveName(name: string): Promise<null | string>;
|
||||
|
||||
@ -118,15 +119,15 @@ export interface Signer extends Addressable, ContractRunner, NameResolver {
|
||||
// Signing
|
||||
|
||||
/**
|
||||
* Signs %%tx%%, returning the fully signed transaction. This does not populate
|
||||
* any additional properties within the transaction.
|
||||
* Signs %%tx%%, returning the fully signed transaction. This does not
|
||||
* populate any additional properties within the transaction.
|
||||
*/
|
||||
signTransaction(tx: TransactionRequest): Promise<string>;
|
||||
|
||||
/**
|
||||
* Sends %%tx%% to the Network. The ``signer.populateTransaction(tx)`` is
|
||||
* called first to ensure all necessary properties for the transaction to be
|
||||
* valid have been popualted dirst.
|
||||
* Sends %%tx%% to the Network. The ``signer.populateTransaction(tx)``
|
||||
* is called first to ensure all necessary properties for the
|
||||
* transaction to be valid have been popualted first.
|
||||
*/
|
||||
sendTransaction(tx: TransactionRequest): Promise<TransactionResponse>;
|
||||
|
||||
|
@ -1,17 +1,13 @@
|
||||
//export type TransactionReceipt {
|
||||
//}
|
||||
import { version } from "../_version.js";
|
||||
|
||||
import { defineReadOnly } from "./properties.js";
|
||||
|
||||
export type ErrorSignature = {
|
||||
r: string;
|
||||
s: string;
|
||||
yParity: 0 | 1;
|
||||
networkV: bigint;
|
||||
};
|
||||
import type {
|
||||
TransactionRequest, TransactionReceipt, TransactionResponse
|
||||
} from "../providers/index.js";
|
||||
|
||||
import type { FetchRequest, FetchResponse } from "./fetch.js";
|
||||
|
||||
export type ErrorAccessList = Array<{ address: string, storageKeys: Array<string> }>;
|
||||
|
||||
export type ErrorInfo<T> = Omit<T, "code" | "name" | "message">;
|
||||
|
||||
@ -20,61 +16,17 @@ const ErrorConstructors: Record<string, { new (...args: Array<any>): Error }> =
|
||||
ErrorConstructors.INVALID_ARGUMENT = TypeError;
|
||||
ErrorConstructors.NUMERIC_FAULT = RangeError;
|
||||
ErrorConstructors.BUFFER_OVERRUN = RangeError;
|
||||
/*
|
||||
export interface ErrorTransaction {
|
||||
type?: number;
|
||||
|
||||
to?: string;
|
||||
from?: string;
|
||||
|
||||
nonce?: number;
|
||||
|
||||
gasLimit?: bigint;
|
||||
gasPrice?: bigint;
|
||||
|
||||
maxPriorityFeePerGas?: bigint;
|
||||
maxFeePerGas?: bigint;
|
||||
|
||||
data?: string;
|
||||
value?: bigint;
|
||||
chainId?: bigint;
|
||||
|
||||
hash?: string;
|
||||
|
||||
signature?: ErrorSignature;
|
||||
|
||||
accessList?: ErrorAccessList;
|
||||
}
|
||||
*/
|
||||
|
||||
export interface ErrorFetchRequestWithBody extends ErrorFetchRequest {
|
||||
body: Readonly<Uint8Array>;
|
||||
}
|
||||
|
||||
export interface ErrorFetchRequest {
|
||||
url: string;
|
||||
method: string;
|
||||
headers: Readonly<Record<string, string>>;
|
||||
getHeader(key: string): string;
|
||||
body: null | Readonly<Uint8Array>;
|
||||
hasBody(): this is ErrorFetchRequestWithBody;
|
||||
}
|
||||
|
||||
|
||||
export interface ErrorFetchResponseWithBody extends ErrorFetchResponse {
|
||||
body: Readonly<Uint8Array>;
|
||||
}
|
||||
|
||||
export interface ErrorFetchResponse {
|
||||
statusCode: number;
|
||||
statusMessage: string;
|
||||
headers: Readonly<Record<string, string>>;
|
||||
getHeader(key: string): string;
|
||||
body: null | Readonly<Uint8Array>;
|
||||
hasBody(): this is ErrorFetchResponseWithBody;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* All errors emitted by ethers have an **ErrorCode** to help
|
||||
* identify and coalesce errors to simplfy programatic analysis.
|
||||
*
|
||||
* _property: ``"UNKNOWN_ERROR"``
|
||||
* This is a general puspose fallback when no other error makes sense
|
||||
* or the error wasn't expected
|
||||
*
|
||||
* _property: ``"NOT_IMPLEMENTED"``
|
||||
*/
|
||||
export type ErrorCode =
|
||||
|
||||
// Generic Errors
|
||||
@ -125,14 +77,14 @@ export interface NetworkError extends EthersError<"NETWORK_ERROR"> {
|
||||
}
|
||||
|
||||
export interface ServerError extends EthersError<"SERVER_ERROR"> {
|
||||
request: ErrorFetchRequest | string;
|
||||
response?: ErrorFetchResponse;
|
||||
request: FetchRequest | string;
|
||||
response?: FetchResponse;
|
||||
}
|
||||
|
||||
export interface TimeoutError extends EthersError<"TIMEOUT"> {
|
||||
operation: string;
|
||||
reason: string;
|
||||
request?: ErrorFetchRequest;
|
||||
request?: FetchRequest;
|
||||
}
|
||||
|
||||
export interface BadDataError extends EthersError<"BAD_DATA"> {
|
||||
@ -176,11 +128,6 @@ export interface UnexpectedArgumentError extends EthersError<"UNEXPECTED_ARGUMEN
|
||||
expectedCount: number;
|
||||
}
|
||||
|
||||
//export interface ValueMismatchError extends EthersError<ErrorCode.UNEXPECTED_ARGUMENT> {
|
||||
// count: number;
|
||||
// expectedCount: number;
|
||||
//}
|
||||
|
||||
|
||||
// Blockchain Errors
|
||||
|
||||
@ -209,28 +156,28 @@ export interface CallExceptionError extends EthersError<"CALL_EXCEPTION"> {
|
||||
//}
|
||||
|
||||
export interface InsufficientFundsError extends EthersError<"INSUFFICIENT_FUNDS"> {
|
||||
transaction: any;//ErrorTransaction;
|
||||
transaction: TransactionRequest;
|
||||
}
|
||||
|
||||
export interface NonceExpiredError extends EthersError<"NONCE_EXPIRED"> {
|
||||
transaction: any; //ErrorTransaction;
|
||||
transaction: TransactionRequest;
|
||||
}
|
||||
|
||||
export interface OffchainFaultError extends EthersError<"OFFCHAIN_FAULT"> {
|
||||
transaction?: any;
|
||||
transaction?: TransactionRequest;
|
||||
reason: string;
|
||||
}
|
||||
|
||||
export interface ReplacementUnderpricedError extends EthersError<"REPLACEMENT_UNDERPRICED"> {
|
||||
transaction: any; //ErrorTransaction;
|
||||
transaction: TransactionRequest;
|
||||
}
|
||||
|
||||
export interface TransactionReplacedError extends EthersError<"TRANSACTION_REPLACED"> {
|
||||
cancelled: boolean;
|
||||
reason: "repriced" | "cancelled" | "replaced";
|
||||
hash: string;
|
||||
replacement: any; //TransactionResponse;
|
||||
receipt: any; //TransactionReceipt;
|
||||
replacement: TransactionResponse;
|
||||
receipt: TransactionReceipt;
|
||||
}
|
||||
|
||||
export interface UnconfiguredNameError extends EthersError<"UNCONFIGURED_NAME"> {
|
||||
@ -238,7 +185,7 @@ export interface UnconfiguredNameError extends EthersError<"UNCONFIGURED_NAME">
|
||||
}
|
||||
|
||||
export interface UnpredictableGasLimitError extends EthersError<"UNPREDICTABLE_GAS_LIMIT"> {
|
||||
transaction: any; //ErrorTransaction;
|
||||
transaction: TransactionRequest;
|
||||
}
|
||||
|
||||
export interface ActionRejectedError extends EthersError<"ACTION_REJECTED"> {
|
||||
@ -286,10 +233,19 @@ export type CodedEthersError<T> =
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the %%error%% matches an error thrown by ethers
|
||||
* that matches the error %%code%%.
|
||||
*
|
||||
* In TypeScript envornoments, this can be used to check that %%error%%
|
||||
* matches an EthersError type, which means the expected properties will
|
||||
* be set.
|
||||
*
|
||||
* @See [ErrorCodes](api:ErrorCode)
|
||||
* @example
|
||||
* try {
|
||||
* // code....
|
||||
* } catch (e) {
|
||||
* if (isError(e, errors.CALL_EXCEPTION)) {
|
||||
* if (isError(e, "CALL_EXCEPTION")) {
|
||||
* console.log(e.data);
|
||||
* }
|
||||
* }
|
||||
@ -298,14 +254,30 @@ export function isError<K extends ErrorCode, T extends CodedEthersError<K>>(erro
|
||||
return (error && (<EthersError>error).code === code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if %%error%% is a [CALL_EXCEPTION](api:CallExceptionError).
|
||||
*/
|
||||
export function isCallException(error: any): error is CallExceptionError {
|
||||
return isError(error, "CALL_EXCEPTION");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new Error configured to the format ethers emits errors, with
|
||||
* the %%message%%, [[api:ErrorCode]] %%code%% and additioanl properties
|
||||
* for the corresponding EthersError.
|
||||
*
|
||||
* Each error in ethers includes the version of ethers, a
|
||||
* machine-readable [[ErrorCode]], and depneding on %%code%%, additional
|
||||
* required properties. The error message will also include the %%meeage%%,
|
||||
* ethers version, %%code%% and all aditional properties, serialized.
|
||||
*/
|
||||
export function makeError<K extends ErrorCode, T extends CodedEthersError<K>>(message: string, code: K, info?: ErrorInfo<T>): T {
|
||||
{
|
||||
const details: Array<string> = [];
|
||||
if (info) {
|
||||
if ("message" in info || "code" in info || "name" in info) {
|
||||
throw new Error(`value will overwrite populated values: ${ JSON.stringify(info) }`);
|
||||
}
|
||||
for (const key in info) {
|
||||
const value = <any>(info[<keyof ErrorInfo<T>>key]);
|
||||
try {
|
||||
@ -326,18 +298,30 @@ export function makeError<K extends ErrorCode, T extends CodedEthersError<K>>(me
|
||||
const create = ErrorConstructors[code] || Error;
|
||||
const error = <T>(new create(message));
|
||||
defineReadOnly(error, "code", code);
|
||||
|
||||
if (info) {
|
||||
for (const key in info) {
|
||||
defineReadOnly(error, <keyof T>key, <any>(info[<keyof ErrorInfo<T>>key]));
|
||||
}
|
||||
}
|
||||
|
||||
return <T>error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an EthersError with %%message%%, %%code%% and additional error
|
||||
* info.
|
||||
*
|
||||
* @see [[api:makeError]]
|
||||
*/
|
||||
export function throwError<K extends ErrorCode, T extends CodedEthersError<K>>(message: string, code: K, info?: ErrorInfo<T>): never {
|
||||
throw makeError(message, code, info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an [[api:ArgumentError]] with %%message%% for the parameter with
|
||||
* %%name%% and the %%value%%.
|
||||
*/
|
||||
export function throwArgumentError(message: string, name: string, value: any): never {
|
||||
return throwError(message, "INVALID_ARGUMENT", {
|
||||
argument: name,
|
||||
@ -345,11 +329,17 @@ export function throwArgumentError(message: string, name: string, value: any): n
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple helper to simply ensuring provided arguments match expected
|
||||
* constraints, throwing if not.
|
||||
*
|
||||
* In TypeScript environments, the %%check%% has been asserted true, so
|
||||
* any further code does not need additional compile-time checks.
|
||||
*/
|
||||
export function assertArgument(check: unknown, message: string, name: string, value: unknown): asserts check {
|
||||
if (!check) { throwArgumentError(message, name, value); }
|
||||
}
|
||||
|
||||
|
||||
export function assertArgumentCount(count: number, expectedCount: number, message: string = ""): void {
|
||||
if (message) { message = ": " + message; }
|
||||
|
||||
@ -389,6 +379,9 @@ const _normalizeForms = ["NFD", "NFC", "NFKD", "NFKC"].reduce((accum, form) => {
|
||||
return accum;
|
||||
}, <Array<string>>[]);
|
||||
|
||||
/**
|
||||
* Throws if the normalization %%form%% is not supported.
|
||||
*/
|
||||
export function assertNormalize(form: string): void {
|
||||
if (_normalizeForms.indexOf(form) === -1) {
|
||||
throwError("platform missing String.prototype.normalize", "UNSUPPORTED_OPERATION", {
|
||||
@ -397,6 +390,12 @@ export function assertNormalize(form: string): void {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Many classes use file-scoped values to guard the constructor,
|
||||
* making it effectively private. This facilitates that pattern
|
||||
* by ensuring the %%givenGaurd%% matches the file-scoped %%guard%%,
|
||||
* throwing if not, indicating the %%className%% if provided.
|
||||
*/
|
||||
export function assertPrivate(givenGuard: any, guard: any, className: string = ""): void {
|
||||
if (givenGuard !== guard) {
|
||||
let method = className, operation = "new";
|
||||
|
Loading…
Reference in New Issue
Block a user