refactor: move brother_node development artifact to dev/test-nodes subdirectory

Development Artifact Cleanup:
 BROTHER_NODE REORGANIZATION: Moved development test node to appropriate location
- dev/test-nodes/brother_node/: Moved from root directory for better organization
- Contains development configuration, test logs, and test chain data
- No impact on production systems - purely development/testing artifact

 DEVELOPMENT ARTIFACTS IDENTIFIED:
- Chain ID: aitbc-brother-chain (test/development chain)
- Ports: 8010 (P2P) and 8011 (RPC) - different from production
- Environment: .env file with test configuration
- Logs: rpc.log and node.log from development testing session (March 15, 2026)

 ROOT DIRECTORY CLEANUP: Removed development clutter from production directory
- brother_node/ moved to dev/test-nodes/brother_node/
- Root directory now contains only production-ready components
- Development artifacts properly organized in dev/ subdirectory

DIRECTORY STRUCTURE IMPROVEMENT:
📁 dev/test-nodes/: Development and testing node configurations
🏗️ Root Directory: Clean production structure with only essential components
🧪 Development Isolation: Test environments separated from production

BENEFITS:
 Clean Production Directory: No development artifacts in root
 Better Organization: Development nodes grouped in dev/ subdirectory
 Clear Separation: Production vs development environments clearly distinguished
 Maintainability: Easier to identify and manage development components

RESULT: Successfully moved brother_node development artifact to dev/test-nodes/ subdirectory, cleaning up the root directory while preserving development testing environment for future use.
This commit is contained in:
2026-03-30 17:09:06 +02:00
parent bf730dcb4a
commit 816e258d4c
11734 changed files with 2001707 additions and 0 deletions

73
dev/env/node_modules/ethers/src.ts/utils/base58.ts generated vendored Executable file
View File

@@ -0,0 +1,73 @@
/**
* The [Base58 Encoding](link-base58) scheme allows a **numeric** value
* to be encoded as a compact string using a radix of 58 using only
* alpha-numeric characters. Confusingly similar characters are omitted
* (i.e. ``"l0O"``).
*
* Note that Base58 encodes a **numeric** value, not arbitrary bytes,
* since any zero-bytes on the left would get removed. To mitigate this
* issue most schemes that use Base58 choose specific high-order values
* to ensure non-zero prefixes.
*
* @_subsection: api/utils:Base58 Encoding [about-base58]
*/
import { getBytes } from "./data.js";
import { assertArgument } from "./errors.js";
import { toBigInt } from "./maths.js";
import type { BytesLike } from "./index.js";
const Alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
let Lookup: null | Record<string, bigint> = null;
function getAlpha(letter: string): bigint {
if (Lookup == null) {
Lookup = { };
for (let i = 0; i < Alphabet.length; i++) {
Lookup[Alphabet[i]] = BigInt(i);
}
}
const result = Lookup[letter];
assertArgument(result != null, `invalid base58 value`, "letter", letter);
return result;
}
const BN_0 = BigInt(0);
const BN_58 = BigInt(58);
/**
* Encode %%value%% as a Base58-encoded string.
*/
export function encodeBase58(_value: BytesLike): string {
const bytes = getBytes(_value);
let value = toBigInt(bytes);
let result = "";
while (value) {
result = Alphabet[Number(value % BN_58)] + result;
value /= BN_58;
}
// Account for leading padding zeros
for (let i = 0; i < bytes.length; i++) {
if (bytes[i]) { break; }
result = Alphabet[0] + result;
}
return result;
}
/**
* Decode the Base58-encoded %%value%%.
*/
export function decodeBase58(value: string): bigint {
let result = BN_0;
for (let i = 0; i < value.length; i++) {
result *= BN_58;
result += getAlpha(value[i]);
}
return result;
}

25
dev/env/node_modules/ethers/src.ts/utils/base64-browser.ts generated vendored Executable file
View File

@@ -0,0 +1,25 @@
// utils/base64-browser
import { getBytes } from "./data.js";
import type { BytesLike } from "./data.js";
export function decodeBase64(textData: string): Uint8Array {
textData = atob(textData);
const data = new Uint8Array(textData.length);
for (let i = 0; i < textData.length; i++) {
data[i] = textData.charCodeAt(i);
}
return getBytes(data);
}
export function encodeBase64(_data: BytesLike): string {
const data = getBytes(_data);
let textData = "";
for (let i = 0; i < data.length; i++) {
textData += String.fromCharCode(data[i]);
}
return btoa(textData);
}

56
dev/env/node_modules/ethers/src.ts/utils/base64.ts generated vendored Executable file
View File

@@ -0,0 +1,56 @@
/**
* [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.
*
* @_subsection: api/utils:Base64 Encoding [about-base64]
*/
import { getBytes, getBytesCopy } from "./data.js";
import type { BytesLike } from "./data.js";
/**
* Decodes the base-64 encoded %%value%%.
*
* @example:
* // The decoded value is always binary data...
* result = decodeBase64("SGVsbG8gV29ybGQhIQ==")
* //_result:
*
* // ...use toUtf8String to convert it to a string.
* toUtf8String(result)
* //_result:
*
* // Decoding binary data
* decodeBase64("EjQ=")
* //_result:
*/
export function decodeBase64(value: string): Uint8Array {
return getBytesCopy(Buffer.from(value, "base64"));
};
/**
* Encodes %%data%% as a base-64 encoded string.
*
* @example:
* // Encoding binary data as a hexstring
* encodeBase64("0x1234")
* //_result:
*
* // Encoding binary data as a Uint8Array
* encodeBase64(new Uint8Array([ 0x12, 0x34 ]))
* //_result:
*
* // The input MUST be data...
* encodeBase64("Hello World!!")
* //_error:
*
* // ...use toUtf8Bytes for this.
* encodeBase64(toUtf8Bytes("Hello World!!"))
* //_result:
*/
export function encodeBase64(data: BytesLike): string {
return Buffer.from(getBytes(data)).toString("base64");
}

200
dev/env/node_modules/ethers/src.ts/utils/data.ts generated vendored Executable file
View File

