2022-11-28 05:50:34 +03:00
|
|
|
/**
|
|
|
|
* About Errors.
|
|
|
|
*
|
2022-12-03 05:23:13 +03:00
|
|
|
* @_section: api/utils/errors:Errors [about-errors]
|
2022-11-28 05:50:34 +03:00
|
|
|
*/
|
|
|
|
|
2022-09-09 06:21:08 +03:00
|
|
|
import { version } from "../_version.js";
|
|
|
|
|
2022-11-28 05:50:34 +03:00
|
|
|
import { defineProperties } from "./properties.js";
|
2022-09-05 23:14:43 +03:00
|
|
|
|
2022-09-16 05:30:27 +03:00
|
|
|
import type {
|
|
|
|
TransactionRequest, TransactionReceipt, TransactionResponse
|
|
|
|
} from "../providers/index.js";
|
|
|
|
|
|
|
|
import type { FetchRequest, FetchResponse } from "./fetch.js";
|
2022-09-05 23:14:43 +03:00
|
|
|
|
|
|
|
|
2022-09-09 06:21:08 +03:00
|
|
|
export type ErrorInfo<T> = Omit<T, "code" | "name" | "message">;
|
|
|
|
|
2022-11-28 05:50:34 +03:00
|
|
|
|
|
|
|
function stringify(value: any): any {
|
|
|
|
if (value == null) { return "null"; }
|
|
|
|
|
|
|
|
if (Array.isArray(value)) {
|
|
|
|
return "[ " + (value.map(stringify)).join(", ") + " ]";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (value instanceof Uint8Array) {
|
|
|
|
const HEX = "0123456789abcdef";
|
|
|
|
let result = "0x";
|
|
|
|
for (let i = 0; i < value.length; i++) {
|
|
|
|
result += HEX[value[i] >> 4];
|
|
|
|
result += HEX[value[i] & 0xf];
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (typeof(value) === "object" && typeof(value.toJSON) === "function") {
|
|
|
|
return stringify(value.toJSON());
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (typeof(value)) {
|
|
|
|
case "boolean": case "symbol":
|
|
|
|
return value.toString();
|
|
|
|
case "bigint":
|
|
|
|
return BigInt(value).toString();
|
|
|
|
case "number":
|
|
|
|
return (value).toString();
|
|
|
|
case "string":
|
|
|
|
return JSON.stringify(value);
|
|
|
|
case "object": {
|
|
|
|
const keys = Object.keys(value);
|
|
|
|
keys.sort();
|
|
|
|
return "{ " + keys.map((k) => `${ stringify(k) }: ${ stringify(value[k]) }`).join(", ") + " }";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return `[ COULD NOT SERIALIZE ]`;
|
|
|
|
}
|
2022-09-05 23:14:43 +03:00
|
|
|
|
2022-09-16 05:30:27 +03:00
|
|
|
/**
|
|
|
|
* 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"``
|
|
|
|
*/
|
2022-09-05 23:14:43 +03:00
|
|
|
export type ErrorCode =
|
|
|
|
|
|
|
|
// Generic Errors
|
|
|
|
"UNKNOWN_ERROR" | "NOT_IMPLEMENTED" | "UNSUPPORTED_OPERATION" |
|
|
|
|
"NETWORK_ERROR" | "SERVER_ERROR" | "TIMEOUT" | "BAD_DATA" |
|
|
|
|
"CANCELLED" |
|
|
|
|
|
|
|
|
// Operational Errors
|
|
|
|
"BUFFER_OVERRUN" | "NUMERIC_FAULT" |
|
|
|
|
|
|
|
|
// Argument Errors
|
|
|
|
"INVALID_ARGUMENT" | "MISSING_ARGUMENT" | "UNEXPECTED_ARGUMENT" |
|
|
|
|
"VALUE_MISMATCH" |
|
|
|
|
|
|
|
|
// Blockchain Errors
|
|
|
|
"CALL_EXCEPTION" | "INSUFFICIENT_FUNDS" | "NONCE_EXPIRED" |
|
|
|
|
"REPLACEMENT_UNDERPRICED" | "TRANSACTION_REPLACED" |
|
|
|
|
"UNCONFIGURED_NAME" | "OFFCHAIN_FAULT" |
|
|
|
|
|
|
|
|
// User Interaction
|
|
|
|
"ACTION_REJECTED"
|
|
|
|
;
|
|
|
|
|
|
|
|
export interface EthersError<T extends ErrorCode = ErrorCode> extends Error {
|
|
|
|
code: ErrorCode;
|
|
|
|
// recover?: (...args: Array<any>) => any;
|
|
|
|
info?: Record<string, any>;
|
|
|
|
error?: Error;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generic Errors
|
|
|
|
|
2022-11-28 05:50:34 +03:00
|
|
|
/**
|
|
|
|
* This Error is a catch-all for when there is no way for Ethers to
|
|
|
|
* know what the underlying problem is.
|
|
|
|
*/
|
2022-09-05 23:14:43 +03:00
|
|
|
export interface UnknownError extends EthersError<"UNKNOWN_ERROR"> {
|
|
|
|
[ key: string ]: any;
|
|
|
|
}
|
|
|
|
|
2022-11-28 05:50:34 +03:00
|
|
|
/**
|
|
|
|
* This Error is mostly used as a stub for functionality that is
|
|
|
|
* intended for the future, but is currently not implemented.
|
|
|
|
*/
|
2022-09-05 23:14:43 +03:00
|
|
|
export interface NotImplementedError extends EthersError<"NOT_IMPLEMENTED"> {
|
2022-11-28 05:50:34 +03:00
|
|
|
/**
|
|
|
|
* The attempted operation.
|
|
|
|
*/
|
2022-09-05 23:14:43 +03:00
|
|
|
operation: string;
|
|
|
|
}
|
|
|
|
|
2022-11-28 05:50:34 +03:00
|
|
|
/**
|
|
|
|
* This Error indicates that the attempted operation is not supported.
|
|
|
|
*
|
|
|
|
* This could range from a specifc JSON-RPC end-point not supporting
|
|
|
|
* a feature to a specific configuration of an object prohibiting the
|
|
|
|
* operation.
|
|
|
|
*
|
|
|
|
* For example, a [[Wallet]] with no connected [[Provider]] is unable
|
|
|
|
* to send a transaction.
|
|
|
|
*/
|
2022-09-05 23:14:43 +03:00
|
|
|
export interface UnsupportedOperationError extends EthersError<"UNSUPPORTED_OPERATION"> {
|
2022-11-28 05:50:34 +03:00
|
|
|
/**
|
|
|
|
* The attempted operation.
|
|
|
|
*/
|
2022-09-05 23:14:43 +03:00
|
|
|
operation: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
export interface NetworkError extends EthersError<"NETWORK_ERROR"> {
|
|
|
|
event: string;
|
|
|
|
}
|
|
|
|
|
2022-11-28 05:50:34 +03:00
|
|
|
/**
|
|
|
|
* This Error indicates there was a problem fetching a resource from
|
|
|
|
* a server.
|
|
|
|
*/
|
2022-09-05 23:14:43 +03:00
|
|
|
export interface ServerError extends EthersError<"SERVER_ERROR"> {
|
2022-11-28 05:50:34 +03:00
|
|
|
/**
|
|
|
|
* The requested resource.
|
|
|
|
*/
|
2022-09-16 05:30:27 +03:00
|
|
|
request: FetchRequest | string;
|
2022-11-28 05:50:34 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The response received from the server, if available.
|
|
|
|
*/
|
2022-09-16 05:30:27 +03:00
|
|
|
response?: FetchResponse;
|
2022-09-05 23:14:43 +03:00
|
|
|
}
|
|
|
|
|
2022-11-28 05:50:34 +03:00
|
|
|
/**
|
|
|
|
* This Error indicates that the timeout duration has expired and
|
|
|
|
* that the operation has been implicitly cancelled.
|
|
|
|
*
|
|
|
|
* The side-effect of the operation may still occur, as this
|
|
|
|
* generally means a request has been sent and there has simply
|
|
|
|
* been no response to indicate whether it was processed or not.
|
|
|
|
*/
|
2022-09-05 23:14:43 +03:00
|
|
|
export interface TimeoutError extends EthersError<"TIMEOUT"> {
|
2022-11-28 05:50:34 +03:00
|
|
|
/**
|
|
|
|
* The attempted operation.
|
|
|
|
*/
|
2022-09-05 23:14:43 +03:00
|
|
|
operation: string;
|
2022-11-28 05:50:34 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The reason.
|
|
|
|
*/
|
2022-09-05 23:14:43 +03:00
|
|
|
reason: string;
|
2022-11-28 05:50:34 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The resource request, if available.
|
|
|
|
*/
|
2022-09-16 05:30:27 +03:00
|
|
|
request?: FetchRequest;
|
2022-09-05 23:14:43 +03:00
|
|
|
}
|
|
|
|
|
2022-11-28 05:50:34 +03:00
|
|
|
/**
|
|
|
|
* This Error indicates that a provided set of data cannot
|
|
|
|
* be correctly interpretted.
|
|
|
|
*/
|
2022-09-05 23:14:43 +03:00
|
|
|
export interface BadDataError extends EthersError<"BAD_DATA"> {
|
2022-11-28 05:50:34 +03:00
|
|
|
/**
|
|
|
|
* The data.
|
|
|
|
*/
|
2022-09-05 23:14:43 +03:00
|
|
|
value: any;
|
|
|
|
}
|
|
|
|
|
2022-11-28 05:50:34 +03:00
|
|
|
/**
|
|
|
|
* This Error indicates that the operation was cancelled by a
|
|
|
|
* programmatic call, for example to ``cancel()``.
|
|
|
|
*/
|
2022-09-05 23:14:43 +03:00
|
|
|
export interface CancelledError extends EthersError<"CANCELLED"> {
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Operational Errors
|
|
|
|
|
2022-11-28 05:50:34 +03:00
|
|
|
/**
|
|
|
|
* This Error indicates an attempt was made to read outside the bounds
|
|
|
|
* of protected data.
|
|
|
|
*
|
|
|
|
* Most operations in Ethers are protected by bounds checks, to mitigate
|
|
|
|
* exploits when parsing data.
|
|
|
|
*/
|
2022-09-05 23:14:43 +03:00
|
|
|
export interface BufferOverrunError extends EthersError<"BUFFER_OVERRUN"> {
|
2022-11-28 05:50:34 +03:00
|
|
|
/**
|
|
|
|
* The buffer that was overrun.
|
|
|
|
*/
|
2022-09-05 23:14:43 +03:00
|
|
|
buffer: Uint8Array;
|
2022-11-28 05:50:34 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The length of the buffer.
|
|
|
|
*/
|
2022-09-05 23:14:43 +03:00
|
|
|
length: number;
|
2022-11-28 05:50:34 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The offset that was requested.
|
|
|
|
*/
|
2022-09-05 23:14:43 +03:00
|
|
|
offset: number;
|
|
|
|
}
|
|
|
|
|
2022-11-28 05:50:34 +03:00
|
|
|
/**
|
|
|
|
* This Error indicates an operation which would result in incorrect
|
|
|
|
* arithmetic output has occurred.
|
|
|
|
*
|
|
|
|
* For example, trying to divide by zero or using a ``uint8`` to store
|
|
|
|
* a negative value.
|
|
|
|
*/
|
2022-09-05 23:14:43 +03:00
|
|
|
export interface NumericFaultError extends EthersError<"NUMERIC_FAULT"> {
|
2022-11-28 05:50:34 +03:00
|
|
|
/**
|
|
|
|
* The attempted operation.
|
|
|
|
*/
|
2022-09-05 23:14:43 +03:00
|
|
|
operation: string;
|
2022-11-28 05:50:34 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The fault reported.
|
|
|
|
*/
|
2022-09-05 23:14:43 +03:00
|
|
|
fault: string;
|
2022-11-28 05:50:34 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The value the operation was attempted against.
|
|
|
|
*/
|
2022-09-05 23:14:43 +03:00
|
|
|
value: any;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Argument Errors
|
|
|
|
|
2022-11-28 05:50:34 +03:00
|
|
|
/**
|
|
|
|
* This Error indicates an incorrect type or value was passed to
|
|
|
|
* a function or method.
|
|
|
|
*/
|
2022-09-05 23:14:43 +03:00
|
|
|
export interface InvalidArgumentError extends EthersError<"INVALID_ARGUMENT"> {
|
2022-11-28 05:50:34 +03:00
|
|
|
/**
|
|
|
|
* The name of the argument.
|
|
|
|
*/
|
2022-09-05 23:14:43 +03:00
|
|
|
argument: string;
|
2022-11-28 05:50:34 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The value that was provided.
|
|
|
|
*/
|
2022-09-05 23:14:43 +03:00
|
|
|
value: any;
|
2022-11-28 05:50:34 +03:00
|
|
|
|
2022-09-05 23:14:43 +03:00
|
|
|
info?: Record<string, any>
|
|
|
|
}
|
|
|
|
|
|
|
|
export interface MissingArgumentError extends EthersError<"MISSING_ARGUMENT"> {
|
|
|
|
count: number;
|
|
|
|
expectedCount: number;
|
|
|
|
}
|
|
|
|
|
|
|
|
export interface UnexpectedArgumentError extends EthersError<"UNEXPECTED_ARGUMENT"> {
|
|
|
|
count: number;
|
|
|
|
expectedCount: number;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Blockchain Errors
|
2022-10-20 11:49:40 +03:00
|
|
|
export type CallExceptionAction = "call" | "estimateGas" | "getTransactionResult" | "unknown";
|
|
|
|
export type CallExceptionTransaction = {
|
|
|
|
to: null | string;
|
|
|
|
from?: string;
|
|
|
|
data: string;
|
|
|
|
};
|
2022-09-05 23:14:43 +03:00
|
|
|
export interface CallExceptionError extends EthersError<"CALL_EXCEPTION"> {
|
2022-10-20 11:49:40 +03:00
|
|
|
// What was being performed when the call exception occurred
|
|
|
|
action: CallExceptionAction;
|
|
|
|
|
2022-09-05 23:14:43 +03:00
|
|
|
// The revert data
|
2022-10-20 11:49:40 +03:00
|
|
|
data: null | string;
|
|
|
|
|
|
|
|
// If possible, a human-readable representation of data
|
|
|
|
reason: null | string;
|
2022-09-05 23:14:43 +03:00
|
|
|
|
|
|
|
// The transaction that triggered the exception
|
2022-10-20 11:49:40 +03:00
|
|
|
transaction: CallExceptionTransaction,
|
|
|
|
|
|
|
|
// If avaiable, the contract invocation details
|
|
|
|
invocation: null | {
|
|
|
|
method: string;
|
|
|
|
signature: string;
|
|
|
|
args: Array<any>;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The built-in or custom revert error if available
|
|
|
|
revert: null | {
|
|
|
|
signature: string;
|
|
|
|
name: string;
|
|
|
|
args: Array<any>;
|
|
|
|
}
|
2022-09-05 23:14:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
//export interface ContractCallExceptionError extends CallExceptionError {
|
|
|
|
// The transaction call
|
|
|
|
// transaction: any;//ErrorTransaction;
|
|
|
|
//}
|
|
|
|
|
2022-11-28 05:50:34 +03:00
|
|
|
|
2022-09-05 23:14:43 +03:00
|
|
|
export interface InsufficientFundsError extends EthersError<"INSUFFICIENT_FUNDS"> {
|
2022-09-16 05:30:27 +03:00
|
|
|
transaction: TransactionRequest;
|
2022-09-05 23:14:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
export interface NonceExpiredError extends EthersError<"NONCE_EXPIRED"> {
|
2022-09-16 05:30:27 +03:00
|
|
|
transaction: TransactionRequest;
|
2022-09-05 23:14:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
export interface OffchainFaultError extends EthersError<"OFFCHAIN_FAULT"> {
|
2022-09-16 05:30:27 +03:00
|
|
|
transaction?: TransactionRequest;
|
2022-09-05 23:14:43 +03:00
|
|
|
reason: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
export interface ReplacementUnderpricedError extends EthersError<"REPLACEMENT_UNDERPRICED"> {
|
2022-09-16 05:30:27 +03:00
|
|
|
transaction: TransactionRequest;
|
2022-09-05 23:14:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
export interface TransactionReplacedError extends EthersError<"TRANSACTION_REPLACED"> {
|
|
|
|
cancelled: boolean;
|
|
|
|
reason: "repriced" | "cancelled" | "replaced";
|
|
|
|
hash: string;
|
2022-09-16 05:30:27 +03:00
|
|
|
replacement: TransactionResponse;
|
|
|
|
receipt: TransactionReceipt;
|
2022-09-05 23:14:43 +03:00
|
|
|
}
|
|
|
|
|
2022-11-28 05:50:34 +03:00
|
|
|
/**
|
|
|
|
* This Error indicates an ENS name was used, but the name has not
|
|
|
|
* been configured.
|
|
|
|
*
|
|
|
|
* This could indicate an ENS name is unowned or that the current
|
|
|
|
* address being pointed to is the [[Zero]].
|
|
|
|
*/
|
2022-09-05 23:14:43 +03:00
|
|
|
export interface UnconfiguredNameError extends EthersError<"UNCONFIGURED_NAME"> {
|
2022-11-28 05:50:34 +03:00
|
|
|
/**
|
|
|
|
* The ENS name that was requested
|
|
|
|
*/
|
2022-09-05 23:14:43 +03:00
|
|
|
value: string;
|
|
|
|
}
|
|
|
|
|
2022-11-28 05:50:34 +03:00
|
|
|
/**
|
|
|
|
* This Error indicates a request was rejected by the user.
|
|
|
|
*
|
|
|
|
* In most clients (such as MetaMask), when an operation requires user
|
|
|
|
* authorization (such as ``signer.sendTransaction``), the client
|
|
|
|
* presents a dialog box to the user. If the user denies the request
|
|
|
|
* this error is thrown.
|
|
|
|
*/
|
2022-09-05 23:14:43 +03:00
|
|
|
export interface ActionRejectedError extends EthersError<"ACTION_REJECTED"> {
|
2022-11-28 05:50:34 +03:00
|
|
|
/**
|
|
|
|
* The requested action.
|
|
|
|
*/
|
2022-10-20 11:49:40 +03:00
|
|
|
action: "requestAccess" | "sendTransaction" | "signMessage" | "signTransaction" | "signTypedData" | "unknown",
|
2022-11-28 05:50:34 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The reason the action was rejected.
|
|
|
|
*
|
|
|
|
* If there is already a pending request, some clients may indicate
|
|
|
|
* there is already a ``"pending"`` action. This prevents an app
|
|
|
|
* from spamming the user.
|
|
|
|
*/
|
2022-10-20 11:49:40 +03:00
|
|
|
reason: "expired" | "rejected" | "pending"
|
2022-09-05 23:14:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Coding; converts an ErrorCode its Typed Error
|
|
|
|
|
2022-09-09 06:21:08 +03:00
|
|
|
/**
|
|
|
|
* A conditional type that transforms the [[ErrorCode]] T into
|
|
|
|
* its EthersError type.
|
|
|
|
*
|
|
|
|
* @flatworm-skip-docs
|
|
|
|
*/
|
2022-09-05 23:14:43 +03:00
|
|
|
export type CodedEthersError<T> =
|
|
|
|
T extends "UNKNOWN_ERROR" ? UnknownError:
|
|
|
|
T extends "NOT_IMPLEMENTED" ? NotImplementedError:
|
|
|
|
T extends "UNSUPPORTED_OPERATION" ? UnsupportedOperationError:
|
|
|
|
T extends "NETWORK_ERROR" ? NetworkError:
|
|
|
|
T extends "SERVER_ERROR" ? ServerError:
|
|
|
|
T extends "TIMEOUT" ? TimeoutError:
|
|
|
|
T extends "BAD_DATA" ? BadDataError:
|
|
|
|
T extends "CANCELLED" ? CancelledError:
|
|
|
|
|
|
|
|
T extends "BUFFER_OVERRUN" ? BufferOverrunError:
|
|
|
|
T extends "NUMERIC_FAULT" ? NumericFaultError:
|
|
|
|
|
|
|
|
T extends "INVALID_ARGUMENT" ? InvalidArgumentError:
|
|
|
|
T extends "MISSING_ARGUMENT" ? MissingArgumentError:
|
|
|
|
T extends "UNEXPECTED_ARGUMENT" ? UnexpectedArgumentError:
|
|
|
|
|
|
|
|
T extends "CALL_EXCEPTION" ? CallExceptionError:
|
|
|
|
T extends "INSUFFICIENT_FUNDS" ? InsufficientFundsError:
|
|
|
|
T extends "NONCE_EXPIRED" ? NonceExpiredError:
|
|
|
|
T extends "OFFCHAIN_FAULT" ? OffchainFaultError:
|
|
|
|
T extends "REPLACEMENT_UNDERPRICED" ? ReplacementUnderpricedError:
|
|
|
|
T extends "TRANSACTION_REPLACED" ? TransactionReplacedError:
|
|
|
|
T extends "UNCONFIGURED_NAME" ? UnconfiguredNameError:
|
|
|
|
|
|
|
|
T extends "ACTION_REJECTED" ? ActionRejectedError:
|
|
|
|
|
|
|
|
never;
|
|
|
|
|
2022-09-09 06:21:08 +03:00
|
|
|
|
|
|
|
|
2022-09-05 23:14:43 +03:00
|
|
|
/**
|
2022-09-16 05:30:27 +03:00
|
|
|
* 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
|
2022-12-10 02:21:45 +03:00
|
|
|
* try {
|
|
|
|
* // code....
|
|
|
|
* } catch (e) {
|
2022-09-16 05:30:27 +03:00
|
|
|
* if (isError(e, "CALL_EXCEPTION")) {
|
2022-12-10 02:21:45 +03:00
|
|
|
* // The Type Guard has validated this object
|
2022-09-05 23:14:43 +03:00
|
|
|
* console.log(e.data);
|
|
|
|
* }
|
2022-12-10 02:21:45 +03:00
|
|
|
* }
|
2022-09-05 23:14:43 +03:00
|
|
|
*/
|
|
|
|
export function isError<K extends ErrorCode, T extends CodedEthersError<K>>(error: any, code: K): error is T {
|
|
|
|
return (error && (<EthersError>error).code === code);
|
|
|
|
}
|
|
|
|
|
2022-09-16 05:30:27 +03:00
|
|
|
/**
|
|
|
|
* Returns true if %%error%% is a [CALL_EXCEPTION](api:CallExceptionError).
|
|
|
|
*/
|
2022-09-05 23:14:43 +03:00
|
|
|
export function isCallException(error: any): error is CallExceptionError {
|
|
|
|
return isError(error, "CALL_EXCEPTION");
|
|
|
|
}
|
2022-09-09 06:21:08 +03:00
|
|
|
|
2022-09-16 05:30:27 +03:00
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
2022-09-09 06:21:08 +03:00
|
|
|
export function makeError<K extends ErrorCode, T extends CodedEthersError<K>>(message: string, code: K, info?: ErrorInfo<T>): T {
|
|
|
|
{
|
|
|
|
const details: Array<string> = [];
|
|
|
|
if (info) {
|
2022-09-16 05:30:27 +03:00
|
|
|
if ("message" in info || "code" in info || "name" in info) {
|
2022-11-28 05:50:34 +03:00
|
|
|
throw new Error(`value will overwrite populated values: ${ stringify(info) }`);
|
2022-09-16 05:30:27 +03:00
|
|
|
}
|
2022-09-09 06:21:08 +03:00
|
|
|
for (const key in info) {
|
|
|
|
const value = <any>(info[<keyof ErrorInfo<T>>key]);
|
2022-11-28 05:50:34 +03:00
|
|
|
// try {
|
|
|
|
details.push(key + "=" + stringify(value));
|
|
|
|
// } catch (error: any) {
|
|
|
|
// console.log("MMM", error.message);
|
|
|
|
// details.push(key + "=[could not serialize object]");
|
|
|
|
// }
|
2022-09-09 06:21:08 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
details.push(`code=${ code }`);
|
|
|
|
details.push(`version=${ version }`);
|
|
|
|
|
|
|
|
if (details.length) {
|
|
|
|
message += " (" + details.join(", ") + ")";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-28 05:50:34 +03:00
|
|
|
let error;
|
|
|
|
switch (code) {
|
|
|
|
case "INVALID_ARGUMENT":
|
|
|
|
error = new TypeError(message);
|
|
|
|
break;
|
|
|
|
case "NUMERIC_FAULT":
|
|
|
|
case "BUFFER_OVERRUN":
|
|
|
|
error = new RangeError(message);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
error = new Error(message);
|
2022-09-09 06:21:08 +03:00
|
|
|
}
|
2022-09-16 05:30:27 +03:00
|
|
|
|
2022-11-28 05:50:34 +03:00
|
|
|
defineProperties<EthersError>(<EthersError>error, { code });
|
|
|
|
|
|
|
|
if (info) { defineProperties<any>(error, info); }
|
|
|
|
|
2022-09-09 06:21:08 +03:00
|
|
|
return <T>error;
|
|
|
|
}
|
|
|
|
|
2022-09-16 05:30:27 +03:00
|
|
|
/**
|
|
|
|
* Throws an EthersError with %%message%%, %%code%% and additional error
|
2022-11-05 01:08:37 +03:00
|
|
|
* %%info%% when %%check%% is falsish..
|
2022-09-16 05:30:27 +03:00
|
|
|
*
|
|
|
|
* @see [[api:makeError]]
|
|
|
|
*/
|
2022-11-05 01:08:37 +03:00
|
|
|
export function assert<K extends ErrorCode, T extends CodedEthersError<K>>(check: unknown, message: string, code: K, info?: ErrorInfo<T>): asserts check {
|
|
|
|
if (!check) { throw makeError(message, code, info); }
|
2022-09-09 06:21:08 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-09-16 05:30:27 +03:00
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
2022-09-09 06:21:08 +03:00
|
|
|
export function assertArgument(check: unknown, message: string, name: string, value: unknown): asserts check {
|
2022-11-05 01:08:37 +03:00
|
|
|
assert(check, message, "INVALID_ARGUMENT", { argument: name, value: value });
|
2022-09-09 06:21:08 +03:00
|
|
|
}
|
|
|
|
|
2022-11-28 05:50:34 +03:00
|
|
|
export function assertArgumentCount(count: number, expectedCount: number, message?: string): void {
|
|
|
|
if (message == null) { message = ""; }
|
2022-09-09 06:21:08 +03:00
|
|
|
if (message) { message = ": " + message; }
|
|
|
|
|
2022-11-05 01:08:37 +03:00
|
|
|
assert(count >= expectedCount, "missing arguemnt" + message, "MISSING_ARGUMENT", {
|
|
|
|
count: count,
|
|
|
|
expectedCount: expectedCount
|
|
|
|
});
|
2022-09-09 06:21:08 +03:00
|
|
|
|
2022-11-05 01:08:37 +03:00
|
|
|
assert(count <= expectedCount, "too many arguemnts" + message, "UNEXPECTED_ARGUMENT", {
|
|
|
|
count: count,
|
|
|
|
expectedCount: expectedCount
|
|
|
|
});
|
2022-09-09 06:21:08 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
const _normalizeForms = ["NFD", "NFC", "NFKD", "NFKC"].reduce((accum, form) => {
|
|
|
|
try {
|
|
|
|
// General test for normalize
|
|
|
|
/* c8 ignore start */
|
|
|
|
if ("test".normalize(form) !== "test") { throw new Error("bad"); };
|
|
|
|
/* c8 ignore stop */
|
|
|
|
|
|
|
|
if (form === "NFD") {
|
|
|
|
const check = String.fromCharCode(0xe9).normalize("NFD");
|
|
|
|
const expected = String.fromCharCode(0x65, 0x0301)
|
|
|
|
/* c8 ignore start */
|
|
|
|
if (check !== expected) { throw new Error("broken") }
|
|
|
|
/* c8 ignore stop */
|
|
|
|
}
|
|
|
|
|
|
|
|
accum.push(form);
|
|
|
|
} catch(error) { }
|
|
|
|
|
|
|
|
return accum;
|
|
|
|
}, <Array<string>>[]);
|
|
|
|
|
2022-09-16 05:30:27 +03:00
|
|
|
/**
|
|
|
|
* Throws if the normalization %%form%% is not supported.
|
|
|
|
*/
|
2022-09-09 06:21:08 +03:00
|
|
|
export function assertNormalize(form: string): void {
|
2022-11-05 01:08:37 +03:00
|
|
|
assert(_normalizeForms.indexOf(form) >= 0, "platform missing String.prototype.normalize", "UNSUPPORTED_OPERATION", {
|
|
|
|
operation: "String.prototype.normalize", info: { form }
|
|
|
|
});
|
2022-09-09 06:21:08 +03:00
|
|
|
}
|
|
|
|
|
2022-09-16 05:30:27 +03:00
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
2022-11-28 05:50:34 +03:00
|
|
|
export function assertPrivate(givenGuard: any, guard: any, className?: string): void {
|
|
|
|
if (className == null) { className = ""; }
|
2022-09-09 06:21:08 +03:00
|
|
|
if (givenGuard !== guard) {
|
|
|
|
let method = className, operation = "new";
|
|
|
|
if (className) {
|
|
|
|
method += ".";
|
|
|
|
operation += " " + className;
|
|
|
|
}
|
2022-11-05 01:08:37 +03:00
|
|
|
assert(false, `private constructor; use ${ method }from* methods`, "UNSUPPORTED_OPERATION", {
|
2022-09-09 06:21:08 +03:00
|
|
|
operation
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|