@@ -0,0 +1,200 @@
/**
* Some data helpers.
*
*
* @_subsection api/utils:Data Helpers [about-data]
*/
import { assert, assertArgument } from "./errors.js";
/**
* A [[HexString]] whose length is even, which ensures it is a valid
* representation of binary data.
*/
export type DataHexString = string;
/**
* A string which is prefixed with ``0x`` and followed by any number
* of case-agnostic hexadecimal characters.
*
* It must match the regular expression ``/0x[0-9A-Fa-f]*\/``.
*/
export type HexString = string;
/**
* An object that can be used to represent binary data.
*/
export type BytesLike = DataHexString | Uint8Array;
function _getBytes(value: BytesLike, name?: string, copy?: boolean): Uint8Array {
if (value instanceof Uint8Array) {
if (copy) { return new Uint8Array(value); }
return value;
}
if (typeof(value) === "string" && (value.length % 2) === 0 &&
value.match(/^0x[0-9a-f]*$/i)) {
const result = new Uint8Array((value.length - 2) / 2);
let offset = 2;
for (let i = 0; i < result.length; i++) {
result[i] = parseInt(value.substring(offset, offset + 2), 16);
offset += 2;
}
return result;
}
assertArgument(false, "invalid BytesLike value", name || "value", value);
}
/**
* Get a typed Uint8Array for %%value%%. If already a Uint8Array
* the original %%value%% is returned; if a copy is required use
* [[getBytesCopy]].
*
* @see: getBytesCopy
*/
export function getBytes(value: BytesLike, name?: string): Uint8Array {
return _getBytes(value, name, false);
}
/**
* Get a typed Uint8Array for %%value%%, creating a copy if necessary
* to prevent any modifications of the returned value from being
* reflected elsewhere.
*
* @see: getBytes
*/
export function getBytesCopy(value: BytesLike, name?: string): Uint8Array {
return _getBytes(value, name, true);
}
/**
* Returns true if %%value%% is a valid [[HexString]].
*
* If %%length%% is ``true`` or a //number//, it also checks that
* %%value%% is a valid [[DataHexString]] of %%length%% (if a //number//)
* bytes of data (e.g. ``0x1234`` is 2 bytes).
*/
export function isHexString(value: any, length?: number | boolean): value is `0x${ string }` {
if (typeof(value) !== "string" || !value.match(/^0x[0-9A-Fa-f]*$/)) {
return false
}
if (typeof(length) === "number" && value.length !== 2 + 2 * length) { return false; }
if (length === true && (value.length % 2) !== 0) { return false; }
return true;
}
/**
* Returns true if %%value%% is a valid representation of arbitrary
* data (i.e. a valid [[DataHexString]] or a Uint8Array).
*/
export function isBytesLike(value: any): value is BytesLike {
return (isHexString(value, true) || (value instanceof Uint8Array));
}
const HexCharacters: string = "0123456789abcdef";
/**
* Returns a [[DataHexString]] representation of %%data%%.
*/
export function hexlify(data: BytesLike): string {
const bytes = getBytes(data);
let result = "0x";
for (let i = 0; i < bytes.length; i++) {
const v = bytes[i];
result += HexCharacters[(v & 0xf0) >> 4] + HexCharacters[v & 0x0f];
}
return result;
}
/**
* Returns a [[DataHexString]] by concatenating all values
* within %%data%%.
*/
export function concat(datas: ReadonlyArray<BytesLike>): string {
return "0x" + datas.map((d) => hexlify(d).substring(2)).join("");
}
/**
* Returns the length of %%data%%, in bytes.
*/
export function dataLength(data: BytesLike): number {
if (isHexString(data, true)) { return (data.length - 2) / 2; }
return getBytes(data).length;
}
/**
* Returns a [[DataHexString]] by slicing %%data%% from the %%start%%
* offset to the %%end%% offset.
*
* By default %%start%% is 0 and %%end%% is the length of %%data%%.
*/
export function dataSlice(data: BytesLike, start?: number, end?: number): string {
const bytes = getBytes(data);
if (end != null && end > bytes.length) {
assert(false, "cannot slice beyond data bounds", "BUFFER_OVERRUN", {
buffer: bytes, length: bytes.length, offset: end
});
}
return hexlify(bytes.slice((start == null) ? 0: start, (end == null) ? bytes.length: end));
}
/**
* Return the [[DataHexString]] result by stripping all **leading**
** zero bytes from %%data%%.
*/
export function stripZerosLeft(data: BytesLike): string {
let bytes = hexlify(data).substring(2);
while (bytes.startsWith("00")) { bytes = bytes.substring(2); }
return "0x" + bytes;
}
function zeroPad(data: BytesLike, length: number, left: boolean): string {
const bytes = getBytes(data);
assert(length >= bytes.length, "padding exceeds data length", "BUFFER_OVERRUN", {
buffer: new Uint8Array(bytes),
length: length,
offset: length + 1
});
const result = new Uint8Array(length);
result.fill(0);
if (left) {
result.set(bytes, length - bytes.length);
} else {
result.set(bytes, 0);
}
return hexlify(result);
}
/**
* Return the [[DataHexString]] of %%data%% padded on the **left**
* to %%length%% bytes.
*
* If %%data%% already exceeds %%length%%, a [[BufferOverrunError]] 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);
}
/**
* Return the [[DataHexString]] of %%data%% padded on the **right**
* to %%length%% bytes.
*
* If %%data%% already exceeds %%length%%, a [[BufferOverrunError]] 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);
}

797
dev/env/node_modules/ethers/src.ts/utils/errors.ts generated vendored Executable file
View File

@@ -0,0 +1,797 @@
/**
* All errors in ethers include properties to ensure they are both
* human-readable (i.e. ``.message``) and machine-readable (i.e. ``.code``).
*
* The [[isError]] function can be used to check the error ``code`` and
* provide a type guard for the properties present on that error interface.
*
* @_section: api/utils/errors:Errors [about-errors]
*/
import { version } from "../_version.js";
import { defineProperties } from "./properties.js";
import type {
TransactionRequest, TransactionReceipt, TransactionResponse
} from "../providers/index.js";
import type { FetchRequest, FetchResponse } from "./fetch.js";
/**
* An error may contain additional properties, but those must not
* conflict with any implicit properties.
*/
export type ErrorInfo<T> = Omit<T, "code" | "name" | "message" | "shortMessage"> & { shortMessage?: string };
function stringify(value: any, seen?: Set<any>): any {
if (value == null) { return "null"; }
if (seen == null) { seen = new Set(); }
if (typeof(value) === "object") {
if (seen.has(value)) { return "[Circular]"; }
seen.add(value);
}
if (Array.isArray(value)) {
return "[ " + (value.map((v) => stringify(v, seen))).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(), seen);
}
switch (typeof(value)) {
case "boolean": case "number": case "symbol":
return value.toString();
case "bigint":
return BigInt(value).toString();
case "string":
return JSON.stringify(value);
case "object": {
const keys = Object.keys(value);
keys.sort();
return "{ " + keys.map((k) => `${ stringify(k, seen) }: ${ stringify(value[k], seen) }`).join(", ") + " }";
}
}
return `[ COULD NOT SERIALIZE ]`;
}
/**
* All errors emitted by ethers have an **ErrorCode** to help
* identify and coalesce errors to simplify programmatic analysis.
*
* Each **ErrorCode** is the %%code%% proerty of a coresponding
* [[EthersError]].
*
* **Generic Errors**
*
* **``"UNKNOWN_ERROR"``** - see [[UnknownError]]
*
* **``"NOT_IMPLEMENTED"``** - see [[NotImplementedError]]
*
* **``"UNSUPPORTED_OPERATION"``** - see [[UnsupportedOperationError]]
*
* **``"NETWORK_ERROR"``** - see [[NetworkError]]
*
* **``"SERVER_ERROR"``** - see [[ServerError]]
*
* **``"TIMEOUT"``** - see [[TimeoutError]]
*
* **``"BAD_DATA"``** - see [[BadDataError]]
*
* **``"CANCELLED"``** - see [[CancelledError]]
*
* **Operational Errors**
*
* **``"BUFFER_OVERRUN"``** - see [[BufferOverrunError]]
*
* **``"NUMERIC_FAULT"``** - see [[NumericFaultError]]
*
* **Argument Errors**
*
* **``"INVALID_ARGUMENT"``** - see [[InvalidArgumentError]]
*
* **``"MISSING_ARGUMENT"``** - see [[MissingArgumentError]]
*
* **``"UNEXPECTED_ARGUMENT"``** - see [[UnexpectedArgumentError]]
*
* **``"VALUE_MISMATCH"``** - //unused//
*
* **Blockchain Errors**
*
* **``"CALL_EXCEPTION"``** - see [[CallExceptionError]]
*
* **``"INSUFFICIENT_FUNDS"``** - see [[InsufficientFundsError]]
*
* **``"NONCE_EXPIRED"``** - see [[NonceExpiredError]]
*
* **``"REPLACEMENT_UNDERPRICED"``** - see [[ReplacementUnderpricedError]]
*
* **``"TRANSACTION_REPLACED"``** - see [[TransactionReplacedError]]
*
* **``"UNCONFIGURED_NAME"``** - see [[UnconfiguredNameError]]
*
* **``"OFFCHAIN_FAULT"``** - see [[OffchainFaultError]]
*
* **User Interaction Errors**
*
* **``"ACTION_REJECTED"``** - see [[ActionRejectedError]]
*/
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"
;
/**
* All errors in Ethers include properties to assist in
* machine-readable errors.
*/
export interface EthersError<T extends ErrorCode = ErrorCode> extends Error {
/**
* The string error code.
*/
code: ErrorCode;
/**
* A short message describing the error, with minimal additional
* details.
*/
shortMessage: string;
/**
* Additional info regarding the error that may be useful.
*
* This is generally helpful mostly for human-based debugging.
*/
info?: Record<string, any>;
/**
* Any related error.
*/
error?: Error;
}
// Generic Errors
/**
* This Error is a catch-all for when there is no way for Ethers to
* know what the underlying problem is.
*/
export interface UnknownError extends EthersError<"UNKNOWN_ERROR"> {
[ key: string ]: any;
}
/**
* This Error is mostly used as a stub for functionality that is
* intended for the future, but is currently not implemented.
*/
export interface NotImplementedError extends EthersError<"NOT_IMPLEMENTED"> {
/**
* The attempted operation.
*/
operation: string;
}
/**
* This Error indicates that the attempted operation is not supported.
*
* This could range from a specific 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.
*/
export interface UnsupportedOperationError extends EthersError<"UNSUPPORTED_OPERATION"> {
/**
* The attempted operation.
*/
operation: string;
}
/**
* This Error indicates a problem connecting to a network.
*/
export interface NetworkError extends EthersError<"NETWORK_ERROR"> {
/**
* The network event.
*/
event: string;
}
/**
* This Error indicates there was a problem fetching a resource from
* a server.
*/
export interface ServerError extends EthersError<"SERVER_ERROR"> {
/**
* The requested resource.
*/
request: FetchRequest | string;
/**
* The response received from the server, if available.
*/
response?: FetchResponse;
}
/**
* 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.
*/
export interface TimeoutError extends EthersError<"TIMEOUT"> {
/**
* The attempted operation.
*/
operation: string;
/**
* The reason.
*/
reason: string;
/**
* The resource request, if available.
*/
request?: FetchRequest;
}
/**
* This Error indicates that a provided set of data cannot
* be correctly interpreted.
*/
export interface BadDataError extends EthersError<"BAD_DATA"> {
/**
* The data.
*/
value: any;
}
/**
* This Error indicates that the operation was cancelled by a
* programmatic call, for example to ``cancel()``.
*/
export interface CancelledError extends EthersError<"CANCELLED"> {
}
// Operational Errors
/**
* 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.
*/
export interface BufferOverrunError extends EthersError<"BUFFER_OVERRUN"> {
/**
* The buffer that was overrun.
*/
buffer: Uint8Array;
/**
* The length of the buffer.
*/
length: number;
/**
* The offset that was requested.
*/
offset: number;
}
/**
* 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.
*/
export interface NumericFaultError extends EthersError<"NUMERIC_FAULT"> {
/**
* The attempted operation.
*/
operation: string;
/**
* The fault reported.
*/
fault: string;
/**
* The value the operation was attempted against.
*/
value: any;
}
// Argument Errors
/**
* This Error indicates an incorrect type or value was passed to
* a function or method.
*/
export interface InvalidArgumentError extends EthersError<"INVALID_ARGUMENT"> {
/**
* The name of the argument.
*/
argument: string;
/**
* The value that was provided.
*/
value: any;
info?: Record<string, any>
}
/**
* 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 call exception.
*/
export type CallExceptionAction = "call" | "estimateGas" | "getTransactionResult" | "sendTransaction" | "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"> {
/**
* The action being performed when the revert was encountered.
*/
action: CallExceptionAction;
/**
* The revert data returned.
*/
data: null | string;
/**
* A human-readable representation of data, if possible.
*/
reason: null | string;
/**
* The transaction that triggered the exception.
*/
transaction: CallExceptionTransaction,
/**
* The contract invocation details, if available.
*/
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>;
}
/**
* If the error occurred in a transaction that was mined
* (with a status of ``0``), this is the receipt.
*/
receipt?: TransactionReceipt; // @TODO: in v7, make this `null | TransactionReceipt`
}
/**
* 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;
}
/**
* 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 [[ZeroAddress]].
*/
export interface UnconfiguredNameError extends EthersError<"UNCONFIGURED_NAME"> {
/**
* The ENS name that was requested
*/
value: string;
}
/**
* 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.
*/
export interface ActionRejectedError extends EthersError<"ACTION_REJECTED"> {
/**
* The requested action.
*/
action: "requestAccess" | "sendTransaction" | "signMessage" | "signTransaction" | "signTypedData" | "unknown",
/**
* 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.
*/
reason: "expired" | "rejected" | "pending"
}
// Coding; converts an ErrorCode its Typed Error
/**
* A conditional type that transforms the [[ErrorCode]] T into
* its EthersError type.
*
* @flatworm-skip-docs
*/
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;
/**
* Returns true if the %%error%% matches an error thrown by ethers
* that matches the error %%code%%.
*
* In TypeScript environments, 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, "CALL_EXCEPTION")) {
* // The Type Guard has validated this object
* console.log(e.data);
* }
* }
*/
export function isError<K extends ErrorCode, T extends CodedEthersError<K>>(error: any, code: K): error is T {
return (error && (<EthersError>error).code === code);
}
/**
* Returns true if %%error%% is a [[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 additional properties
* for the corresponding EthersError.
*
* Each error in ethers includes the version of ethers, a
* machine-readable [[ErrorCode]], and depending on %%code%%, additional
* required properties. The error message will also include the %%message%%,
* ethers version, %%code%% and all additional properties, serialized.
*/
export function makeError<K extends ErrorCode, T extends CodedEthersError<K>>(message: string, code: K, info?: ErrorInfo<T>): T {
let shortMessage = message;
{
const details: Array<string> = [];
if (info) {
if ("message" in info || "code" in info || "name" in info) {
throw new Error(`value will overwrite populated values: ${ stringify(info) }`);
}
for (const key in info) {
if (key === "shortMessage") { continue; }
const value = <any>(info[<keyof ErrorInfo<T>>key]);
// try {
details.push(key + "=" + stringify(value));
// } catch (error: any) {
// console.log("MMM", error.message);
// details.push(key + "=[could not serialize object]");
// }
}
}
details.push(`code=${ code }`);
details.push(`version=${ version }`);
if (details.length) {
message += " (" + details.join(", ") + ")";
}
}
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);
}
defineProperties<EthersError>(<EthersError>error, { code });
if (info) { Object.assign(error, info); }
if ((<any>error).shortMessage == null) {
defineProperties<EthersError>(<EthersError>error, { shortMessage });
}
return <T>error;
}
/**
* Throws an EthersError with %%message%%, %%code%% and additional error
* %%info%% when %%check%% is falsish..
*
* @see [[api:makeError]]
*/
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); }
}
/**
* 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 {
assert(check, message, "INVALID_ARGUMENT", { argument: name, value: value });
}
export function assertArgumentCount(count: number, expectedCount: number, message?: string): void {
if (message == null) { message = ""; }
if (message) { message = ": " + message; }
assert(count >= expectedCount, "missing argument" + message, "MISSING_ARGUMENT", {
count: count,
expectedCount: expectedCount
});
assert(count <= expectedCount, "too many arguments" + message, "UNEXPECTED_ARGUMENT", {
count: count,
expectedCount: expectedCount
});
}
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>>[]);
/**
* Throws if the normalization %%form%% is not supported.
*/
export function assertNormalize(form: string): void {
assert(_normalizeForms.indexOf(form) >= 0, "platform missing String.prototype.normalize", "UNSUPPORTED_OPERATION", {
operation: "String.prototype.normalize", info: { form }
});
}
/**
* 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 (className == null) { className = ""; }
if (givenGuard !== guard) {
let method = className, operation = "new";
if (className) {
method += ".";
operation += " " + className;
}
assert(false, `private constructor; use ${ method }from* methods`, "UNSUPPORTED_OPERATION", {
operation
});
}
}

105
dev/env/node_modules/ethers/src.ts/utils/events.ts generated vendored Executable file
View File

@@ -0,0 +1,105 @@
/**
* Events allow for applications to use the observer pattern, which
* allows subscribing and publishing events, outside the normal
* execution paths.
*
* @_section api/utils/events:Events [about-events]
*/
import { defineProperties } from "./properties.js";
/**
* A callback function called when a an event is triggered.
*/
export type Listener = (...args: Array<any>) => void;
/**
* An **EventEmitterable** behaves similar to an EventEmitter
* except provides async access to its methods.
*
* An EventEmitter implements the observer pattern.
*/
export interface EventEmitterable<T> {
/**
* Registers a %%listener%% that is called whenever the
* %%event%% occurs until unregistered.
*/
on(event: T, listener: Listener): Promise<this>;
/**
* Registers a %%listener%% that is called the next time
* %%event%% occurs.
*/
once(event: T, listener: Listener): Promise<this>;
/**
* Triggers each listener for %%event%% with the %%args%%.
*/
emit(event: T, ...args: Array<any>): Promise<boolean>;
/**
* Resolves to the number of listeners for %%event%%.
*/
listenerCount(event?: T): Promise<number>;
/**
* Resolves to the listeners for %%event%%.
*/
listeners(event?: T): Promise<Array<Listener>>;
/**
* Unregister the %%listener%% for %%event%%. If %%listener%%
* is unspecified, all listeners are unregistered.
*/
off(event: T, listener?: Listener): Promise<this>;
/**
* Unregister all listeners for %%event%%.
*/
removeAllListeners(event?: T): Promise<this>;
/**
* Alias for [[on]].
*/
addListener(event: T, listener: Listener): Promise<this>;
/**
* Alias for [[off]].
*/
removeListener(event: T, listener: Listener): Promise<this>;
}
/**
* When an [[EventEmitterable]] triggers a [[Listener]], the
* callback always ahas one additional argument passed, which is
* an **EventPayload**.
*/
export class EventPayload<T> {
/**
* The event filter.
*/
readonly filter!: T;
/**
* The **EventEmitterable**.
*/
readonly emitter!: EventEmitterable<T>;
readonly #listener: null | Listener;
/**
* Create a new **EventPayload** for %%emitter%% with
* the %%listener%% and for %%filter%%.
*/
constructor(emitter: EventEmitterable<T>, listener: null | Listener, filter: T) {
this.#listener = listener;
defineProperties<EventPayload<any>>(this, { emitter, filter });
}
/**
* Unregister the triggered listener for future events.
*/
async removeListener(): Promise<void> {
if (this.#listener == null) { return; }
await this.emitter.off(this.filter, this.#listener);
}
}

970
dev/env/node_modules/ethers/src.ts/utils/fetch.ts generated vendored Executable file
View File

@@ -0,0 +1,970 @@
/**
* Fetching content from the web is environment-specific, so Ethers
* provides an abstraction that each environment can implement to provide
* this service.
*
* On [Node.js](link-node), the ``http`` and ``https`` libs are used to
* create a request object, register event listeners and process data
* and populate the [[FetchResponse]].
*
* In a browser, the [DOM fetch](link-js-fetch) is used, and the resulting
* ``Promise`` is waited on to retrieve the payload.
*
* The [[FetchRequest]] is responsible for handling many common situations,
* such as redirects, server throttling, authentication, etc.
*
* It also handles common gateways, such as IPFS and data URIs.
*
* @_section api/utils/fetching:Fetching Web Content [about-fetch]
*/
import { decodeBase64, encodeBase64 } from "./base64.js";
import { hexlify } from "./data.js";
import { assert, assertArgument } from "./errors.js";
import { defineProperties } from "./properties.js";
import { toUtf8Bytes, toUtf8String } from "./utf8.js";
import { createGetUrl } from "./geturl.js";
/**
* An environment's implementation of ``getUrl`` must return this type.
*/
export type GetUrlResponse = {
statusCode: number,
statusMessage: string,
headers: Record<string, string>,
body: null | Uint8Array
};
/**
* This can be used to control how throttling is handled in
* [[FetchRequest-setThrottleParams]].
*/
export type FetchThrottleParams = {
maxAttempts?: number;
slotInterval?: number;
};
/**
* Called before any network request, allowing updated headers (e.g. Bearer tokens), etc.
*/
export type FetchPreflightFunc = (req: FetchRequest) => Promise<FetchRequest>;
/**
* Called on the response, allowing client-based throttling logic or post-processing.
*/
export type FetchProcessFunc = (req: FetchRequest, resp: FetchResponse) => Promise<FetchResponse>;
/**
* Called prior to each retry; return true to retry, false to abort.
*/
export type FetchRetryFunc = (req: FetchRequest, resp: FetchResponse, attempt: number) => Promise<boolean>;
/**
* Called on Gateway URLs.
*/
export type FetchGatewayFunc = (url: string, signal?: FetchCancelSignal) => Promise<FetchRequest | FetchResponse>;
/**
* Used to perform a fetch; use this to override the underlying network
* fetch layer. In NodeJS, the default uses the "http" and "https" libraries
* and in the browser ``fetch`` is used. If you wish to use Axios, this is
* how you would register it.
*/
export type FetchGetUrlFunc = (req: FetchRequest, signal?: FetchCancelSignal) => Promise<GetUrlResponse>;
const MAX_ATTEMPTS = 12;
const SLOT_INTERVAL = 250;
// The global FetchGetUrlFunc implementation.
let defaultGetUrlFunc: FetchGetUrlFunc = createGetUrl();
const reData = new RegExp("^data:([^;:]*)?(;base64)?,(.*)$", "i");
const reIpfs = new RegExp("^ipfs:/\/(ipfs/)?(.*)$", "i");
// If locked, new Gateways cannot be added
let locked = false;
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs
async function dataGatewayFunc(url: string, signal?: FetchCancelSignal): Promise<FetchResponse> {
try {
const match = url.match(reData);
if (!match) { throw new Error("invalid data"); }
return new FetchResponse(200, "OK", {
"content-type": (match[1] || "text/plain"),
}, (match[2] ? decodeBase64(match[3]): unpercent(match[3])));
} catch (error) {
return new FetchResponse(599, "BAD REQUEST (invalid data: URI)", { }, null, new FetchRequest(url));
}
}
/**
* Returns a [[FetchGatewayFunc]] for fetching content from a standard
* IPFS gateway hosted at %%baseUrl%%.
*/
function getIpfsGatewayFunc(baseUrl: string): FetchGatewayFunc {
async function gatewayIpfs(url: string, signal?: FetchCancelSignal): Promise<FetchRequest | FetchResponse> {
try {
const match = url.match(reIpfs);
if (!match) { throw new Error("invalid link"); }
return new FetchRequest(`${ baseUrl }${ match[2] }`);
} catch (error) {
return new FetchResponse(599, "BAD REQUEST (invalid IPFS URI)", { }, null, new FetchRequest(url));
}
}
return gatewayIpfs;
}
const Gateways: Record<string, FetchGatewayFunc> = {
"data": dataGatewayFunc,
"ipfs": getIpfsGatewayFunc("https:/\/gateway.ipfs.io/ipfs/")
};
const fetchSignals: WeakMap<FetchRequest, () => void> = new WeakMap();
/**
* @_ignore
*/
export class FetchCancelSignal {
#listeners: Array<() => void>;
#cancelled: boolean;
constructor(request: FetchRequest) {
this.#listeners = [ ];
this.#cancelled = false;
fetchSignals.set(request, () => {
if (this.#cancelled) { return; }
this.#cancelled = true;
for (const listener of this.#listeners) {
setTimeout(() => { listener(); }, 0);
}
this.#listeners = [ ];
});
}
addListener(listener: () => void): void {
assert(!this.#cancelled, "singal already cancelled", "UNSUPPORTED_OPERATION", {
operation: "fetchCancelSignal.addCancelListener"
});
this.#listeners.push(listener);
}
get cancelled(): boolean { return this.#cancelled; }
checkSignal(): void {
assert(!this.cancelled, "cancelled", "CANCELLED", { });
}
}
// Check the signal, throwing if it is cancelled
function checkSignal(signal?: FetchCancelSignal): FetchCancelSignal {
if (signal == null) { throw new Error("missing signal; should not happen"); }
signal.checkSignal();
return signal;
}
/**
* Represents a request for a resource using a URI.
*
* By default, the supported schemes are ``HTTP``, ``HTTPS``, ``data:``,
* and ``IPFS:``.
*
* Additional schemes can be added globally using [[registerGateway]].
*
* @example:
* req = new FetchRequest("https://www.ricmoo.com")
* resp = await req.send()
* resp.body.length
* //_result:
*/
export class FetchRequest implements Iterable<[ key: string, value: string ]> {
#allowInsecure: boolean;
#gzip: boolean;
#headers: Record<string, string>;
#method: string;
#timeout: number;
#url: string;
#body?: Uint8Array;
#bodyType?: string;
#creds?: string;
// Hooks
#preflight?: null | FetchPreflightFunc;
#process?: null | FetchProcessFunc;
#retry?: null | FetchRetryFunc;
#signal?: FetchCancelSignal;
#throttle: Required<FetchThrottleParams>;
#getUrlFunc: null | FetchGetUrlFunc;
/**
* The fetch URL to request.
*/
get url(): string { return this.#url; }
set url(url: string) {
this.#url = String(url);
}
/**
* The fetch body, if any, to send as the request body. //(default: null)//
*
* When setting a body, the intrinsic ``Content-Type`` is automatically
* set and will be used if **not overridden** by setting a custom
* header.
*
* If %%body%% is null, the body is cleared (along with the
* intrinsic ``Content-Type``).
*
* If %%body%% is a string, the intrinsic ``Content-Type`` is set to
* ``text/plain``.
*
* If %%body%% is a Uint8Array, the intrinsic ``Content-Type`` is set to
* ``application/octet-stream``.
*
* If %%body%% is any other object, the intrinsic ``Content-Type`` is
* set to ``application/json``.
*/
get body(): null | Uint8Array {
if (this.#body == null) { return null; }
return new Uint8Array(this.#body);
}
set body(body: null | string | Readonly<object> | Readonly<Uint8Array>) {
if (body == null) {
this.#body = undefined;
this.#bodyType = undefined;
} else if (typeof(body) === "string") {
this.#body = toUtf8Bytes(body);
this.#bodyType = "text/plain";
} else if (body instanceof Uint8Array) {
this.#body = body;
this.#bodyType = "application/octet-stream";
} else if (typeof(body) === "object") {
this.#body = toUtf8Bytes(JSON.stringify(body));
this.#bodyType = "application/json";
} else {
throw new Error("invalid body");
}
}
/**
* Returns true if the request has a body.
*/
hasBody(): this is (FetchRequest & { body: Uint8Array }) {
return (this.#body != null);
}
/**
* The HTTP method to use when requesting the URI. If no method
* has been explicitly set, then ``GET`` is used if the body is
* null and ``POST`` otherwise.
*/
get method(): string {
if (this.#method) { return this.#method; }
if (this.hasBody()) { return "POST"; }
return "GET";
}
set method(method: null | string) {
if (method == null) { method = ""; }
this.#method = String(method).toUpperCase();
}
/**
* The headers that will be used when requesting the URI. All
* keys are lower-case.
*
* This object is a copy, so any changes will **NOT** be reflected
* in the ``FetchRequest``.
*
* To set a header entry, use the ``setHeader`` method.
*/
get headers(): Record<string, string> {
const headers = Object.assign({ }, this.#headers);
if (this.#creds) {
headers["authorization"] = `Basic ${ encodeBase64(toUtf8Bytes(this.#creds)) }`;
};
if (this.allowGzip) {
headers["accept-encoding"] = "gzip";
}
if (headers["content-type"] == null && this.#bodyType) {
headers["content-type"] = this.#bodyType;
}
if (this.body) { headers["content-length"] = String(this.body.length); }
return headers;
}
/**
* Get the header for %%key%%, ignoring case.
*/
getHeader(key: string): string {
return this.headers[key.toLowerCase()];
}
/**
* Set the header for %%key%% to %%value%%. All values are coerced
* to a string.
*/
setHeader(key: string, value: string | number): void {
this.#headers[String(key).toLowerCase()] = String(value);
}
/**
* Clear all headers, resetting all intrinsic headers.
*/
clearHeaders(): void {
this.#headers = { };
}
[Symbol.iterator](): Iterator<[ key: string, value: string ]> {
const headers = this.headers;
const keys = Object.keys(headers);
let index = 0;
return {
next: () => {
if (index < keys.length) {
const key = keys[index++];
return {
value: [ key, headers[key] ], done: false
}
}
return { value: undefined, done: true };
}
};
}
/**
* The value that will be sent for the ``Authorization`` header.
*
* To set the credentials, use the ``setCredentials`` method.
*/
get credentials(): null | string {
return this.#creds || null;
}
/**
* Sets an ``Authorization`` for %%username%% with %%password%%.
*/
setCredentials(username: string, password: string): void {
assertArgument(!username.match(/:/), "invalid basic authentication username", "username", "[REDACTED]");
this.#creds = `${ username }:${ password }`;
}
/**
* Enable and request gzip-encoded responses. The response will
* automatically be decompressed. //(default: true)//
*/
get allowGzip(): boolean {
return this.#gzip;
}
set allowGzip(value: boolean) {
this.#gzip = !!value;
}
/**
* Allow ``Authentication`` credentials to be sent over insecure
* channels. //(default: false)//
*/
get allowInsecureAuthentication(): boolean {
return !!this.#allowInsecure;
}
set allowInsecureAuthentication(value: boolean) {
this.#allowInsecure = !!value;
}
/**
* The timeout (in milliseconds) to wait for a complete response.
* //(default: 5 minutes)//
*/
get timeout(): number { return this.#timeout; }
set timeout(timeout: number) {
assertArgument(timeout >= 0, "timeout must be non-zero", "timeout", timeout);
this.#timeout = timeout;
}
/**
* This function is called prior to each request, for example
* during a redirection or retry in case of server throttling.
*
* This offers an opportunity to populate headers or update
* content before sending a request.
*/
get preflightFunc(): null | FetchPreflightFunc {
return this.#preflight || null;
}
set preflightFunc(preflight: null | FetchPreflightFunc) {
this.#preflight = preflight;
}
/**
* This function is called after each response, offering an
* opportunity to provide client-level throttling or updating
* response data.
*
* Any error thrown in this causes the ``send()`` to throw.
*
* To schedule a retry attempt (assuming the maximum retry limit
* has not been reached), use [[response.throwThrottleError]].
*/
get processFunc(): null | FetchProcessFunc {
return this.#process || null;
}
set processFunc(process: null | FetchProcessFunc) {
this.#process = process;
}
/**
* This function is called on each retry attempt.
*/
get retryFunc(): null | FetchRetryFunc {
return this.#retry || null;
}
set retryFunc(retry: null | FetchRetryFunc) {
this.#retry = retry;
}
/**
* This function is called to fetch content from HTTP and
* HTTPS URLs and is platform specific (e.g. nodejs vs
* browsers).
*
* This is by default the currently registered global getUrl
* function, which can be changed using [[registerGetUrl]].
* If this has been set, setting is to ``null`` will cause
* this FetchRequest (and any future clones) to revert back to
* using the currently registered global getUrl function.
*
* Setting this is generally not necessary, but may be useful
* for developers that wish to intercept requests or to
* configurege a proxy or other agent.
*/
get getUrlFunc(): FetchGetUrlFunc {
return this.#getUrlFunc || defaultGetUrlFunc;
}
set getUrlFunc(value: null | FetchGetUrlFunc) {
this.#getUrlFunc = value;
}
/**
* Create a new FetchRequest instance with default values.
*
* Once created, each property may be set before issuing a
* ``.send()`` to make the request.
*/
constructor(url: string) {
this.#url = String(url);
this.#allowInsecure = false;
this.#gzip = true;
this.#headers = { };
this.#method = "";
this.#timeout = 300000;
this.#throttle = {
slotInterval: SLOT_INTERVAL,
maxAttempts: MAX_ATTEMPTS
};
this.#getUrlFunc = null;
}
toString(): string {
return `<FetchRequest method=${ JSON.stringify(this.method) } url=${ JSON.stringify(this.url) } headers=${ JSON.stringify(this.headers) } body=${ this.#body ? hexlify(this.#body): "null" }>`;
}
/**
* Update the throttle parameters used to determine maximum
* attempts and exponential-backoff properties.
*/
setThrottleParams(params: FetchThrottleParams): void {
if (params.slotInterval != null) {
this.#throttle.slotInterval = params.slotInterval;
}
if (params.maxAttempts != null) {
this.#throttle.maxAttempts = params.maxAttempts;
}
}
async #send(attempt: number, expires: number, delay: number, _request: FetchRequest, _response: FetchResponse): Promise<FetchResponse> {
if (attempt >= this.#throttle.maxAttempts) {
return _response.makeServerError("exceeded maximum retry limit");
}
assert(getTime() <= expires, "timeout", "TIMEOUT", {
operation: "request.send", reason: "timeout", request: _request
});
if (delay > 0) { await wait(delay); }
let req = this.clone();
const scheme = (req.url.split(":")[0] || "").toLowerCase();
// Process any Gateways
if (scheme in Gateways) {
const result = await Gateways[scheme](req.url, checkSignal(_request.#signal));
if (result instanceof FetchResponse) {
let response = result;
if (this.processFunc) {
checkSignal(_request.#signal);
try {
response = await this.processFunc(req, response);
} catch (error: any) {
// Something went wrong during processing; throw a 5xx server error
if (error.throttle == null || typeof(error.stall) !== "number") {
response.makeServerError("error in post-processing function", error).assertOk();
}
// Ignore throttling
}
}
return response;
}
req = result;
}
// We have a preflight function; update the request
if (this.preflightFunc) { req = await this.preflightFunc(req); }
const resp = await this.getUrlFunc(req, checkSignal(_request.#signal));
let response = new FetchResponse(resp.statusCode, resp.statusMessage, resp.headers, resp.body, _request);
if (response.statusCode === 301 || response.statusCode === 302) {
// Redirect
try {
const location = response.headers.location || "";
return req.redirect(location).#send(attempt + 1, expires, 0, _request, response);
} catch (error) { }
// Things won't get any better on another attempt; abort
return response;
} else if (response.statusCode === 429) {
// Throttle
if (this.retryFunc == null || (await this.retryFunc(req, response, attempt))) {
const retryAfter = response.headers["retry-after"];
let delay = this.#throttle.slotInterval * Math.trunc(Math.random() * Math.pow(2, attempt));
if (typeof(retryAfter) === "string" && retryAfter.match(/^[1-9][0-9]*$/)) {
delay = parseInt(retryAfter);
}
return req.clone().#send(attempt + 1, expires, delay, _request, response);
}
}
if (this.processFunc) {
checkSignal(_request.#signal);
try {
response = await this.processFunc(req, response);
} catch (error: any) {
// Something went wrong during processing; throw a 5xx server error
if (error.throttle == null || typeof(error.stall) !== "number") {
response.makeServerError("error in post-processing function", error).assertOk();
}
// Throttle
let delay = this.#throttle.slotInterval * Math.trunc(Math.random() * Math.pow(2, attempt));;
if (error.stall >= 0) { delay = error.stall; }
return req.clone().#send(attempt + 1, expires, delay, _request, response);
}
}
return response;
}
/**
* Resolves to the response by sending the request.
*/
send(): Promise<FetchResponse> {
assert(this.#signal == null, "request already sent", "UNSUPPORTED_OPERATION", { operation: "fetchRequest.send" });
this.#signal = new FetchCancelSignal(this);
return this.#send(0, getTime() + this.timeout, 0, this, new FetchResponse(0, "", { }, null, this));
}
/**
* Cancels the inflight response, causing a ``CANCELLED``
* error to be rejected from the [[send]].
*/
cancel(): void {
assert(this.#signal != null, "request has not been sent", "UNSUPPORTED_OPERATION", { operation: "fetchRequest.cancel" });
const signal = fetchSignals.get(this);
if (!signal) { throw new Error("missing signal; should not happen"); }
signal();
}
/**
* Returns a new [[FetchRequest]] that represents the redirection
* to %%location%%.
*/
redirect(location: string): FetchRequest {
// Redirection; for now we only support absolute locations
const current = this.url.split(":")[0].toLowerCase();
const target = location.split(":")[0].toLowerCase();
// Don't allow redirecting:
// - non-GET requests
// - downgrading the security (e.g. https => http)
// - to non-HTTP (or non-HTTPS) protocols [this could be relaxed?]
assert(this.method === "GET" && (current !== "https" || target !== "http") && location.match(/^https?:/), `unsupported redirect`, "UNSUPPORTED_OPERATION", {
operation: `redirect(${ this.method } ${ JSON.stringify(this.url) } => ${ JSON.stringify(location) })`
});
// Create a copy of this request, with a new URL
const req = new FetchRequest(location);
req.method = "GET";
req.allowGzip = this.allowGzip;
req.timeout = this.timeout;
req.#headers = Object.assign({ }, this.#headers);
if (this.#body) { req.#body = new Uint8Array(this.#body); }
req.#bodyType = this.#bodyType;
// Do not forward credentials unless on the same domain; only absolute
//req.allowInsecure = false;
// paths are currently supported; may want a way to specify to forward?
//setStore(req.#props, "creds", getStore(this.#pros, "creds"));
return req;
}
/**
* Create a new copy of this request.
*/
clone(): FetchRequest {
const clone = new FetchRequest(this.url);
// Preserve "default method" (i.e. null)
clone.#method = this.#method;
// Preserve "default body" with type, copying the Uint8Array is present
if (this.#body) { clone.#body = this.#body; }
clone.#bodyType = this.#bodyType;
// Preserve "default headers"
clone.#headers = Object.assign({ }, this.#headers);
// Credentials is readonly, so we copy internally
clone.#creds = this.#creds;
if (this.allowGzip) { clone.allowGzip = true; }
clone.timeout = this.timeout;
if (this.allowInsecureAuthentication) { clone.allowInsecureAuthentication = true; }
clone.#preflight = this.#preflight;
clone.#process = this.#process;
clone.#retry = this.#retry;
clone.#throttle = Object.assign({ }, this.#throttle);
clone.#getUrlFunc = this.#getUrlFunc;
return clone;
}
/**
* Locks all static configuration for gateways and FetchGetUrlFunc
* registration.
*/
static lockConfig(): void {
locked = true;
}
/**
* Get the current Gateway function for %%scheme%%.
*/
static getGateway(scheme: string): null | FetchGatewayFunc {
return Gateways[scheme.toLowerCase()] || null;
}
/**
* Use the %%func%% when fetching URIs using %%scheme%%.
*
* This method affects all requests globally.
*
* If [[lockConfig]] has been called, no change is made and this
* throws.
*/
static registerGateway(scheme: string, func: FetchGatewayFunc): void {
scheme = scheme.toLowerCase();
if (scheme === "http" || scheme === "https") {
throw new Error(`cannot intercept ${ scheme }; use registerGetUrl`);
}
if (locked) { throw new Error("gateways locked"); }
Gateways[scheme] = func;
}
/**
* Use %%getUrl%% when fetching URIs over HTTP and HTTPS requests.
*
* This method affects all requests globally.
*
* If [[lockConfig]] has been called, no change is made and this
* throws.
*/
static registerGetUrl(getUrl: FetchGetUrlFunc): void {
if (locked) { throw new Error("gateways locked"); }
defaultGetUrlFunc = getUrl;
}
/**
* Creates a getUrl function that fetches content from HTTP and
* HTTPS URLs.
*
* The available %%options%% are dependent on the platform
* implementation of the default getUrl function.
*
* This is not generally something that is needed, but is useful
* when trying to customize simple behaviour when fetching HTTP
* content.
*/
static createGetUrlFunc(options?: Record<string, any>): FetchGetUrlFunc {
return createGetUrl(options);
}
/**
* Creates a function that can "fetch" data URIs.
*
* Note that this is automatically done internally to support
* data URIs, so it is not necessary to register it.
*
* This is not generally something that is needed, but may
* be useful in a wrapper to perfom custom data URI functionality.
*/
static createDataGateway(): FetchGatewayFunc {
return dataGatewayFunc;
}
/**
* Creates a function that will fetch IPFS (unvalidated) from
* a custom gateway baseUrl.
*
* The default IPFS gateway used internally is
* ``"https:/\/gateway.ipfs.io/ipfs/"``.
*/
static createIpfsGatewayFunc(baseUrl: string): FetchGatewayFunc {
return getIpfsGatewayFunc(baseUrl);
}
}
interface ThrottleError extends Error {
stall: number;
throttle: true;
};
/**
* The response for a FetchRequest.
*/
export class FetchResponse implements Iterable<[ key: string, value: string ]> {
#statusCode: number;
#statusMessage: string;
#headers: Record<string, string>;
#body: null | Readonly<Uint8Array>;
#request: null | FetchRequest;
#error: { error?: Error, message: string };
toString(): string {
return `<FetchResponse status=${ this.statusCode } body=${ this.#body ? hexlify(this.#body): "null" }>`;
}
/**
* The response status code.
*/
get statusCode(): number { return this.#statusCode; }
/**
* The response status message.
*/
get statusMessage(): string { return this.#statusMessage; }
/**
* The response headers. All keys are lower-case.
*/
get headers(): Record<string, string> { return Object.assign({ }, this.#headers); }
/**
* The response body, or ``null`` if there was no body.
*/
get body(): null | Readonly<Uint8Array> {
return (this.#body == null) ? null: new Uint8Array(this.#body);
}
/**
* The response body as a UTF-8 encoded string, or the empty
* string (i.e. ``""``) if there was no body.
*
* An error is thrown if the body is invalid UTF-8 data.
*/
get bodyText(): string {
try {
return (this.#body == null) ? "": toUtf8String(this.#body);
} catch (error) {
assert(false, "response body is not valid UTF-8 data", "UNSUPPORTED_OPERATION", {
operation: "bodyText", info: { response: this }
});
}
}
/**
* The response body, decoded as JSON.
*
* An error is thrown if the body is invalid JSON-encoded data
* or if there was no body.
*/
get bodyJson(): any {
try {
return JSON.parse(this.bodyText);
} catch (error) {
assert(false, "response body is not valid JSON", "UNSUPPORTED_OPERATION", {
operation: "bodyJson", info: { response: this }
});
}
}
[Symbol.iterator](): Iterator<[ key: string, value: string ]> {
const headers = this.headers;
const keys = Object.keys(headers);
let index = 0;
return {
next: () => {
if (index < keys.length) {
const key = keys[index++];
return {
value: [ key, headers[key] ], done: false
}
}
return { value: undefined, done: true };
}
};
}
constructor(statusCode: number, statusMessage: string, headers: Readonly<Record<string, string>>, body: null | Uint8Array, request?: FetchRequest) {
this.#statusCode = statusCode;
this.#statusMessage = statusMessage;
this.#headers = Object.keys(headers).reduce((accum, k) => {
accum[k.toLowerCase()] = String(headers[k]);
return accum;
}, <Record<string, string>>{ });
this.#body = ((body == null) ? null: new Uint8Array(body));
this.#request = (request || null);
this.#error = { message: "" };
}
/**
* Return a Response with matching headers and body, but with
* an error status code (i.e. 599) and %%message%% with an
* optional %%error%%.
*/
makeServerError(message?: string, error?: Error): FetchResponse {
let statusMessage: string;
if (!message) {
message = `${ this.statusCode } ${ this.statusMessage }`;
statusMessage = `CLIENT ESCALATED SERVER ERROR (${ message })`;
} else {
statusMessage = `CLIENT ESCALATED SERVER ERROR (${ this.statusCode } ${ this.statusMessage }; ${ message })`;
}
const response = new FetchResponse(599, statusMessage, this.headers,
this.body, this.#request || undefined);
response.#error = { message, error };
return response;
}
/**
* If called within a [request.processFunc](FetchRequest-processFunc)
* call, causes the request to retry as if throttled for %%stall%%
* milliseconds.
*/
throwThrottleError(message?: string, stall?: number): never {
if (stall == null) {
stall = -1;
} else {
assertArgument(Number.isInteger(stall) && stall >= 0, "invalid stall timeout", "stall", stall);
}
const error = new Error(message || "throttling requests");
defineProperties(<ThrottleError>error, { stall, throttle: true });
throw error;
}
/**
* Get the header value for %%key%%, ignoring case.
*/
getHeader(key: string): string {
return this.headers[key.toLowerCase()];
}
/**
* Returns true if the response has a body.
*/
hasBody(): this is (FetchResponse & { body: Uint8Array }) {
return (this.#body != null);
}
/**
* The request made for this response.
*/
get request(): null | FetchRequest { return this.#request; }
/**
* Returns true if this response was a success statusCode.
*/
ok(): boolean {
return (this.#error.message === "" && this.statusCode >= 200 && this.statusCode < 300);
}
/**
* Throws a ``SERVER_ERROR`` if this response is not ok.
*/
assertOk(): void {
if (this.ok()) { return; }
let { message, error } = this.#error;
if (message === "") {
message = `server response ${ this.statusCode } ${ this.statusMessage }`;
}
let requestUrl: null | string = null;
if (this.request) { requestUrl = this.request.url; }
let responseBody: null | string = null;
try {
if (this.#body) { responseBody = toUtf8String(this.#body); }
} catch (e) { }
assert(false, message, "SERVER_ERROR", {
request: (this.request || "unknown request"), response: this, error,
info: {
requestUrl, responseBody,
responseStatus: `${ this.statusCode } ${ this.statusMessage }` }
});
}
}
function getTime(): number { return (new Date()).getTime(); }
function unpercent(value: string): Uint8Array {
return toUtf8Bytes(value.replace(/%([0-9a-f][0-9a-f])/gi, (all, code) => {
return String.fromCharCode(parseInt(code, 16));
}));
}
function wait(delay: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, delay));
}

643
dev/env/node_modules/ethers/src.ts/utils/fixednumber.ts generated vendored Executable file
View File

@@ -0,0 +1,643 @@
/**
* The **FixedNumber** class permits using values with decimal places,
* using fixed-pont math.
*
* Fixed-point math is still based on integers under-the-hood, but uses an
* internal offset to store fractional components below, and each operation
* corrects for this after each operation.
*
* @_section: api/utils/fixed-point-math:Fixed-Point Maths [about-fixed-point-math]
*/
import { getBytes } from "./data.js";
import { assert, assertArgument, assertPrivate } from "./errors.js";
import {
getBigInt, getNumber, fromTwos, mask, toBigInt
} from "./maths.js";
import { defineProperties } from "./properties.js";
import type { BigNumberish, BytesLike, Numeric } from "./index.js";
const BN_N1 = BigInt(-1);
const BN_0 = BigInt(0);
const BN_1 = BigInt(1);
const BN_5 = BigInt(5);
const _guard = { };
// Constant to pull zeros from for multipliers
let Zeros = "0000";
while (Zeros.length < 80) { Zeros += Zeros; }
// Returns a string "1" followed by decimal "0"s
function getTens(decimals: number): bigint {
let result = Zeros;
while (result.length < decimals) { result += result; }
return BigInt("1" + result.substring(0, decimals));
}
/*
* Returns a new FixedFormat for %%value%%.
*
* If %%value%% is specified as a ``number``, the bit-width is
* 128 bits and %%value%% is used for the ``decimals``.
*
* A string %%value%% may begin with ``fixed`` or ``ufixed``
* for signed and unsigned respectfully. If no other properties
* are specified, the bit-width is 128-bits with 18 decimals.
*
* To specify the bit-width and demicals, append them separated
* by an ``"x"`` to the %%value%%.
*
* For example, ``ufixed128x18`` describes an unsigned, 128-bit
* wide format with 18 decimals.
*
* If %%value%% is an other object, its properties for ``signed``,
* ``width`` and ``decimals`` are checked.
*/
/**
* A description of a fixed-point arithmetic field.
*
* When specifying the fixed format, the values override the default of
* a ``fixed128x18``, which implies a signed 128-bit value with 18
* decimals of precision.
*
* The alias ``fixed`` and ``ufixed`` can be used for ``fixed128x18`` and
* ``ufixed128x18`` respectively.
*
* When a fixed format string begins with a ``u``, it indicates the field
* is unsigned, so any negative values will overflow. The first number
* indicates the bit-width and the second number indicates the decimal
* precision.
*
* When a ``number`` is used for a fixed format, it indicates the number
* of decimal places, and the default width and signed-ness will be used.
*
* The bit-width must be byte aligned and the decimals can be at most 80.
*/
export type FixedFormat = number | string | {
signed?: boolean,
width?: number,
decimals?: number
};
function checkValue(val: bigint, format: _FixedFormat, safeOp?: string): bigint {
const width = BigInt(format.width);
if (format.signed) {
const limit = (BN_1 << (width - BN_1));
assert(safeOp == null || (val >= -limit && val < limit), "overflow", "NUMERIC_FAULT", {
operation: <string>safeOp, fault: "overflow", value: val
});
if (val > BN_0) {
val = fromTwos(mask(val, width), width);
} else {
val = -fromTwos(mask(-val, width), width);
}
} else {
const limit = (BN_1 << width);
assert(safeOp == null || (val >= 0 && val < limit), "overflow", "NUMERIC_FAULT", {
operation: <string>safeOp, fault: "overflow", value: val
});
val = (((val % limit) + limit) % limit) & (limit - BN_1);
}
return val;
}
type _FixedFormat = { signed: boolean, width: number, decimals: number, name: string }
function getFormat(value?: FixedFormat): _FixedFormat {
if (typeof(value) === "number") { value = `fixed128x${value}` }
let signed = true;
let width = 128;
let decimals = 18;
if (typeof(value) === "string") {
// Parse the format string
if (value === "fixed") {
// defaults...
} else if (value === "ufixed") {
signed = false;
} else {
const match = value.match(/^(u?)fixed([0-9]+)x([0-9]+)$/);
assertArgument(match, "invalid fixed format", "format", value);
signed = (match[1] !== "u");
width = parseInt(match[2]);
decimals = parseInt(match[3]);
}
} else if (value) {
// Extract the values from the object
const v: any = value;
const check = (key: string, type: string, defaultValue: any): any => {
if (v[key] == null) { return defaultValue; }
assertArgument(typeof(v[key]) === type,
"invalid fixed format (" + key + " not " + type +")", "format." + key, v[key]);
return v[key];
}
signed = check("signed", "boolean", signed);
width = check("width", "number", width);
decimals = check("decimals", "number", decimals);
}
assertArgument((width % 8) === 0, "invalid FixedNumber width (not byte aligned)", "format.width", width);
assertArgument(decimals <= 80, "invalid FixedNumber decimals (too large)", "format.decimals", decimals);
const name = (signed ? "": "u") + "fixed" + String(width) + "x" + String(decimals);
return { signed, width, decimals, name };
}
function toString(val: bigint, decimals: number) {
let negative = "";
if (val < BN_0) {
negative = "-";
val *= BN_N1;
}
let str = val.toString();
// No decimal point for whole values
if (decimals === 0) { return (negative + str); }
// Pad out to the whole component (including a whole digit)
while (str.length <= decimals) { str = Zeros + str; }
// Insert the decimal point
const index = str.length - decimals;
str = str.substring(0, index) + "." + str.substring(index);
// Trim the whole component (leaving at least one 0)
while (str[0] === "0" && str[1] !== ".") {
str = str.substring(1);
}
// Trim the decimal component (leaving at least one 0)
while (str[str.length - 1] === "0" && str[str.length - 2] !== ".") {
str = str.substring(0, str.length - 1);
}
return (negative + str);
}
/**
* A FixedNumber represents a value over its [[FixedFormat]]
* arithmetic field.
*
* A FixedNumber can be used to perform math, losslessly, on
* values which have decmial places.
*
* A FixedNumber has a fixed bit-width to store values in, and stores all
* values internally by multiplying the value by 10 raised to the power of
* %%decimals%%.
*
* If operations are performed that cause a value to grow too high (close to
* positive infinity) or too low (close to negative infinity), the value
* is said to //overflow//.
*
* For example, an 8-bit signed value, with 0 decimals may only be within
* the range ``-128`` to ``127``; so ``-128 - 1`` will overflow and become
* ``127``. Likewise, ``127 + 1`` will overflow and become ``-127``.
*
* Many operation have a normal and //unsafe// variant. The normal variant
* will throw a [[NumericFaultError]] on any overflow, while the //unsafe//
* variant will silently allow overflow, corrupting its value value.
*
* If operations are performed that cause a value to become too small
* (close to zero), the value loses precison and is said to //underflow//.
*
* For example, a value with 1 decimal place may store a number as small
* as ``0.1``, but the value of ``0.1 / 2`` is ``0.05``, which cannot fit
* into 1 decimal place, so underflow occurs which means precision is lost
* and the value becomes ``0``.
*
* Some operations have a normal and //signalling// variant. The normal
* variant will silently ignore underflow, while the //signalling// variant
* will thow a [[NumericFaultError]] on underflow.
*/
export class FixedNumber {
/**
* The specific fixed-point arithmetic field for this value.
*/
readonly format!: string;
readonly #format: _FixedFormat;
// The actual value (accounting for decimals)
#val: bigint;
// A base-10 value to multiple values by to maintain the magnitude
readonly #tens: bigint;
/**
* This is a property so console.log shows a human-meaningful value.
*
* @private
*/
readonly _value!: string;
// Use this when changing this file to get some typing info,
// but then switch to any to mask the internal type
//constructor(guard: any, value: bigint, format: _FixedFormat) {
/**
* @private
*/
constructor(guard: any, value: bigint, format: any) {
assertPrivate(guard, _guard, "FixedNumber");
this.#val = value;
this.#format = format;
const _value = toString(value, format.decimals);
defineProperties<FixedNumber>(this, { format: format.name, _value });
this.#tens = getTens(format.decimals);
}
/**
* If true, negative values are permitted, otherwise only
* positive values and zero are allowed.
*/
get signed(): boolean { return this.#format.signed; }
/**
* The number of bits available to store the value.
*/
get width(): number { return this.#format.width; }
/**
* The number of decimal places in the fixed-point arithment field.
*/
get decimals(): number { return this.#format.decimals; }
/**
* The value as an integer, based on the smallest unit the
* [[decimals]] allow.
*/
get value(): bigint { return this.#val; }
#checkFormat(other: FixedNumber): void {
assertArgument(this.format === other.format,
"incompatible format; use fixedNumber.toFormat", "other", other);
}
#checkValue(val: bigint, safeOp?: string): FixedNumber {
/*
const width = BigInt(this.width);
if (this.signed) {
const limit = (BN_1 << (width - BN_1));
assert(safeOp == null || (val >= -limit && val < limit), "overflow", "NUMERIC_FAULT", {
operation: <string>safeOp, fault: "overflow", value: val
});
if (val > BN_0) {
val = fromTwos(mask(val, width), width);
} else {
val = -fromTwos(mask(-val, width), width);
}
} else {
const masked = mask(val, width);
assert(safeOp == null || (val >= 0 && val === masked), "overflow", "NUMERIC_FAULT", {
operation: <string>safeOp, fault: "overflow", value: val
});
val = masked;
}
*/
val = checkValue(val, this.#format, safeOp);
return new FixedNumber(_guard, val, this.#format);
}
#add(o: FixedNumber, safeOp?: string): FixedNumber {
this.#checkFormat(o);
return this.#checkValue(this.#val + o.#val, safeOp);
}
/**
* Returns a new [[FixedNumber]] with the result of %%this%% added
* to %%other%%, ignoring overflow.
*/
addUnsafe(other: FixedNumber): FixedNumber { return this.#add(other); }
/**
* Returns a new [[FixedNumber]] with the result of %%this%% added
* to %%other%%. A [[NumericFaultError]] is thrown if overflow
* occurs.
*/
add(other: FixedNumber): FixedNumber { return this.#add(other, "add"); }
#sub(o: FixedNumber, safeOp?: string): FixedNumber {
this.#checkFormat(o);
return this.#checkValue(this.#val - o.#val, safeOp);
}
/**
* Returns a new [[FixedNumber]] with the result of %%other%% subtracted
* from %%this%%, ignoring overflow.
*/
subUnsafe(other: FixedNumber): FixedNumber { return this.#sub(other); }
/**
* Returns a new [[FixedNumber]] with the result of %%other%% subtracted
* from %%this%%. A [[NumericFaultError]] is thrown if overflow
* occurs.
*/
sub(other: FixedNumber): FixedNumber { return this.#sub(other, "sub"); }
#mul(o: FixedNumber, safeOp?: string): FixedNumber {
this.#checkFormat(o);
return this.#checkValue((this.#val * o.#val) / this.#tens, safeOp);
}
/**
* Returns a new [[FixedNumber]] with the result of %%this%% multiplied
* by %%other%%, ignoring overflow and underflow (precision loss).
*/
mulUnsafe(other: FixedNumber): FixedNumber { return this.#mul(other); }
/**
* Returns a new [[FixedNumber]] with the result of %%this%% multiplied
* by %%other%%. A [[NumericFaultError]] is thrown if overflow
* occurs.
*/
mul(other: FixedNumber): FixedNumber { return this.#mul(other, "mul"); }
/**
* Returns a new [[FixedNumber]] with the result of %%this%% multiplied
* by %%other%%. A [[NumericFaultError]] is thrown if overflow
* occurs or if underflow (precision loss) occurs.
*/
mulSignal(other: FixedNumber): FixedNumber {
this.#checkFormat(other);
const value = this.#val * other.#val;
assert((value % this.#tens) === BN_0, "precision lost during signalling mul", "NUMERIC_FAULT", {
operation: "mulSignal", fault: "underflow", value: this
});
return this.#checkValue(value / this.#tens, "mulSignal");
}
#div(o: FixedNumber, safeOp?: string): FixedNumber {
assert(o.#val !== BN_0, "division by zero", "NUMERIC_FAULT", {
operation: "div", fault: "divide-by-zero", value: this
});
this.#checkFormat(o);
return this.#checkValue((this.#val * this.#tens) / o.#val, safeOp);
}
/**
* Returns a new [[FixedNumber]] with the result of %%this%% divided
* by %%other%%, ignoring underflow (precision loss). A
* [[NumericFaultError]] is thrown if overflow occurs.
*/
divUnsafe(other: FixedNumber): FixedNumber { return this.#div(other); }
/**
* Returns a new [[FixedNumber]] with the result of %%this%% divided
* by %%other%%, ignoring underflow (precision loss). A
* [[NumericFaultError]] is thrown if overflow occurs.
*/
div(other: FixedNumber): FixedNumber { return this.#div(other, "div"); }
/**
* Returns a new [[FixedNumber]] with the result of %%this%% divided
* by %%other%%. A [[NumericFaultError]] is thrown if underflow
* (precision loss) occurs.
*/
divSignal(other: FixedNumber): FixedNumber {
assert(other.#val !== BN_0, "division by zero", "NUMERIC_FAULT", {
operation: "div", fault: "divide-by-zero", value: this
});
this.#checkFormat(other);
const value = (this.#val * this.#tens);
assert((value % other.#val) === BN_0, "precision lost during signalling div", "NUMERIC_FAULT", {
operation: "divSignal", fault: "underflow", value: this
});
return this.#checkValue(value / other.#val, "divSignal");
}
/**
* Returns a comparison result between %%this%% and %%other%%.
*
* This is suitable for use in sorting, where ``-1`` implies %%this%%
* is smaller, ``1`` implies %%this%% is larger and ``0`` implies
* both are equal.
*/
cmp(other: FixedNumber): number {
let a = this.value, b = other.value;
// Coerce a and b to the same magnitude
const delta = this.decimals - other.decimals;
if (delta > 0) {
b *= getTens(delta);
} else if (delta < 0) {
a *= getTens(-delta);
}
// Comnpare
if (a < b) { return -1; }
if (a > b) { return 1; }
return 0;
}
/**
* Returns true if %%other%% is equal to %%this%%.
*/
eq(other: FixedNumber): boolean { return this.cmp(other) === 0; }
/**
* Returns true if %%other%% is less than to %%this%%.
*/
lt(other: FixedNumber): boolean { return this.cmp(other) < 0; }
/**
* Returns true if %%other%% is less than or equal to %%this%%.
*/
lte(other: FixedNumber): boolean { return this.cmp(other) <= 0; }
/**
* Returns true if %%other%% is greater than to %%this%%.
*/
gt(other: FixedNumber): boolean { return this.cmp(other) > 0; }
/**
* Returns true if %%other%% is greater than or equal to %%this%%.
*/
gte(other: FixedNumber): boolean { return this.cmp(other) >= 0; }
/**
* Returns a new [[FixedNumber]] which is the largest **integer**
* that is less than or equal to %%this%%.
*
* The decimal component of the result will always be ``0``.
*/
floor(): FixedNumber {
let val = this.#val;
if (this.#val < BN_0) { val -= this.#tens - BN_1; }
val = (this.#val / this.#tens) * this.#tens;
return this.#checkValue(val, "floor");
}
/**
* Returns a new [[FixedNumber]] which is the smallest **integer**
* that is greater than or equal to %%this%%.
*
* The decimal component of the result will always be ``0``.
*/
ceiling(): FixedNumber {
let val = this.#val;
if (this.#val > BN_0) { val += this.#tens - BN_1; }
val = (this.#val / this.#tens) * this.#tens;
return this.#checkValue(val, "ceiling");
}
/**
* Returns a new [[FixedNumber]] with the decimal component
* rounded up on ties at %%decimals%% places.
*/
round(decimals?: number): FixedNumber {
if (decimals == null) { decimals = 0; }
// Not enough precision to not already be rounded
if (decimals >= this.decimals) { return this; }
const delta = this.decimals - decimals;
const bump = BN_5 * getTens(delta - 1);
let value = this.value + bump;
const tens = getTens(delta);
value = (value / tens) * tens;
checkValue(value, this.#format, "round");
return new FixedNumber(_guard, value, this.#format);
}
/**
* Returns true if %%this%% is equal to ``0``.
*/
isZero(): boolean { return (this.#val === BN_0); }
/**
* Returns true if %%this%% is less than ``0``.
*/
isNegative(): boolean { return (this.#val < BN_0); }
/**
* Returns the string representation of %%this%%.
*/
toString(): string { return this._value; }
/**
* Returns a float approximation.
*
* Due to IEEE 754 precission (or lack thereof), this function
* can only return an approximation and most values will contain
* rounding errors.
*/
toUnsafeFloat(): number { return parseFloat(this.toString()); }
/**
* Return a new [[FixedNumber]] with the same value but has had
* its field set to %%format%%.
*
* This will throw if the value cannot fit into %%format%%.
*/
toFormat(format: FixedFormat): FixedNumber {
return FixedNumber.fromString(this.toString(), format);
}
/**
* Creates a new [[FixedNumber]] for %%value%% divided by
* %%decimal%% places with %%format%%.
*
* This will throw a [[NumericFaultError]] if %%value%% (once adjusted
* for %%decimals%%) cannot fit in %%format%%, either due to overflow
* or underflow (precision loss).
*/
static fromValue(_value: BigNumberish, _decimals?: Numeric, _format?: FixedFormat): FixedNumber {
const decimals = (_decimals == null) ? 0: getNumber(_decimals);
const format = getFormat(_format);
let value = getBigInt(_value, "value");
const delta = decimals - format.decimals;
if (delta > 0) {
const tens = getTens(delta);
assert((value % tens) === BN_0, "value loses precision for format", "NUMERIC_FAULT", {
operation: "fromValue", fault: "underflow", value: _value
});
value /= tens;
} else if (delta < 0) {
value *= getTens(-delta);
}
checkValue(value, format, "fromValue");
return new FixedNumber(_guard, value, format);
}
/**
* Creates a new [[FixedNumber]] for %%value%% with %%format%%.
*
* This will throw a [[NumericFaultError]] if %%value%% cannot fit
* in %%format%%, either due to overflow or underflow (precision loss).
*/
static fromString(_value: string, _format?: FixedFormat): FixedNumber {
const match = _value.match(/^(-?)([0-9]*)\.?([0-9]*)$/);
assertArgument(match && (match[2].length + match[3].length) > 0, "invalid FixedNumber string value", "value", _value);
const format = getFormat(_format);
let whole = (match[2] || "0"), decimal = (match[3] || "");
// Pad out the decimals
while (decimal.length < format.decimals) { decimal += Zeros; }
// Check precision is safe
assert(decimal.substring(format.decimals).match(/^0*$/), "too many decimals for format", "NUMERIC_FAULT", {
operation: "fromString", fault: "underflow", value: _value
});
// Remove extra padding
decimal = decimal.substring(0, format.decimals);
const value = BigInt(match[1] + whole + decimal)
checkValue(value, format, "fromString");
return new FixedNumber(_guard, value, format);
}
/**
* Creates a new [[FixedNumber]] with the big-endian representation
* %%value%% with %%format%%.
*
* This will throw a [[NumericFaultError]] if %%value%% cannot fit
* in %%format%% due to overflow.
*/
static fromBytes(_value: BytesLike, _format?: FixedFormat): FixedNumber {
let value = toBigInt(getBytes(_value, "value"));
const format = getFormat(_format);
if (format.signed) { value = fromTwos(value, format.width); }
checkValue(value, format, "fromBytes");
return new FixedNumber(_guard, value, format);
}
}
//const f1 = FixedNumber.fromString("12.56", "fixed16x2");
//const f2 = FixedNumber.fromString("0.3", "fixed16x2");
//console.log(f1.divSignal(f2));
//const BUMP = FixedNumber.from("0.5");

81
dev/env/node_modules/ethers/src.ts/utils/geturl-browser.ts generated vendored Executable file
View File

@@ -0,0 +1,81 @@
import { assert, makeError } from "./errors.js";
import type {
FetchGetUrlFunc, FetchRequest, FetchCancelSignal, GetUrlResponse
} from "./fetch.js";
export function createGetUrl(options?: Record<string, any>): FetchGetUrlFunc {
async function getUrl(req: FetchRequest, _signal?: FetchCancelSignal): Promise<GetUrlResponse> {
assert(_signal == null || !_signal.cancelled, "request cancelled before sending", "CANCELLED");
const protocol = req.url.split(":")[0].toLowerCase();
assert(protocol === "http" || protocol === "https", `unsupported protocol ${ protocol }`, "UNSUPPORTED_OPERATION", {
info: { protocol },
operation: "request"
});
assert(protocol === "https" || !req.credentials || req.allowInsecureAuthentication, "insecure authorized connections unsupported", "UNSUPPORTED_OPERATION", {
operation: "request"
});
let error: null | Error = null;
const controller = new AbortController();
const timer = setTimeout(() => {
error = makeError("request timeout", "TIMEOUT");
controller.abort();
}, req.timeout);
if (_signal) {
_signal.addListener(() => {
error = makeError("request cancelled", "CANCELLED");
controller.abort();
});
}
const init = Object.assign({ }, options, {
method: req.method,
headers: new Headers(Array.from(req)),
body: req.body || undefined,
signal: controller.signal
});
let resp: Awaited<ReturnType<typeof fetch>>;
try {
resp = await fetch(req.url, init);
} catch (_error) {
clearTimeout(timer);
if (error) { throw error; }
throw _error;
}
clearTimeout(timer);
const headers: Record<string, string> = { };
resp.headers.forEach((value, key) => {
headers[key.toLowerCase()] = value;
});
const respBody = await resp.arrayBuffer();
const body = (respBody == null) ? null: new Uint8Array(respBody);
return {
statusCode: resp.status,
statusMessage: resp.statusText,
headers, body
};
}
return getUrl;
}
// @TODO: remove in v7; provided for backwards compat
const defaultGetUrl: FetchGetUrlFunc = createGetUrl({ });
export async function getUrl(req: FetchRequest, _signal?: FetchCancelSignal): Promise<GetUrlResponse> {
return defaultGetUrl(req, _signal);
}

141
dev/env/node_modules/ethers/src.ts/utils/geturl.ts generated vendored Executable file
View File

@@ -0,0 +1,141 @@
import http from "http";
import https from "https";
import { gunzipSync } from "zlib";
import { assert, makeError } from "./errors.js";
import { getBytes } from "./data.js";
import type {
FetchGetUrlFunc, FetchRequest, FetchCancelSignal, GetUrlResponse
} from "./fetch.js";
/**
* @_ignore:
*/
export function createGetUrl(options?: Record<string, any>): FetchGetUrlFunc {
async function getUrl(req: FetchRequest, signal?: FetchCancelSignal): Promise<GetUrlResponse> {
// Make sure we weren't cancelled before sending
assert(signal == null || !signal.cancelled, "request cancelled before sending", "CANCELLED");
const protocol = req.url.split(":")[0].toLowerCase();
assert(protocol === "http" || protocol === "https", `unsupported protocol ${ protocol }`, "UNSUPPORTED_OPERATION", {
info: { protocol },
operation: "request"
});
assert(protocol === "https" || !req.credentials || req.allowInsecureAuthentication, "insecure authorized connections unsupported", "UNSUPPORTED_OPERATION", {
operation: "request"
});
const method = req.method;
const headers = Object.assign({ }, req.headers);
const reqOptions: any = { method, headers };
if (options) {
if (options.agent) { reqOptions.agent = options.agent; }
}
// Create a Node-specific AbortController, if available
let abort: null | AbortController = null;
try {
abort = new AbortController();
reqOptions.abort = abort.signal;
} catch (e) { console.log(e); }
const request = ((protocol === "http") ? http: https).request(req.url, reqOptions);
request.setTimeout(req.timeout);
const body = req.body;
if (body) { request.write(Buffer.from(body)); }
request.end();
return new Promise((resolve, reject) => {
if (signal) {
signal.addListener(() => {
if (abort) { abort.abort(); }
reject(makeError("request cancelled", "CANCELLED"));
});
}
request.on("timeout", () => {
reject(makeError("request timeout", "TIMEOUT"));
});
request.once("response", (resp: http.IncomingMessage) => {
const statusCode = resp.statusCode || 0;
const statusMessage = resp.statusMessage || "";
const headers = Object.keys(resp.headers || {}).reduce((accum, name) => {
let value = resp.headers[name] || "";
if (Array.isArray(value)) {
value = value.join(", ");
}
accum[name] = value;
return accum;
}, <{ [ name: string ]: string }>{ });
let body: null | Uint8Array = null;
//resp.setEncoding("utf8");
resp.on("data", (chunk: Uint8Array) => {
if (signal) {
try {
signal.checkSignal();
} catch (error) {
return reject(error);
}
}
if (body == null) {
body = chunk;
} else {
const newBody = new Uint8Array(body.length + chunk.length);
newBody.set(body, 0);
newBody.set(chunk, body.length);
body = newBody;
}
});
resp.on("end", () => {
try {
if (headers["content-encoding"] === "gzip" && body) {
body = getBytes(gunzipSync(body));
}
resolve({ statusCode, statusMessage, headers, body });
} catch (error) {
reject(makeError("bad response data", "SERVER_ERROR", {
request: req, info: { response: resp, error }
}));
}
});
resp.on("error", (error) => {
//@TODO: Should this just return nornal response with a server error?
(<any>error).response = { statusCode, statusMessage, headers, body };
reject(error);
});
});
request.on("error", (error) => { reject(error); });
});
}
return getUrl;
}
// @TODO: remove in v7; provided for backwards compat
const defaultGetUrl: FetchGetUrlFunc = createGetUrl({ });
/**
* @_ignore:
*/
export async function getUrl(req: FetchRequest, signal?: FetchCancelSignal): Promise<GetUrlResponse> {
return defaultGetUrl(req, signal);
}

95
dev/env/node_modules/ethers/src.ts/utils/index.ts generated vendored Executable file
View File

@@ -0,0 +1,95 @@
/**
* There are many simple utilities required to interact with
* Ethereum and to simplify the library, without increasing
* the library dependencies for simple functions.
*
* @_section api/utils:Utilities [about-utils]
*/
export { decodeBase58, encodeBase58 } from "./base58.js";
export { decodeBase64, encodeBase64 } from "./base64.js";
export {
getBytes, getBytesCopy, isHexString, isBytesLike, hexlify, concat, dataLength, dataSlice,
stripZerosLeft, zeroPadValue, zeroPadBytes
} from "./data.js";
export {
isCallException, isError,
assert, assertArgument, assertArgumentCount, assertPrivate, assertNormalize, makeError
} from "./errors.js"
export { EventPayload } from "./events.js";
export {
FetchRequest, FetchResponse, FetchCancelSignal,
} from "./fetch.js";
export { FixedNumber } from "./fixednumber.js"
export {
fromTwos, toTwos, mask,
getBigInt, getNumber, getUint, toBigInt, toNumber, toBeHex, toBeArray, toQuantity
} from "./maths.js";
export { resolveProperties, defineProperties} from "./properties.js";
export { decodeRlp } from "./rlp-decode.js";
export { encodeRlp } from "./rlp-encode.js";
export { formatEther, parseEther, formatUnits, parseUnits } from "./units.js";
export {
toUtf8Bytes,
toUtf8CodePoints,
toUtf8String,
Utf8ErrorFuncs,
} from "./utf8.js";
export { uuidV4 } from "./uuid.js";
/////////////////////////////
// Types
export type { BytesLike } from "./data.js";
export type {
//ErrorFetchRequestWithBody, ErrorFetchRequest,
//ErrorFetchResponseWithBody, ErrorFetchResponse,
ErrorCode,
EthersError, UnknownError, NotImplementedError, UnsupportedOperationError, NetworkError,
ServerError, TimeoutError, BadDataError, CancelledError, BufferOverrunError,
NumericFaultError, InvalidArgumentError, MissingArgumentError, UnexpectedArgumentError,
CallExceptionError, InsufficientFundsError, NonceExpiredError, OffchainFaultError,
ReplacementUnderpricedError, TransactionReplacedError, UnconfiguredNameError,
ActionRejectedError,
CallExceptionAction, CallExceptionTransaction,
CodedEthersError
} from "./errors.js"
export type { EventEmitterable, Listener } from "./events.js";
export type {
GetUrlResponse,
FetchPreflightFunc, FetchProcessFunc, FetchRetryFunc,
FetchGatewayFunc, FetchGetUrlFunc
} from "./fetch.js";
export type { FixedFormat } from "./fixednumber.js"
export type { BigNumberish, Numeric } from "./maths.js";
export type { RlpStructuredData, RlpStructuredDataish } from "./rlp.js";
export type {
Utf8ErrorFunc,
UnicodeNormalizationForm,
Utf8ErrorReason
} from "./utf8.js";

259
dev/env/node_modules/ethers/src.ts/utils/maths.ts generated vendored Executable file
View File

@@ -0,0 +1,259 @@
/**
* Some mathematic operations.
*
* @_subsection: api/utils:Math Helpers [about-maths]
*/
import { hexlify, isBytesLike } from "./data.js";
import { assert, assertArgument } from "./errors.js";
import type { BytesLike } from "./data.js";
/**
* Any type that can be used where a numeric value is needed.
*/
export type Numeric = number | bigint;
/**
* Any type that can be used where a big number is needed.
*/
export type BigNumberish = string | Numeric;
const BN_0 = BigInt(0);
const BN_1 = BigInt(1);
//const BN_Max256 = (BN_1 << BigInt(256)) - BN_1;
// IEEE 754 support 53-bits of mantissa
const maxValue = 0x1fffffffffffff;
/**
* Convert %%value%% from a twos-compliment representation of %%width%%
* bits to its value.
*
* If the highest bit is ``1``, the result will be negative.
*/
export function fromTwos(_value: BigNumberish, _width: Numeric): bigint {
const value = getUint(_value, "value");
const width = BigInt(getNumber(_width, "width"));
assert((value >> width) === BN_0, "overflow", "NUMERIC_FAULT", {
operation: "fromTwos", fault: "overflow", value: _value
});
// Top bit set; treat as a negative value
if (value >> (width - BN_1)) {
const mask = (BN_1 << width) - BN_1;
return -(((~value) & mask) + BN_1);
}
return value;
}
/**
* Convert %%value%% to a twos-compliment representation of
* %%width%% bits.
*
* The result will always be positive.
*/
export function toTwos(_value: BigNumberish, _width: Numeric): bigint {
let value = getBigInt(_value, "value");
const width = BigInt(getNumber(_width, "width"));
const limit = (BN_1 << (width - BN_1));
if (value < BN_0) {
value = -value;
assert(value <= limit, "too low", "NUMERIC_FAULT", {
operation: "toTwos", fault: "overflow", value: _value
});
const mask = (BN_1 << width) - BN_1;
return ((~value) & mask) + BN_1;
} else {
assert(value < limit, "too high", "NUMERIC_FAULT", {
operation: "toTwos", fault: "overflow", value: _value
});
}
return value;
}
/**
* Mask %%value%% with a bitmask of %%bits%% ones.
*/
export function mask(_value: BigNumberish, _bits: Numeric): bigint {
const value = getUint(_value, "value");
const bits = BigInt(getNumber(_bits, "bits"));
return value & ((BN_1 << bits) - BN_1);
}
/**
* Gets a BigInt from %%value%%. If it is an invalid value for
* a BigInt, then an ArgumentError will be thrown for %%name%%.
*/
export function getBigInt(value: BigNumberish, name?: string): bigint {
switch (typeof(value)) {
case "bigint": return value;
case "number":
assertArgument(Number.isInteger(value), "underflow", name || "value", value);
assertArgument(value >= -maxValue && value <= maxValue, "overflow", name || "value", value);
return BigInt(value);
case "string":
try {
if (value === "") { throw new Error("empty string"); }
if (value[0] === "-" && value[1] !== "-") {
return -BigInt(value.substring(1));
}
return BigInt(value);
} catch(e: any) {
assertArgument(false, `invalid BigNumberish string: ${ e.message }`, name || "value", value);
}
}
assertArgument(false, "invalid BigNumberish value", name || "value", value);
}
/**
* Returns %%value%% as a bigint, validating it is valid as a bigint
* value and that it is positive.
*/
export function getUint(value: BigNumberish, name?: string): bigint {
const result = getBigInt(value, name);
assert(result >= BN_0, "unsigned value cannot be negative", "NUMERIC_FAULT", {
fault: "overflow", operation: "getUint", value
});
return result;
}
const Nibbles = "0123456789abcdef";
/*
* Converts %%value%% to a BigInt. If %%value%% is a Uint8Array, it
* is treated as Big Endian data.
*/
export function toBigInt(value: BigNumberish | Uint8Array): bigint {
if (value instanceof Uint8Array) {
let result = "0x0";
for (const v of value) {
result += Nibbles[v >> 4];
result += Nibbles[v & 0x0f];
}
return BigInt(result);
}
return getBigInt(value);
}
/**
* Gets a //number// from %%value%%. If it is an invalid value for
* a //number//, then an ArgumentError will be thrown for %%name%%.
*/
export function getNumber(value: BigNumberish, name?: string): number {
switch (typeof(value)) {
case "bigint":
assertArgument(value >= -maxValue && value <= maxValue, "overflow", name || "value", value);
return Number(value);
case "number":
assertArgument(Number.isInteger(value), "underflow", name || "value", value);
assertArgument(value >= -maxValue && value <= maxValue, "overflow", name || "value", value);
return value;
case "string":
try {
if (value === "") { throw new Error("empty string"); }
return getNumber(BigInt(value), name);
} catch(e: any) {
assertArgument(false, `invalid numeric string: ${ e.message }`, name || "value", value);
}
}
assertArgument(false, "invalid numeric value", name || "value", value);
}
/**
* Converts %%value%% to a number. If %%value%% is a Uint8Array, it
* is treated as Big Endian data. Throws if the value is not safe.
*/
export function toNumber(value: BigNumberish | Uint8Array): number {
return getNumber(toBigInt(value));
}
/**
* Converts %%value%% to a Big Endian hexstring, optionally padded to
* %%width%% bytes.
*/
export function toBeHex(_value: BigNumberish, _width?: Numeric): string {
const value = getUint(_value, "value");
let result = value.toString(16);
if (_width == null) {
// Ensure the value is of even length
if (result.length % 2) { result = "0" + result; }
} else {
const width = getNumber(_width, "width");
// Special case when both value and width are 0 (see: #5025)
if (width === 0 && value === BN_0) { return "0x"; }
assert(width * 2 >= result.length, `value exceeds width (${ width } bytes)`, "NUMERIC_FAULT", {
operation: "toBeHex",
fault: "overflow",
value: _value
});
// Pad the value to the required width
while (result.length < (width * 2)) { result = "0" + result; }
}
return "0x" + result;
}
/**
* Converts %%value%% to a Big Endian Uint8Array.
*/
export function toBeArray(_value: BigNumberish, _width?: Numeric): Uint8Array {
const value = getUint(_value, "value");
if (value === BN_0) {
const width = (_width != null) ? getNumber(_width, "width"): 0;
return new Uint8Array(width);
}
let hex = value.toString(16);
if (hex.length % 2) { hex = "0" + hex; }
if (_width != null) {
const width = getNumber(_width, "width");
while (hex.length < (width * 2)) { hex = "00" + hex; }
assert((width * 2) === hex.length, `value exceeds width (${ width } bytes)`, "NUMERIC_FAULT", {
operation: "toBeArray",
fault: "overflow",
value: _value
});
}
const result = new Uint8Array(hex.length / 2);
for (let i = 0; i < result.length; i++) {
const offset = i * 2;
result[i] = parseInt(hex.substring(offset, offset + 2), 16);
}
return result;
}
/**
* Returns a [[HexString]] for %%value%% safe to use as a //Quantity//.
*
* A //Quantity// does not have and leading 0 values unless the value is
* the literal value `0x0`. This is most commonly used for JSSON-RPC
* numeric values.
*/
export function toQuantity(value: BytesLike | BigNumberish): string {
let result = hexlify(isBytesLike(value) ? value: toBeArray(value)).substring(2);
while (result.startsWith("0")) { result = result.substring(1); }
if (result === "") { result = "0"; }
return "0x" + result;
}

60
dev/env/node_modules/ethers/src.ts/utils/properties.ts generated vendored Executable file
View File

@@ -0,0 +1,60 @@
/**
* Property helper functions.
*
* @_subsection api/utils:Properties [about-properties]
*/
function checkType(value: any, type: string, name: string): void {
const types = type.split("|").map(t => t.trim());
for (let i = 0; i < types.length; i++) {
switch (type) {
case "any":
return;
case "bigint":
case "boolean":
case "number":
case "string":
if (typeof(value) === type) { return; }
}
}
const error: any = new Error(`invalid value for type ${ type }`);
error.code = "INVALID_ARGUMENT";
error.argument = `value.${ name }`;
error.value = value;
throw error;
}
/**
* Resolves to a new object that is a copy of %%value%%, but with all
* values resolved.
*/
export async function resolveProperties<T>(value: { [ P in keyof T ]: T[P] | Promise<T[P]>}): Promise<T> {
const keys = Object.keys(value);
const results = await Promise.all(keys.map((k) => Promise.resolve(value[<keyof T>k])));
return results.reduce((accum: any, v, index) => {
accum[keys[index]] = v;
return accum;
}, <{ [ P in keyof T]: T[P] }>{ });
}
/**
* Assigns the %%values%% to %%target%% as read-only values.
*
* It %%types%% is specified, the values are checked.
*/
export function defineProperties<T>(
target: T,
values: { [ K in keyof T ]?: T[K] },
types?: { [ K in keyof T ]?: string }): void {
for (let key in values) {
let value = values[key];
const type = (types ? types[key]: null);
if (type) { checkType(value, type, key); }
Object.defineProperty(target, key, { enumerable: true, value, writable: false });
}
}

104
dev/env/node_modules/ethers/src.ts/utils/rlp-decode.ts generated vendored Executable file
View File

@@ -0,0 +1,104 @@
//See: https://github.com/ethereum/wiki/wiki/RLP
import { hexlify } from "./data.js";
import { assert, assertArgument } from "./errors.js";
import { getBytes } from "./data.js";
import type { BytesLike, RlpStructuredData } from "./index.js";
function hexlifyByte(value: number): string {
let result = value.toString(16);
while (result.length < 2) { result = "0" + result; }
return "0x" + result;
}
function unarrayifyInteger(data: Uint8Array, offset: number, length: number): number {
let result = 0;
for (let i = 0; i < length; i++) {
result = (result * 256) + data[offset + i];
}
return result;
}
type Decoded = {
result: any;
consumed: number;
};
function _decodeChildren(data: Uint8Array, offset: number, childOffset: number, length: number): Decoded {
const result: Array<any> = [];
while (childOffset < offset + 1 + length) {
const decoded = _decode(data, childOffset);
result.push(decoded.result);
childOffset += decoded.consumed;
assert(childOffset <= offset + 1 + length, "child data too short", "BUFFER_OVERRUN", {
buffer: data, length, offset
});
}
return {consumed: (1 + length), result: result};
}
// returns { consumed: number, result: Object }
function _decode(data: Uint8Array, offset: number): { consumed: number, result: any } {
assert(data.length !== 0, "data too short", "BUFFER_OVERRUN", {
buffer: data, length: 0, offset: 1
});
const checkOffset = (offset: number) => {
assert(offset <= data.length, "data short segment too short", "BUFFER_OVERRUN", {
buffer: data, length: data.length, offset
});
};
// Array with extra length prefix
if (data[offset] >= 0xf8) {
const lengthLength = data[offset] - 0xf7;
checkOffset(offset + 1 + lengthLength);
const length = unarrayifyInteger(data, offset + 1, lengthLength);
checkOffset(offset + 1 + lengthLength + length);
return _decodeChildren(data, offset, offset + 1 + lengthLength, lengthLength + length);
} else if (data[offset] >= 0xc0) {
const length = data[offset] - 0xc0;
checkOffset(offset + 1 + length);
return _decodeChildren(data, offset, offset + 1, length);
} else if (data[offset] >= 0xb8) {
const lengthLength = data[offset] - 0xb7;
checkOffset(offset + 1 + lengthLength);
const length = unarrayifyInteger(data, offset + 1, lengthLength);
checkOffset(offset + 1 + lengthLength + length);
const result = hexlify(data.slice(offset + 1 + lengthLength, offset + 1 + lengthLength + length));
return { consumed: (1 + lengthLength + length), result: result }
} else if (data[offset] >= 0x80) {
const length = data[offset] - 0x80;
checkOffset(offset + 1 + length);
const result = hexlify(data.slice(offset + 1, offset + 1 + length));
return { consumed: (1 + length), result: result }
}
return { consumed: 1, result: hexlifyByte(data[offset]) };
}
/**
* Decodes %%data%% into the structured data it represents.
*/
export function decodeRlp(_data: BytesLike): RlpStructuredData {
const data = getBytes(_data, "data");
const decoded = _decode(data, 0);
assertArgument(decoded.consumed === data.length, "unexpected junk after rlp payload", "data", _data);
return decoded.result;
}

64
dev/env/node_modules/ethers/src.ts/utils/rlp-encode.ts generated vendored Executable file
View File

@@ -0,0 +1,64 @@
//See: https://github.com/ethereum/wiki/wiki/RLP
import { getBytes } from "./data.js";
import type { RlpStructuredDataish } from "./rlp.js";
function arrayifyInteger(value: number): Array<number> {
const result: Array<number> = [];
while (value) {
result.unshift(value & 0xff);
value >>= 8;
}
return result;
}
function _encode(object: Array<any> | string | Uint8Array): Array<number> {
if (Array.isArray(object)) {
let payload: Array<number> = [];
object.forEach(function(child) {
payload = payload.concat(_encode(child));
});
if (payload.length <= 55) {
payload.unshift(0xc0 + payload.length)
return payload;
}
const length = arrayifyInteger(payload.length);
length.unshift(0xf7 + length.length);
return length.concat(payload);
}
const data: Array<number> = Array.prototype.slice.call(getBytes(object, "object"));
if (data.length === 1 && data[0] <= 0x7f) {
return data;
} else if (data.length <= 55) {
data.unshift(0x80 + data.length);
return data;
}
const length = arrayifyInteger(data.length);
length.unshift(0xb7 + length.length);
return length.concat(data);
}
const nibbles = "0123456789abcdef";
/**
* Encodes %%object%% as an RLP-encoded [[DataHexString]].
*/
export function encodeRlp(object: RlpStructuredDataish): string {
let result = "0x";
for (const v of _encode(object)) {
result += nibbles[v >> 4];
result += nibbles[v & 0xf];
}
return result;
}

20
dev/env/node_modules/ethers/src.ts/utils/rlp.ts generated vendored Executable file
View File

@@ -0,0 +1,20 @@
/**
* The [[link-rlp]] (RLP) encoding is used throughout Ethereum
* to serialize nested structures of Arrays and data.
*
* @_subsection api/utils:Recursive-Length Prefix [about-rlp]
*/
export { decodeRlp } from "./rlp-decode.js";
export { encodeRlp } from "./rlp-encode.js";
/**
* An RLP-encoded structure.
*/
export type RlpStructuredData = string | Array<RlpStructuredData>;
/**
* An RLP-encoded structure, which allows Uint8Array.
*/
export type RlpStructuredDataish = string | Uint8Array | Array<RlpStructuredDataish>;

0
dev/env/node_modules/ethers/src.ts/utils/test.txt generated vendored Executable file
View File

91
dev/env/node_modules/ethers/src.ts/utils/units.ts generated vendored Executable file
View File

@@ -0,0 +1,91 @@
/**
* Most interactions with Ethereum requires integer values, which use
* the smallest magnitude unit.
*
* For example, imagine dealing with dollars and cents. Since dollars
* are divisible, non-integer values are possible, such as ``$10.77``.
* By using the smallest indivisible unit (i.e. cents), the value can
* be kept as the integer ``1077``.
*
* When receiving decimal input from the user (as a decimal string),
* the value should be converted to an integer and when showing a user
* a value, the integer value should be converted to a decimal string.
*
* This creates a clear distinction, between values to be used by code
* (integers) and values used for display logic to users (decimals).
*
* The native unit in Ethereum, //ether// is divisible to 18 decimal places,
* where each individual unit is called a //wei//.
*
* @_subsection api/utils:Unit Conversion [about-units]
*/
import { assertArgument } from "./errors.js";
import { FixedNumber } from "./fixednumber.js";
import { getNumber } from "./maths.js";
import type { BigNumberish, Numeric } from "../utils/index.js";
const names = [
"wei",
"kwei",
"mwei",
"gwei",
"szabo",
"finney",
"ether",
];
/**
* Converts %%value%% into a //decimal string//, assuming %%unit%% decimal
* places. The %%unit%% may be the number of decimal places or the name of
* a unit (e.g. ``"gwei"`` for 9 decimal places).
*
*/
export function formatUnits(value: BigNumberish, unit?: string | Numeric): string {
let decimals = 18;
if (typeof(unit) === "string") {
const index = names.indexOf(unit);
assertArgument(index >= 0, "invalid unit", "unit", unit);
decimals = 3 * index;
} else if (unit != null) {
decimals = getNumber(unit, "unit");
}
return FixedNumber.fromValue(value, decimals, { decimals, width: 512 }).toString();
}
/**
* Converts the //decimal string// %%value%% to a BigInt, assuming
* %%unit%% decimal places. The %%unit%% may the number of decimal places
* or the name of a unit (e.g. ``"gwei"`` for 9 decimal places).
*/
export function parseUnits(value: string, unit?: string | Numeric): bigint {
assertArgument(typeof(value) === "string", "value must be a string", "value", value);
let decimals = 18;
if (typeof(unit) === "string") {
const index = names.indexOf(unit);
assertArgument(index >= 0, "invalid unit", "unit", unit);
decimals = 3 * index;
} else if (unit != null) {
decimals = getNumber(unit, "unit");
}
return FixedNumber.fromString(value, { decimals, width: 512 }).value;
}
/**
* Converts %%value%% into a //decimal string// using 18 decimal places.
*/
export function formatEther(wei: BigNumberish): string {
return formatUnits(wei, 18);
}
/**
* Converts the //decimal string// %%ether%% to a BigInt, using 18
* decimal places.
*/
export function parseEther(ether: string): bigint {
return parseUnits(ether, 18);
}

325
dev/env/node_modules/ethers/src.ts/utils/utf8.ts generated vendored Executable file
View File

@@ -0,0 +1,325 @@
/**
* Using strings in Ethereum (or any security-basd system) requires
* additional care. These utilities attempt to mitigate some of the
* safety issues as well as provide the ability to recover and analyse
* strings.
*
* @_subsection api/utils:Strings and UTF-8 [about-strings]
*/
import { getBytes } from "./data.js";
import { assertArgument, assertNormalize } from "./errors.js";
import type { BytesLike } from "./index.js";
///////////////////////////////
/**
* The stanard normalization forms.
*/
export type UnicodeNormalizationForm = "NFC" | "NFD" | "NFKC" | "NFKD";
/**
* When using the UTF-8 error API the following errors can be intercepted
* and processed as the %%reason%% passed to the [[Utf8ErrorFunc]].
*
* **``"UNEXPECTED_CONTINUE"``** - a continuation byte was present where there
* was nothing to continue.
*
* **``"BAD_PREFIX"``** - an invalid (non-continuation) byte to start a
* UTF-8 codepoint was found.
*
* **``"OVERRUN"``** - the string is too short to process the expected
* codepoint length.
*
* **``"MISSING_CONTINUE"``** - a missing continuation byte was expected but
* not found. The %%offset%% indicates the index the continuation byte
* was expected at.
*
* **``"OUT_OF_RANGE"``** - the computed code point is outside the range
* for UTF-8. The %%badCodepoint%% indicates the computed codepoint, which was
* outside the valid UTF-8 range.
*
* **``"UTF16_SURROGATE"``** - the UTF-8 strings contained a UTF-16 surrogate
* pair. The %%badCodepoint%% is the computed codepoint, which was inside the
* UTF-16 surrogate range.
*
* **``"OVERLONG"``** - the string is an overlong representation. The
* %%badCodepoint%% indicates the computed codepoint, which has already
* been bounds checked.
*
*
* @returns string
*/
export type Utf8ErrorReason = "UNEXPECTED_CONTINUE" | "BAD_PREFIX" | "OVERRUN" |
"MISSING_CONTINUE" | "OUT_OF_RANGE" | "UTF16_SURROGATE" | "OVERLONG";
/**
* A callback that can be used with [[toUtf8String]] to analysis or
* recovery from invalid UTF-8 data.
*
* Parsing UTF-8 data is done through a simple Finite-State Machine (FSM)
* which calls the ``Utf8ErrorFunc`` if a fault is detected.
*
* The %%reason%% indicates where in the FSM execution the fault
* occurred and the %%offset%% indicates where the input failed.
*
* The %%bytes%% represents the raw UTF-8 data that was provided and
* %%output%% is the current array of UTF-8 code-points, which may
* be updated by the ``Utf8ErrorFunc``.
*
* The value of the %%badCodepoint%% depends on the %%reason%%. See
* [[Utf8ErrorReason]] for details.
*
* The function should return the number of bytes that should be skipped
* when control resumes to the FSM.
*/
export type Utf8ErrorFunc = (reason: Utf8ErrorReason, offset: number, bytes: Uint8Array, output: Array<number>, badCodepoint?: number) => number;
function errorFunc(reason: Utf8ErrorReason, offset: number, bytes: Uint8Array, output: Array<number>, badCodepoint?: number): number {
assertArgument(false, `invalid codepoint at offset ${ offset }; ${ reason }`, "bytes", bytes);
}
function ignoreFunc(reason: Utf8ErrorReason, offset: number, bytes: Uint8Array, output: Array<number>, badCodepoint?: number): number {
// If there is an invalid prefix (including stray continuation), skip any additional continuation bytes
if (reason === "BAD_PREFIX" || reason === "UNEXPECTED_CONTINUE") {
let i = 0;
for (let o = offset + 1; o < bytes.length; o++) {
if (bytes[o] >> 6 !== 0x02) { break; }
i++;
}
return i;
}
// This byte runs us past the end of the string, so just jump to the end
// (but the first byte was read already read and therefore skipped)
if (reason === "OVERRUN") {
return bytes.length - offset - 1;
}
// Nothing to skip
return 0;
}
function replaceFunc(reason: Utf8ErrorReason, offset: number, bytes: Uint8Array, output: Array<number>, badCodepoint?: number): number {
// Overlong representations are otherwise "valid" code points; just non-deistingtished
if (reason === "OVERLONG") {
assertArgument(typeof(badCodepoint) === "number", "invalid bad code point for replacement", "badCodepoint", badCodepoint);
output.push(badCodepoint);
return 0;
}
// Put the replacement character into the output
output.push(0xfffd);
// Otherwise, process as if ignoring errors
return ignoreFunc(reason, offset, bytes, output, badCodepoint);
}
/**
* A handful of popular, built-in UTF-8 error handling strategies.
*
* **``"error"``** - throws on ANY illegal UTF-8 sequence or
* non-canonical (overlong) codepoints (this is the default)
*
* **``"ignore"``** - silently drops any illegal UTF-8 sequence
* and accepts non-canonical (overlong) codepoints
*
* **``"replace"``** - replace any illegal UTF-8 sequence with the
* UTF-8 replacement character (i.e. ``"\\ufffd"``) and accepts
* non-canonical (overlong) codepoints
*
* @returns: Record<"error" | "ignore" | "replace", Utf8ErrorFunc>
*/
export const Utf8ErrorFuncs: Readonly<Record<"error" | "ignore" | "replace", Utf8ErrorFunc>> = Object.freeze({
error: errorFunc,
ignore: ignoreFunc,
replace: replaceFunc
});
// http://stackoverflow.com/questions/13356493/decode-utf-8-with-javascript#13691499
function getUtf8CodePoints(_bytes: BytesLike, onError?: Utf8ErrorFunc): Array<number> {
if (onError == null) { onError = Utf8ErrorFuncs.error; }
const bytes = getBytes(_bytes, "bytes");
const result: Array<number> = [];
let i = 0;
// Invalid bytes are ignored
while(i < bytes.length) {
const c = bytes[i++];
// 0xxx xxxx
if (c >> 7 === 0) {
result.push(c);
continue;
}
// Multibyte; how many bytes left for this character?
let extraLength: null | number = null;
let overlongMask: null | number = null;
// 110x xxxx 10xx xxxx
if ((c & 0xe0) === 0xc0) {
extraLength = 1;
overlongMask = 0x7f;
// 1110 xxxx 10xx xxxx 10xx xxxx
} else if ((c & 0xf0) === 0xe0) {
extraLength = 2;
overlongMask = 0x7ff;
// 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx
} else if ((c & 0xf8) === 0xf0) {
extraLength = 3;
overlongMask = 0xffff;
} else {
if ((c & 0xc0) === 0x80) {
i += onError("UNEXPECTED_CONTINUE", i - 1, bytes, result);
} else {
i += onError("BAD_PREFIX", i - 1, bytes, result);
}
continue;
}
// Do we have enough bytes in our data?
if (i - 1 + extraLength >= bytes.length) {
i += onError("OVERRUN", i - 1, bytes, result);
continue;
}
// Remove the length prefix from the char
let res: null | number = c & ((1 << (8 - extraLength - 1)) - 1);
for (let j = 0; j < extraLength; j++) {
let nextChar = bytes[i];
// Invalid continuation byte
if ((nextChar & 0xc0) != 0x80) {
i += onError("MISSING_CONTINUE", i, bytes, result);
res = null;
break;
};
res = (res << 6) | (nextChar & 0x3f);
i++;
}
// See above loop for invalid continuation byte
if (res === null) { continue; }
// Maximum code point
if (res > 0x10ffff) {
i += onError("OUT_OF_RANGE", i - 1 - extraLength, bytes, result, res);
continue;
}
// Reserved for UTF-16 surrogate halves
if (res >= 0xd800 && res <= 0xdfff) {
i += onError("UTF16_SURROGATE", i - 1 - extraLength, bytes, result, res);
continue;
}
// Check for overlong sequences (more bytes than needed)
if (res <= overlongMask) {
i += onError("OVERLONG", i - 1 - extraLength, bytes, result, res);
continue;
}
result.push(res);
}
return result;
}
// http://stackoverflow.com/questions/18729405/how-to-convert-utf8-string-to-byte-array
/**
* Returns the UTF-8 byte representation of %%str%%.
*
* If %%form%% is specified, the string is normalized.
*/
export function toUtf8Bytes(str: string, form?: UnicodeNormalizationForm): Uint8Array {
assertArgument(typeof(str) === "string", "invalid string value", "str", str);
if (form != null) {
assertNormalize(form);
str = str.normalize(form);
}
let result: Array<number> = [];
for (let i = 0; i < str.length; i++) {
const c = str.charCodeAt(i);
if (c < 0x80) {
result.push(c);
} else if (c < 0x800) {
result.push((c >> 6) | 0xc0);
result.push((c & 0x3f) | 0x80);
} else if ((c & 0xfc00) == 0xd800) {
i++;
const c2 = str.charCodeAt(i);
assertArgument(i < str.length && ((c2 & 0xfc00) === 0xdc00),
"invalid surrogate pair", "str", str);
// Surrogate Pair
const pair = 0x10000 + ((c & 0x03ff) << 10) + (c2 & 0x03ff);
result.push((pair >> 18) | 0xf0);
result.push(((pair >> 12) & 0x3f) | 0x80);
result.push(((pair >> 6) & 0x3f) | 0x80);
result.push((pair & 0x3f) | 0x80);
} else {
result.push((c >> 12) | 0xe0);
result.push(((c >> 6) & 0x3f) | 0x80);
result.push((c & 0x3f) | 0x80);
}
}
return new Uint8Array(result);
};
//export
function _toUtf8String(codePoints: Array<number>): string {
return codePoints.map((codePoint) => {
if (codePoint <= 0xffff) {
return String.fromCharCode(codePoint);
}
codePoint -= 0x10000;
return String.fromCharCode(
(((codePoint >> 10) & 0x3ff) + 0xd800),
((codePoint & 0x3ff) + 0xdc00)
);
}).join("");
}
/**
* Returns the string represented by the UTF-8 data %%bytes%%.
*
* When %%onError%% function is specified, it is called on UTF-8
* errors allowing recovery using the [[Utf8ErrorFunc]] API.
* (default: [error](Utf8ErrorFuncs))
*/
export function toUtf8String(bytes: BytesLike, onError?: Utf8ErrorFunc): string {
return _toUtf8String(getUtf8CodePoints(bytes, onError));
}
/**
* Returns the UTF-8 code-points for %%str%%.
*
* If %%form%% is specified, the string is normalized.
*/
export function toUtf8CodePoints(str: string, form?: UnicodeNormalizationForm): Array<number> {
return getUtf8CodePoints(toUtf8Bytes(str, form));
}

36
dev/env/node_modules/ethers/src.ts/utils/uuid.ts generated vendored Executable file
View File

@@ -0,0 +1,36 @@
/**
* 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";
/**
* Returns the version 4 [[link-uuid]] for the %%randomBytes%%.
*
* @see: https://www.ietf.org/rfc/rfc4122.txt (Section 4.4)
*/
export function uuidV4(randomBytes: BytesLike): string {
const bytes = getBytes(randomBytes, "randomBytes");
// Section: 4.1.3:
// - time_hi_and_version[12:16] = 0b0100
bytes[6] = (bytes[6] & 0x0f) | 0x40;
// Section 4.4
// - clock_seq_hi_and_reserved[6] = 0b0
// - clock_seq_hi_and_reserved[7] = 0b1
bytes[8] = (bytes[8] & 0x3f) | 0x80;
const value = hexlify(bytes);
return [
value.substring(2, 10),
value.substring(10, 14),
value.substring(14, 18),
value.substring(18, 22),
value.substring(22, 34),
].join("-");
}