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:
6
dev/env/node_modules/ethers/src.ts/_version.ts
generated
vendored
Executable file
6
dev/env/node_modules/ethers/src.ts/_version.ts
generated
vendored
Executable file
@@ -0,0 +1,6 @@
|
||||
/* Do NOT modify this file; see /src.ts/_admin/update-version.ts */
|
||||
|
||||
/**
|
||||
* The current version of Ethers.
|
||||
*/
|
||||
export const version: string = "6.16.0";
|
||||
237
dev/env/node_modules/ethers/src.ts/abi/abi-coder.ts
generated
vendored
Executable file
237
dev/env/node_modules/ethers/src.ts/abi/abi-coder.ts
generated
vendored
Executable file
@@ -0,0 +1,237 @@
|
||||
/**
|
||||
* When sending values to or receiving values from a [[Contract]], the
|
||||
* data is generally encoded using the [ABI standard](link-solc-abi).
|
||||
*
|
||||
* The AbiCoder provides a utility to encode values to ABI data and
|
||||
* decode values from ABI data.
|
||||
*
|
||||
* Most of the time, developers should favour the [[Contract]] class,
|
||||
* which further abstracts a lot of the finer details of ABI data.
|
||||
*
|
||||
* @_section api/abi/abi-coder:ABI Encoding
|
||||
*/
|
||||
|
||||
// See: https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
|
||||
|
||||
import { assertArgumentCount, assertArgument } from "../utils/index.js";
|
||||
|
||||
import { Coder, Reader, Result, Writer } from "./coders/abstract-coder.js";
|
||||
import { AddressCoder } from "./coders/address.js";
|
||||
import { ArrayCoder } from "./coders/array.js";
|
||||
import { BooleanCoder } from "./coders/boolean.js";
|
||||
import { BytesCoder } from "./coders/bytes.js";
|
||||
import { FixedBytesCoder } from "./coders/fixed-bytes.js";
|
||||
import { NullCoder } from "./coders/null.js";
|
||||
import { NumberCoder } from "./coders/number.js";
|
||||
import { StringCoder } from "./coders/string.js";
|
||||
import { TupleCoder } from "./coders/tuple.js";
|
||||
import { ParamType } from "./fragments.js";
|
||||
|
||||
import { getAddress } from "../address/index.js";
|
||||
import { getBytes, hexlify, makeError } from "../utils/index.js";
|
||||
|
||||
import type {
|
||||
BytesLike,
|
||||
CallExceptionAction, CallExceptionError, CallExceptionTransaction
|
||||
} from "../utils/index.js";
|
||||
|
||||
// https://docs.soliditylang.org/en/v0.8.17/control-structures.html
|
||||
const PanicReasons: Map<number, string> = new Map();
|
||||
PanicReasons.set(0x00, "GENERIC_PANIC");
|
||||
PanicReasons.set(0x01, "ASSERT_FALSE");
|
||||
PanicReasons.set(0x11, "OVERFLOW");
|
||||
PanicReasons.set(0x12, "DIVIDE_BY_ZERO");
|
||||
PanicReasons.set(0x21, "ENUM_RANGE_ERROR");
|
||||
PanicReasons.set(0x22, "BAD_STORAGE_DATA");
|
||||
PanicReasons.set(0x31, "STACK_UNDERFLOW");
|
||||
PanicReasons.set(0x32, "ARRAY_RANGE_ERROR");
|
||||
PanicReasons.set(0x41, "OUT_OF_MEMORY");
|
||||
PanicReasons.set(0x51, "UNINITIALIZED_FUNCTION_CALL");
|
||||
|
||||
const paramTypeBytes = new RegExp(/^bytes([0-9]*)$/);
|
||||
const paramTypeNumber = new RegExp(/^(u?int)([0-9]*)$/);
|
||||
|
||||
|
||||
let defaultCoder: null | AbiCoder = null;
|
||||
let defaultMaxInflation = 1024;
|
||||
|
||||
function getBuiltinCallException(action: CallExceptionAction, tx: { to?: null | string, from?: null | string, data?: string }, data: null | BytesLike, abiCoder: AbiCoder): CallExceptionError {
|
||||
let message = "missing revert data";
|
||||
|
||||
let reason: null | string = null;
|
||||
const invocation = null;
|
||||
let revert: null | { signature: string, name: string, args: Array<any> } = null;
|
||||
|
||||
if (data) {
|
||||
message = "execution reverted";
|
||||
|
||||
const bytes = getBytes(data);
|
||||
data = hexlify(data);
|
||||
|
||||
if (bytes.length === 0) {
|
||||
message += " (no data present; likely require(false) occurred";
|
||||
reason = "require(false)";
|
||||
|
||||
} else if (bytes.length % 32 !== 4) {
|
||||
message += " (could not decode reason; invalid data length)";
|
||||
|
||||
} else if (hexlify(bytes.slice(0, 4)) === "0x08c379a0") {
|
||||
// Error(string)
|
||||
try {
|
||||
reason = abiCoder.decode([ "string" ], bytes.slice(4))[0]
|
||||
revert = {
|
||||
signature: "Error(string)",
|
||||
name: "Error",
|
||||
args: [ reason ]
|
||||
};
|
||||
message += `: ${ JSON.stringify(reason) }`;
|
||||
|
||||
} catch (error) {
|
||||
message += " (could not decode reason; invalid string data)";
|
||||
}
|
||||
|
||||
} else if (hexlify(bytes.slice(0, 4)) === "0x4e487b71") {
|
||||
// Panic(uint256)
|
||||
try {
|
||||
const code = Number(abiCoder.decode([ "uint256" ], bytes.slice(4))[0]);
|
||||
revert = {
|
||||
signature: "Panic(uint256)",
|
||||
name: "Panic",
|
||||
args: [ code ]
|
||||
};
|
||||
reason = `Panic due to ${ PanicReasons.get(code) || "UNKNOWN" }(${ code })`;
|
||||
message += `: ${ reason }`;
|
||||
} catch (error) {
|
||||
message += " (could not decode panic code)";
|
||||
}
|
||||
} else {
|
||||
message += " (unknown custom error)";
|
||||
}
|
||||
}
|
||||
|
||||
const transaction: CallExceptionTransaction = {
|
||||
to: (tx.to ? getAddress(tx.to): null),
|
||||
data: (tx.data || "0x")
|
||||
};
|
||||
if (tx.from) { transaction.from = getAddress(tx.from); }
|
||||
|
||||
return makeError(message, "CALL_EXCEPTION", {
|
||||
action, data, reason, transaction, invocation, revert
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The **AbiCoder** is a low-level class responsible for encoding JavaScript
|
||||
* values into binary data and decoding binary data into JavaScript values.
|
||||
*/
|
||||
export class AbiCoder {
|
||||
|
||||
#getCoder(param: ParamType): Coder {
|
||||
if (param.isArray()) {
|
||||
return new ArrayCoder(this.#getCoder(param.arrayChildren), param.arrayLength, param.name);
|
||||
}
|
||||
|
||||
if (param.isTuple()) {
|
||||
return new TupleCoder(param.components.map((c) => this.#getCoder(c)), param.name);
|
||||
}
|
||||
|
||||
switch (param.baseType) {
|
||||
case "address":
|
||||
return new AddressCoder(param.name);
|
||||
case "bool":
|
||||
return new BooleanCoder(param.name);
|
||||
case "string":
|
||||
return new StringCoder(param.name);
|
||||
case "bytes":
|
||||
return new BytesCoder(param.name);
|
||||
case "":
|
||||
return new NullCoder(param.name);
|
||||
}
|
||||
|
||||
// u?int[0-9]*
|
||||
let match = param.type.match(paramTypeNumber);
|
||||
if (match) {
|
||||
let size = parseInt(match[2] || "256");
|
||||
assertArgument(size !== 0 && size <= 256 && (size % 8) === 0,
|
||||
"invalid " + match[1] + " bit length", "param", param);
|
||||
return new NumberCoder(size / 8, (match[1] === "int"), param.name);
|
||||
}
|
||||
|
||||
// bytes[0-9]+
|
||||
match = param.type.match(paramTypeBytes);
|
||||
if (match) {
|
||||
let size = parseInt(match[1]);
|
||||
assertArgument(size !== 0 && size <= 32, "invalid bytes length", "param", param);
|
||||
return new FixedBytesCoder(size, param.name);
|
||||
}
|
||||
|
||||
assertArgument(false, "invalid type", "type", param.type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default values for the given %%types%%.
|
||||
*
|
||||
* For example, a ``uint`` is by default ``0`` and ``bool``
|
||||
* is by default ``false``.
|
||||
*/
|
||||
getDefaultValue(types: ReadonlyArray<string | ParamType>): Result {
|
||||
const coders: Array<Coder> = types.map((type) => this.#getCoder(ParamType.from(type)));
|
||||
const coder = new TupleCoder(coders, "_");
|
||||
return coder.defaultValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the %%values%% as the %%types%% into ABI data.
|
||||
*
|
||||
* @returns DataHexstring
|
||||
*/
|
||||
encode(types: ReadonlyArray<string | ParamType>, values: ReadonlyArray<any>): string {
|
||||
assertArgumentCount(values.length, types.length, "types/values length mismatch");
|
||||
|
||||
const coders = types.map((type) => this.#getCoder(ParamType.from(type)));
|
||||
const coder = (new TupleCoder(coders, "_"));
|
||||
|
||||
const writer = new Writer();
|
||||
coder.encode(writer, values);
|
||||
return writer.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the ABI %%data%% as the %%types%% into values.
|
||||
*
|
||||
* If %%loose%% decoding is enabled, then strict padding is
|
||||
* not enforced. Some older versions of Solidity incorrectly
|
||||
* padded event data emitted from ``external`` functions.
|
||||
*/
|
||||
decode(types: ReadonlyArray<string | ParamType>, data: BytesLike, loose?: boolean): Result {
|
||||
const coders: Array<Coder> = types.map((type) => this.#getCoder(ParamType.from(type)));
|
||||
const coder = new TupleCoder(coders, "_");
|
||||
return coder.decode(new Reader(data, loose, defaultMaxInflation));
|
||||
}
|
||||
|
||||
static _setDefaultMaxInflation(value: number): void {
|
||||
assertArgument(typeof(value) === "number" && Number.isInteger(value), "invalid defaultMaxInflation factor", "value", value);
|
||||
defaultMaxInflation = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the shared singleton instance of a default [[AbiCoder]].
|
||||
*
|
||||
* On the first call, the instance is created internally.
|
||||
*/
|
||||
static defaultAbiCoder(): AbiCoder {
|
||||
if (defaultCoder == null) {
|
||||
defaultCoder = new AbiCoder();
|
||||
}
|
||||
return defaultCoder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an ethers-compatible [[CallExceptionError]] Error for the given
|
||||
* result %%data%% for the [[CallExceptionAction]] %%action%% against
|
||||
* the Transaction %%tx%%.
|
||||
*/
|
||||
static getBuiltinCallException(action: CallExceptionAction, tx: { to?: null | string, from?: null | string, data?: string }, data: null | BytesLike): CallExceptionError {
|
||||
return getBuiltinCallException(action, tx, data, AbiCoder.defaultAbiCoder());
|
||||
}
|
||||
}
|
||||
45
dev/env/node_modules/ethers/src.ts/abi/bytes32.ts
generated
vendored
Executable file
45
dev/env/node_modules/ethers/src.ts/abi/bytes32.ts
generated
vendored
Executable file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* About bytes32 strings...
|
||||
*
|
||||
* @_docloc: api/utils:Bytes32 Strings
|
||||
*/
|
||||
|
||||
import {
|
||||
getBytes, toUtf8Bytes, toUtf8String, zeroPadBytes
|
||||
} from "../utils/index.js";
|
||||
|
||||
import type { BytesLike } from "../utils/index.js";
|
||||
|
||||
/**
|
||||
* Encodes %%text%% as a Bytes32 string.
|
||||
*/
|
||||
export function encodeBytes32String(text: string): string {
|
||||
|
||||
// Get the bytes
|
||||
const bytes = toUtf8Bytes(text);
|
||||
|
||||
// Check we have room for null-termination
|
||||
if (bytes.length > 31) { throw new Error("bytes32 string must be less than 32 bytes"); }
|
||||
|
||||
// Zero-pad (implicitly null-terminates)
|
||||
return zeroPadBytes(bytes, 32);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the Bytes32-encoded %%bytes%% into a string.
|
||||
*/
|
||||
export function decodeBytes32String(_bytes: BytesLike): string {
|
||||
const data = getBytes(_bytes, "bytes");
|
||||
|
||||
// Must be 32 bytes with a null-termination
|
||||
if (data.length !== 32) { throw new Error("invalid bytes32 - not 32 bytes long"); }
|
||||
if (data[31] !== 0) { throw new Error("invalid bytes32 string - no null terminator"); }
|
||||
|
||||
// Find the null termination
|
||||
let length = 31;
|
||||
while (data[length - 1] === 0) { length--; }
|
||||
|
||||
// Determine the string value
|
||||
return toUtf8String(data.slice(0, length));
|
||||
}
|
||||
|
||||
541
dev/env/node_modules/ethers/src.ts/abi/coders/abstract-coder.ts
generated
vendored
Executable file
541
dev/env/node_modules/ethers/src.ts/abi/coders/abstract-coder.ts
generated
vendored
Executable file
@@ -0,0 +1,541 @@
|
||||
|
||||
import {
|
||||
defineProperties, concat, getBytesCopy, getNumber, hexlify,
|
||||
toBeArray, toBigInt, toNumber,
|
||||
assert, assertArgument
|
||||
/*, isError*/
|
||||
} from "../../utils/index.js";
|
||||
|
||||
import type { BigNumberish, BytesLike } from "../../utils/index.js";
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
export const WordSize: number = 32;
|
||||
const Padding = new Uint8Array(WordSize);
|
||||
|
||||
// Properties used to immediate pass through to the underlying object
|
||||
// - `then` is used to detect if an object is a Promise for await
|
||||
const passProperties = [ "then" ];
|
||||
|
||||
const _guard = { };
|
||||
|
||||
const resultNames: WeakMap<Result, ReadonlyArray<null | string>> = new WeakMap();
|
||||
|
||||
function getNames(result: Result): ReadonlyArray<null | string> {
|
||||
return resultNames.get(result)!;
|
||||
}
|
||||
function setNames(result: Result, names: ReadonlyArray<null | string>): void {
|
||||
resultNames.set(result, names);
|
||||
}
|
||||
|
||||
function throwError(name: string, error: Error): never {
|
||||
const wrapped = new Error(`deferred error during ABI decoding triggered accessing ${ name }`);
|
||||
(<any>wrapped).error = error;
|
||||
throw wrapped;
|
||||
}
|
||||
|
||||
function toObject(names: ReadonlyArray<null | string>, items: Result, deep?: boolean): Record<string, any> | Array<any> {
|
||||
if (names.indexOf(null) >= 0) {
|
||||
return items.map((item, index) => {
|
||||
if (item instanceof Result) {
|
||||
return toObject(getNames(item), item, deep);
|
||||
}
|
||||
return item;
|
||||
});
|
||||
}
|
||||
|
||||
return (<Array<string>>names).reduce((accum, name, index) => {
|
||||
let item = items.getValue(name);
|
||||
if (!(name in accum)) {
|
||||
if (deep && item instanceof Result) {
|
||||
item = toObject(getNames(item), item, deep);
|
||||
}
|
||||
accum[name] = item;
|
||||
}
|
||||
return accum;
|
||||
}, <Record<string, any>>{ });
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A [[Result]] is a sub-class of Array, which allows accessing any
|
||||
* of its values either positionally by its index or, if keys are
|
||||
* provided by its name.
|
||||
*
|
||||
* @_docloc: api/abi
|
||||
*/
|
||||
export class Result extends Array<any> {
|
||||
// No longer used; but cannot be removed as it will remove the
|
||||
// #private field from the .d.ts which may break backwards
|
||||
// compatibility
|
||||
readonly #names: ReadonlyArray<null | string>;
|
||||
|
||||
[ K: string | number ]: any
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
constructor(...args: Array<any>) {
|
||||
// To properly sub-class Array so the other built-in
|
||||
// functions work, the constructor has to behave fairly
|
||||
// well. So, in the event we are created via fromItems()
|
||||
// we build the read-only Result object we want, but on
|
||||
// any other input, we use the default constructor
|
||||
|
||||
// constructor(guard: any, items: Array<any>, keys?: Array<null | string>);
|
||||
const guard = args[0];
|
||||
let items: Array<any> = args[1];
|
||||
let names: Array<null | string> = (args[2] || [ ]).slice();
|
||||
|
||||
let wrap = true;
|
||||
if (guard !== _guard) {
|
||||
items = args;
|
||||
names = [ ];
|
||||
wrap = false;
|
||||
}
|
||||
|
||||
// Can't just pass in ...items since an array of length 1
|
||||
// is a special case in the super.
|
||||
super(items.length);
|
||||
items.forEach((item, index) => { this[index] = item; });
|
||||
|
||||
// Find all unique keys
|
||||
const nameCounts = names.reduce((accum, name) => {
|
||||
if (typeof(name) === "string") {
|
||||
accum.set(name, (accum.get(name) || 0) + 1);
|
||||
}
|
||||
return accum;
|
||||
}, <Map<string, number>>(new Map()));
|
||||
|
||||
// Remove any key thats not unique
|
||||
setNames(this, Object.freeze(items.map((item, index) => {
|
||||
const name = names[index];
|
||||
if (name != null && nameCounts.get(name) === 1) {
|
||||
return name;
|
||||
}
|
||||
return null;
|
||||
})));
|
||||
|
||||
// Dummy operations to prevent TypeScript from complaining
|
||||
this.#names = [ ];
|
||||
if (this.#names == null) { void(this.#names); }
|
||||
|
||||
if (!wrap) { return; }
|
||||
|
||||
// A wrapped Result is immutable
|
||||
Object.freeze(this);
|
||||
|
||||
// Proxy indices and names so we can trap deferred errors
|
||||
const proxy = new Proxy(this, {
|
||||
get: (target, prop, receiver) => {
|
||||
if (typeof(prop) === "string") {
|
||||
|
||||
// Index accessor
|
||||
if (prop.match(/^[0-9]+$/)) {
|
||||
const index = getNumber(prop, "%index");
|
||||
if (index < 0 || index >= this.length) {
|
||||
throw new RangeError("out of result range");
|
||||
}
|
||||
|
||||
const item = target[index];
|
||||
if (item instanceof Error) {
|
||||
throwError(`index ${ index }`, item);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
// Pass important checks (like `then` for Promise) through
|
||||
if (passProperties.indexOf(prop) >= 0) {
|
||||
return Reflect.get(target, prop, receiver);
|
||||
}
|
||||
|
||||
const value = target[prop];
|
||||
if (value instanceof Function) {
|
||||
// Make sure functions work with private variables
|
||||
// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy#no_private_property_forwarding
|
||||
return function(this: any, ...args: Array<any>) {
|
||||
return value.apply((this === receiver) ? target: this, args);
|
||||
};
|
||||
|
||||
} else if (!(prop in target)) {
|
||||
// Possible name accessor
|
||||
return target.getValue.apply((this === receiver) ? target: this, [ prop ]);
|
||||
}
|
||||
}
|
||||
|
||||
return Reflect.get(target, prop, receiver);
|
||||
}
|
||||
});
|
||||
setNames(proxy, getNames(this));
|
||||
return proxy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Result as a normal Array. If %%deep%%, any children
|
||||
* which are Result objects are also converted to a normal Array.
|
||||
*
|
||||
* This will throw if there are any outstanding deferred
|
||||
* errors.
|
||||
*/
|
||||
toArray(deep?: boolean): Array<any> {
|
||||
const result: Array<any> = [ ];
|
||||
this.forEach((item, index) => {
|
||||
if (item instanceof Error) { throwError(`index ${ index }`, item); }
|
||||
if (deep && item instanceof Result) {
|
||||
item = item.toArray(deep);
|
||||
}
|
||||
result.push(item);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Result as an Object with each name-value pair. If
|
||||
* %%deep%%, any children which are Result objects are also
|
||||
* converted to an Object.
|
||||
*
|
||||
* This will throw if any value is unnamed, or if there are
|
||||
* any outstanding deferred errors.
|
||||
*/
|
||||
toObject(deep?: boolean): Record<string, any> {
|
||||
const names = getNames(this);
|
||||
return names.reduce((accum, name, index) => {
|
||||
|
||||
assert(name != null, `value at index ${ index } unnamed`, "UNSUPPORTED_OPERATION", {
|
||||
operation: "toObject()"
|
||||
});
|
||||
|
||||
return toObject(names, this, deep);
|
||||
}, <Record<string, any>>{});
|
||||
}
|
||||
|
||||
/**
|
||||
* @_ignore
|
||||
*/
|
||||
slice(start?: number | undefined, end?: number | undefined): Result {
|
||||
if (start == null) { start = 0; }
|
||||
if (start < 0) {
|
||||
start += this.length;
|
||||
if (start < 0) { start = 0; }
|
||||
}
|
||||
|
||||
if (end == null) { end = this.length; }
|
||||
if (end < 0) {
|
||||
end += this.length;
|
||||
if (end < 0) { end = 0; }
|
||||
}
|
||||
if (end > this.length) { end = this.length; }
|
||||
|
||||
const _names = getNames(this);
|
||||
|
||||
const result: Array<any> = [ ], names: Array<null | string> = [ ];
|
||||
for (let i = start; i < end; i++) {
|
||||
result.push(this[i]);
|
||||
names.push(_names[i]);
|
||||
}
|
||||
|
||||
return new Result(_guard, result, names);
|
||||
}
|
||||
|
||||
/**
|
||||
* @_ignore
|
||||
*/
|
||||
filter(callback: (el: any, index: number, array: Result) => boolean, thisArg?: any): Result {
|
||||
const _names = getNames(this);
|
||||
|
||||
const result: Array<any> = [ ], names: Array<null | string> = [ ];
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
const item = this[i];
|
||||
if (item instanceof Error) {
|
||||
throwError(`index ${ i }`, item);
|
||||
}
|
||||
|
||||
if (callback.call(thisArg, item, i, this)) {
|
||||
result.push(item);
|
||||
names.push(_names[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return new Result(_guard, result, names);
|
||||
}
|
||||
|
||||
/**
|
||||
* @_ignore
|
||||
*/
|
||||
map<T extends any = any>(callback: (el: any, index: number, array: Result) => T, thisArg?: any): Array<T> {
|
||||
const result: Array<T> = [ ];
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
const item = this[i];
|
||||
if (item instanceof Error) {
|
||||
throwError(`index ${ i }`, item);
|
||||
}
|
||||
|
||||
result.push(callback.call(thisArg, item, i, this));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the value for %%name%%.
|
||||
*
|
||||
* Since it is possible to have a key whose name conflicts with
|
||||
* a method on a [[Result]] or its superclass Array, or any
|
||||
* JavaScript keyword, this ensures all named values are still
|
||||
* accessible by name.
|
||||
*/
|
||||
getValue(name: string): any {
|
||||
const index = getNames(this).indexOf(name);
|
||||
if (index === -1) { return undefined; }
|
||||
|
||||
const value = this[index];
|
||||
|
||||
if (value instanceof Error) {
|
||||
throwError(`property ${ JSON.stringify(name) }`, (<any>value).error);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new [[Result]] for %%items%% with each entry
|
||||
* also accessible by its corresponding name in %%keys%%.
|
||||
*/
|
||||
static fromItems(items: Array<any>, keys?: Array<null | string>): Result {
|
||||
return new Result(_guard, items, keys);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all errors found in a [[Result]].
|
||||
*
|
||||
* Since certain errors encountered when creating a [[Result]] do
|
||||
* not impact the ability to continue parsing data, they are
|
||||
* deferred until they are actually accessed. Hence a faulty string
|
||||
* in an Event that is never used does not impact the program flow.
|
||||
*
|
||||
* However, sometimes it may be useful to access, identify or
|
||||
* validate correctness of a [[Result]].
|
||||
*
|
||||
* @_docloc api/abi
|
||||
*/
|
||||
export function checkResultErrors(result: Result): Array<{ path: Array<string | number>, error: Error }> {
|
||||
// Find the first error (if any)
|
||||
const errors: Array<{ path: Array<string | number>, error: Error }> = [ ];
|
||||
|
||||
const checkErrors = function(path: Array<string | number>, object: any): void {
|
||||
if (!Array.isArray(object)) { return; }
|
||||
for (let key in object) {
|
||||
const childPath = path.slice();
|
||||
childPath.push(key);
|
||||
|
||||
try {
|
||||
checkErrors(childPath, object[key]);
|
||||
} catch (error: any) {
|
||||
errors.push({ path: childPath, error: error });
|
||||
}
|
||||
}
|
||||
}
|
||||
checkErrors([ ], result);
|
||||
|
||||
return errors;
|
||||
|
||||
}
|
||||
|
||||
function getValue(value: BigNumberish): Uint8Array {
|
||||
let bytes = toBeArray(value);
|
||||
|
||||
assert (bytes.length <= WordSize, "value out-of-bounds",
|
||||
"BUFFER_OVERRUN", { buffer: bytes, length: WordSize, offset: bytes.length });
|
||||
|
||||
if (bytes.length !== WordSize) {
|
||||
bytes = getBytesCopy(concat([ Padding.slice(bytes.length % WordSize), bytes ]));
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @_ignore
|
||||
*/
|
||||
export abstract class Coder {
|
||||
|
||||
// The coder name:
|
||||
// - address, uint256, tuple, array, etc.
|
||||
readonly name!: string;
|
||||
|
||||
// The fully expanded type, including composite types:
|
||||
// - address, uint256, tuple(address,bytes), uint256[3][4][], etc.
|
||||
readonly type!: string;
|
||||
|
||||
// The localName bound in the signature, in this example it is "baz":
|
||||
// - tuple(address foo, uint bar) baz
|
||||
readonly localName!: string;
|
||||
|
||||
// Whether this type is dynamic:
|
||||
// - Dynamic: bytes, string, address[], tuple(boolean[]), etc.
|
||||
// - Not Dynamic: address, uint256, boolean[3], tuple(address, uint8)
|
||||
readonly dynamic!: boolean;
|
||||
|
||||
constructor(name: string, type: string, localName: string, dynamic: boolean) {
|
||||
defineProperties<Coder>(this, { name, type, localName, dynamic }, {
|
||||
name: "string", type: "string", localName: "string", dynamic: "boolean"
|
||||
});
|
||||
}
|
||||
|
||||
_throwError(message: string, value: any): never {
|
||||
assertArgument(false, message, this.localName, value);
|
||||
}
|
||||
|
||||
abstract encode(writer: Writer, value: any): number;
|
||||
abstract decode(reader: Reader): any;
|
||||
|
||||
abstract defaultValue(): any;
|
||||
}
|
||||
|
||||
/**
|
||||
* @_ignore
|
||||
*/
|
||||
export class Writer {
|
||||
// An array of WordSize lengthed objects to concatenation
|
||||
#data: Array<Uint8Array>;
|
||||
#dataLength: number;
|
||||
|
||||
constructor() {
|
||||
this.#data = [ ];
|
||||
this.#dataLength = 0;
|
||||
}
|
||||
|
||||
get data(): string {
|
||||
return concat(this.#data);
|
||||
}
|
||||
get length(): number { return this.#dataLength; }
|
||||
|
||||
#writeData(data: Uint8Array): number {
|
||||
this.#data.push(data);
|
||||
this.#dataLength += data.length;
|
||||
return data.length;
|
||||
}
|
||||
|
||||
appendWriter(writer: Writer): number {
|
||||
return this.#writeData(getBytesCopy(writer.data));
|
||||
}
|
||||
|
||||
// Arrayish item; pad on the right to *nearest* WordSize
|
||||
writeBytes(value: BytesLike): number {
|
||||
let bytes = getBytesCopy(value);
|
||||
const paddingOffset = bytes.length % WordSize;
|
||||
if (paddingOffset) {
|
||||
bytes = getBytesCopy(concat([ bytes, Padding.slice(paddingOffset) ]))
|
||||
}
|
||||
return this.#writeData(bytes);
|
||||
}
|
||||
|
||||
// Numeric item; pad on the left *to* WordSize
|
||||
writeValue(value: BigNumberish): number {
|
||||
return this.#writeData(getValue(value));
|
||||
}
|
||||
|
||||
// Inserts a numeric place-holder, returning a callback that can
|
||||
// be used to asjust the value later
|
||||
writeUpdatableValue(): (value: BigNumberish) => void {
|
||||
const offset = this.#data.length;
|
||||
this.#data.push(Padding);
|
||||
this.#dataLength += WordSize;
|
||||
return (value: BigNumberish) => {
|
||||
this.#data[offset] = getValue(value);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @_ignore
|
||||
*/
|
||||
export class Reader {
|
||||
// Allows incomplete unpadded data to be read; otherwise an error
|
||||
// is raised if attempting to overrun the buffer. This is required
|
||||
// to deal with an old Solidity bug, in which event data for
|
||||
// external (not public thoguh) was tightly packed.
|
||||
readonly allowLoose!: boolean;
|
||||
|
||||
readonly #data: Uint8Array;
|
||||
#offset: number;
|
||||
|
||||
#bytesRead: number;
|
||||
#parent: null | Reader;
|
||||
#maxInflation: number;
|
||||
|
||||
constructor(data: BytesLike, allowLoose?: boolean, maxInflation?: number) {
|
||||
defineProperties<Reader>(this, { allowLoose: !!allowLoose });
|
||||
|
||||
this.#data = getBytesCopy(data);
|
||||
this.#bytesRead = 0;
|
||||
this.#parent = null;
|
||||
this.#maxInflation = (maxInflation != null) ? maxInflation: 1024;
|
||||
|
||||
this.#offset = 0;
|
||||
}
|
||||
|
||||
get data(): string { return hexlify(this.#data); }
|
||||
get dataLength(): number { return this.#data.length; }
|
||||
get consumed(): number { return this.#offset; }
|
||||
get bytes(): Uint8Array { return new Uint8Array(this.#data); }
|
||||
|
||||
#incrementBytesRead(count: number): void {
|
||||
if (this.#parent) { return this.#parent.#incrementBytesRead(count); }
|
||||
|
||||
this.#bytesRead += count;
|
||||
|
||||
// Check for excessive inflation (see: #4537)
|
||||
assert(this.#maxInflation < 1 || this.#bytesRead <= this.#maxInflation * this.dataLength, `compressed ABI data exceeds inflation ratio of ${ this.#maxInflation } ( see: https:/\/github.com/ethers-io/ethers.js/issues/4537 )`, "BUFFER_OVERRUN", {
|
||||
buffer: getBytesCopy(this.#data), offset: this.#offset,
|
||||
length: count, info: {
|
||||
bytesRead: this.#bytesRead,
|
||||
dataLength: this.dataLength
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#peekBytes(offset: number, length: number, loose?: boolean): Uint8Array {
|
||||
let alignedLength = Math.ceil(length / WordSize) * WordSize;
|
||||
if (this.#offset + alignedLength > this.#data.length) {
|
||||
if (this.allowLoose && loose && this.#offset + length <= this.#data.length) {
|
||||
alignedLength = length;
|
||||
} else {
|
||||
assert(false, "data out-of-bounds", "BUFFER_OVERRUN", {
|
||||
buffer: getBytesCopy(this.#data),
|
||||
length: this.#data.length,
|
||||
offset: this.#offset + alignedLength
|
||||
});
|
||||
}
|
||||
}
|
||||
return this.#data.slice(this.#offset, this.#offset + alignedLength)
|
||||
}
|
||||
|
||||
// Create a sub-reader with the same underlying data, but offset
|
||||
subReader(offset: number): Reader {
|
||||
const reader = new Reader(this.#data.slice(this.#offset + offset), this.allowLoose, this.#maxInflation);
|
||||
reader.#parent = this;
|
||||
return reader;
|
||||
}
|
||||
|
||||
// Read bytes
|
||||
readBytes(length: number, loose?: boolean): Uint8Array {
|
||||
let bytes = this.#peekBytes(0, length, !!loose);
|
||||
this.#incrementBytesRead(length);
|
||||
this.#offset += bytes.length;
|
||||
// @TODO: Make sure the length..end bytes are all 0?
|
||||
return bytes.slice(0, length);
|
||||
}
|
||||
|
||||
// Read a numeric values
|
||||
readValue(): bigint {
|
||||
return toBigInt(this.readBytes(WordSize));
|
||||
}
|
||||
|
||||
readIndex(): number {
|
||||
return toNumber(this.readBytes(WordSize));
|
||||
}
|
||||
}
|
||||
36
dev/env/node_modules/ethers/src.ts/abi/coders/address.ts
generated
vendored
Executable file
36
dev/env/node_modules/ethers/src.ts/abi/coders/address.ts
generated
vendored
Executable file
@@ -0,0 +1,36 @@
|
||||
import { getAddress } from "../../address/index.js";
|
||||
import { toBeHex } from "../../utils/maths.js";
|
||||
|
||||
import { Typed } from "../typed.js";
|
||||
import { Coder } from "./abstract-coder.js";
|
||||
|
||||
import type { Reader, Writer } from "./abstract-coder.js";
|
||||
|
||||
|
||||
/**
|
||||
* @_ignore
|
||||
*/
|
||||
export class AddressCoder extends Coder {
|
||||
|
||||
constructor(localName: string) {
|
||||
super("address", "address", localName, false);
|
||||
}
|
||||
|
||||
defaultValue(): string {
|
||||
return "0x0000000000000000000000000000000000000000";
|
||||
}
|
||||
|
||||
encode(writer: Writer, _value: string | Typed): number {
|
||||
let value = Typed.dereference(_value, "string");
|
||||
try {
|
||||
value = getAddress(value);
|
||||
} catch (error: any) {
|
||||
return this._throwError(error.message, _value);
|
||||
}
|
||||
return writer.writeValue(value);
|
||||
}
|
||||
|
||||
decode(reader: Reader): any {
|
||||
return getAddress(toBeHex(reader.readValue(), 20));
|
||||
}
|
||||
}
|
||||
29
dev/env/node_modules/ethers/src.ts/abi/coders/anonymous.ts
generated
vendored
Executable file
29
dev/env/node_modules/ethers/src.ts/abi/coders/anonymous.ts
generated
vendored
Executable file
@@ -0,0 +1,29 @@
|
||||
import { Coder } from "./abstract-coder.js";
|
||||
|
||||
import type { Reader, Writer } from "./abstract-coder.js";
|
||||
|
||||
/**
|
||||
* Clones the functionality of an existing Coder, but without a localName
|
||||
*
|
||||
* @_ignore
|
||||
*/
|
||||
export class AnonymousCoder extends Coder {
|
||||
private coder: Coder;
|
||||
|
||||
constructor(coder: Coder) {
|
||||
super(coder.name, coder.type, "_", coder.dynamic);
|
||||
this.coder = coder;
|
||||
}
|
||||
|
||||
defaultValue(): any {
|
||||
return this.coder.defaultValue();
|
||||
}
|
||||
|
||||
encode(writer: Writer, value: any): number {
|
||||
return this.coder.encode(writer, value);
|
||||
}
|
||||
|
||||
decode(reader: Reader): any {
|
||||
return this.coder.decode(reader);
|
||||
}
|
||||
}
|
||||
199
dev/env/node_modules/ethers/src.ts/abi/coders/array.ts
generated
vendored
Executable file
199
dev/env/node_modules/ethers/src.ts/abi/coders/array.ts
generated
vendored
Executable file
@@ -0,0 +1,199 @@
|
||||
import {
|
||||
defineProperties, isError, assert, assertArgument, assertArgumentCount
|
||||
} from "../../utils/index.js";
|
||||
|
||||
import { Typed } from "../typed.js";
|
||||
|
||||
import { Coder, Result, WordSize, Writer } from "./abstract-coder.js";
|
||||
import { AnonymousCoder } from "./anonymous.js";
|
||||
|
||||
import type { Reader } from "./abstract-coder.js";
|
||||
|
||||
/**
|
||||
* @_ignore
|
||||
*/
|
||||
export function pack(writer: Writer, coders: ReadonlyArray<Coder>, values: Array<any> | { [ name: string ]: any }): number {
|
||||
let arrayValues: Array<any> = [ ];
|
||||
|
||||
if (Array.isArray(values)) {
|
||||
arrayValues = values;
|
||||
|
||||
} else if (values && typeof(values) === "object") {
|
||||
let unique: { [ name: string ]: boolean } = { };
|
||||
|
||||
arrayValues = coders.map((coder) => {
|
||||
const name = coder.localName;
|
||||
assert(name, "cannot encode object for signature with missing names",
|
||||
"INVALID_ARGUMENT", { argument: "values", info: { coder }, value: values });
|
||||
|
||||
assert(!unique[name], "cannot encode object for signature with duplicate names",
|
||||
"INVALID_ARGUMENT", { argument: "values", info: { coder }, value: values });
|
||||
|
||||
unique[name] = true;
|
||||
|
||||
return values[name];
|
||||
});
|
||||
|
||||
} else {
|
||||
assertArgument(false, "invalid tuple value", "tuple", values);
|
||||
}
|
||||
|
||||
assertArgument(coders.length === arrayValues.length, "types/value length mismatch", "tuple", values);
|
||||
|
||||
let staticWriter = new Writer();
|
||||
let dynamicWriter = new Writer();
|
||||
|
||||
let updateFuncs: Array<(baseOffset: number) => void> = [];
|
||||
coders.forEach((coder, index) => {
|
||||
let value = arrayValues[index];
|
||||
|
||||
if (coder.dynamic) {
|
||||
// Get current dynamic offset (for the future pointer)
|
||||
let dynamicOffset = dynamicWriter.length;
|
||||
|
||||
// Encode the dynamic value into the dynamicWriter
|
||||
coder.encode(dynamicWriter, value);
|
||||
|
||||
// Prepare to populate the correct offset once we are done
|
||||
let updateFunc = staticWriter.writeUpdatableValue();
|
||||
updateFuncs.push((baseOffset: number) => {
|
||||
updateFunc(baseOffset + dynamicOffset);
|
||||
});
|
||||
|
||||
} else {
|
||||
coder.encode(staticWriter, value);
|
||||
}
|
||||
});
|
||||
|
||||
// Backfill all the dynamic offsets, now that we know the static length
|
||||
updateFuncs.forEach((func) => { func(staticWriter.length); });
|
||||
|
||||
let length = writer.appendWriter(staticWriter);
|
||||
length += writer.appendWriter(dynamicWriter);
|
||||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @_ignore
|
||||
*/
|
||||
export function unpack(reader: Reader, coders: ReadonlyArray<Coder>): Result {
|
||||
let values: Array<any> = [];
|
||||
let keys: Array<null | string> = [ ];
|
||||
|
||||
// A reader anchored to this base
|
||||
let baseReader = reader.subReader(0);
|
||||
|
||||
coders.forEach((coder) => {
|
||||
let value: any = null;
|
||||
|
||||
if (coder.dynamic) {
|
||||
let offset = reader.readIndex();
|
||||
let offsetReader = baseReader.subReader(offset);
|
||||
try {
|
||||
value = coder.decode(offsetReader);
|
||||
} catch (error: any) {
|
||||
// Cannot recover from this
|
||||
if (isError(error, "BUFFER_OVERRUN")) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
value = error;
|
||||
value.baseType = coder.name;
|
||||
value.name = coder.localName;
|
||||
value.type = coder.type;
|
||||
}
|
||||
|
||||
} else {
|
||||
try {
|
||||
value = coder.decode(reader);
|
||||
} catch (error: any) {
|
||||
// Cannot recover from this
|
||||
if (isError(error, "BUFFER_OVERRUN")) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
value = error;
|
||||
value.baseType = coder.name;
|
||||
value.name = coder.localName;
|
||||
value.type = coder.type;
|
||||
}
|
||||
}
|
||||
|
||||
if (value == undefined) {
|
||||
throw new Error("investigate");
|
||||
}
|
||||
|
||||
values.push(value);
|
||||
keys.push(coder.localName || null);
|
||||
});
|
||||
|
||||
return Result.fromItems(values, keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* @_ignore
|
||||
*/
|
||||
export class ArrayCoder extends Coder {
|
||||
readonly coder!: Coder;
|
||||
readonly length!: number;
|
||||
|
||||
constructor(coder: Coder, length: number, localName: string) {
|
||||
const type = (coder.type + "[" + (length >= 0 ? length: "") + "]");
|
||||
const dynamic = (length === -1 || coder.dynamic);
|
||||
super("array", type, localName, dynamic);
|
||||
defineProperties<ArrayCoder>(this, { coder, length });
|
||||
}
|
||||
|
||||
defaultValue(): Array<any> {
|
||||
// Verifies the child coder is valid (even if the array is dynamic or 0-length)
|
||||
const defaultChild = this.coder.defaultValue();
|
||||
|
||||
const result: Array<any> = [];
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
result.push(defaultChild);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
encode(writer: Writer, _value: Array<any> | Typed): number {
|
||||
const value = Typed.dereference(_value, "array");
|
||||
|
||||
if(!Array.isArray(value)) {
|
||||
this._throwError("expected array value", value);
|
||||
}
|
||||
|
||||
let count = this.length;
|
||||
|
||||
if (count === -1) {
|
||||
count = value.length;
|
||||
writer.writeValue(value.length);
|
||||
}
|
||||
|
||||
assertArgumentCount(value.length, count, "coder array" + (this.localName? (" "+ this.localName): ""));
|
||||
|
||||
let coders: Array<Coder> = [ ];
|
||||
for (let i = 0; i < value.length; i++) { coders.push(this.coder); }
|
||||
|
||||
return pack(writer, coders, value);
|
||||
}
|
||||
|
||||
decode(reader: Reader): any {
|
||||
let count = this.length;
|
||||
if (count === -1) {
|
||||
count = reader.readIndex();
|
||||
|
||||
// Check that there is *roughly* enough data to ensure
|
||||
// stray random data is not being read as a length. Each
|
||||
// slot requires at least 32 bytes for their value (or 32
|
||||
// bytes as a link to the data). This could use a much
|
||||
// tighter bound, but we are erroring on the side of safety.
|
||||
assert(count * WordSize <= reader.dataLength, "insufficient data length",
|
||||
"BUFFER_OVERRUN", { buffer: reader.bytes, offset: count * WordSize, length: reader.dataLength });
|
||||
}
|
||||
let coders: Array<Coder> = [];
|
||||
for (let i = 0; i < count; i++) { coders.push(new AnonymousCoder(this.coder)); }
|
||||
|
||||
return unpack(reader, coders);
|
||||
}
|
||||
}
|
||||
|
||||
27
dev/env/node_modules/ethers/src.ts/abi/coders/boolean.ts
generated
vendored
Executable file
27
dev/env/node_modules/ethers/src.ts/abi/coders/boolean.ts
generated
vendored
Executable file
@@ -0,0 +1,27 @@
|
||||
import { Typed } from "../typed.js";
|
||||
import { Coder } from "./abstract-coder.js";
|
||||
|
||||
import type { Reader, Writer } from "./abstract-coder.js";
|
||||
|
||||
/**
|
||||
* @_ignore
|
||||
*/
|
||||
export class BooleanCoder extends Coder {
|
||||
|
||||
constructor(localName: string) {
|
||||
super("bool", "bool", localName, false);
|
||||
}
|
||||
|
||||
defaultValue(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
encode(writer: Writer, _value: boolean | Typed): number {
|
||||
const value = Typed.dereference(_value, "bool");
|
||||
return writer.writeValue(value ? 1: 0);
|
||||
}
|
||||
|
||||
decode(reader: Reader): any {
|
||||
return !!reader.readValue();
|
||||
}
|
||||
}
|
||||
43
dev/env/node_modules/ethers/src.ts/abi/coders/bytes.ts
generated
vendored
Executable file
43
dev/env/node_modules/ethers/src.ts/abi/coders/bytes.ts
generated
vendored
Executable file
@@ -0,0 +1,43 @@
|
||||
import { getBytesCopy, hexlify } from "../../utils/index.js";
|
||||
|
||||
import { Coder } from "./abstract-coder.js";
|
||||
|
||||
import type { Reader, Writer } from "./abstract-coder.js";
|
||||
|
||||
|
||||
/**
|
||||
* @_ignore
|
||||
*/
|
||||
export class DynamicBytesCoder extends Coder {
|
||||
constructor(type: string, localName: string) {
|
||||
super(type, type, localName, true);
|
||||
}
|
||||
|
||||
defaultValue(): string {
|
||||
return "0x";
|
||||
}
|
||||
|
||||
encode(writer: Writer, value: any): number {
|
||||
value = getBytesCopy(value);
|
||||
let length = writer.writeValue(value.length);
|
||||
length += writer.writeBytes(value);
|
||||
return length;
|
||||
}
|
||||
|
||||
decode(reader: Reader): any {
|
||||
return reader.readBytes(reader.readIndex(), true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @_ignore
|
||||
*/
|
||||
export class BytesCoder extends DynamicBytesCoder {
|
||||
constructor(localName: string) {
|
||||
super("bytes", localName);
|
||||
}
|
||||
|
||||
decode(reader: Reader): any {
|
||||
return hexlify(super.decode(reader));
|
||||
}
|
||||
}
|
||||
37
dev/env/node_modules/ethers/src.ts/abi/coders/fixed-bytes.ts
generated
vendored
Executable file
37
dev/env/node_modules/ethers/src.ts/abi/coders/fixed-bytes.ts
generated
vendored
Executable file
@@ -0,0 +1,37 @@
|
||||
|
||||
import { defineProperties, getBytesCopy, hexlify } from "../../utils/index.js";
|
||||
|
||||
import { Typed } from "../typed.js";
|
||||
import { Coder } from "./abstract-coder.js";
|
||||
|
||||
import type { BytesLike } from "../../utils/index.js";
|
||||
|
||||
import type { Reader, Writer } from "./abstract-coder.js";
|
||||
|
||||
|
||||
/**
|
||||
* @_ignore
|
||||
*/
|
||||
export class FixedBytesCoder extends Coder {
|
||||
readonly size!: number;
|
||||
|
||||
constructor(size: number, localName: string) {
|
||||
let name = "bytes" + String(size);
|
||||
super(name, name, localName, false);
|
||||
defineProperties<FixedBytesCoder>(this, { size }, { size: "number" });
|
||||
}
|
||||
|
||||
defaultValue(): string {
|
||||
return ("0x0000000000000000000000000000000000000000000000000000000000000000").substring(0, 2 + this.size * 2);
|
||||
}
|
||||
|
||||
encode(writer: Writer, _value: BytesLike | Typed): number {
|
||||
let data = getBytesCopy(Typed.dereference(_value, this.type));
|
||||
if (data.length !== this.size) { this._throwError("incorrect data length", _value); }
|
||||
return writer.writeBytes(data);
|
||||
}
|
||||
|
||||
decode(reader: Reader): any {
|
||||
return hexlify(reader.readBytes(this.size));
|
||||
}
|
||||
}
|
||||
28
dev/env/node_modules/ethers/src.ts/abi/coders/null.ts
generated
vendored
Executable file
28
dev/env/node_modules/ethers/src.ts/abi/coders/null.ts
generated
vendored
Executable file
@@ -0,0 +1,28 @@
|
||||
import { Coder } from "./abstract-coder.js";
|
||||
import type { Reader, Writer } from "./abstract-coder.js";
|
||||
|
||||
const Empty = new Uint8Array([ ]);
|
||||
|
||||
/**
|
||||
* @_ignore
|
||||
*/
|
||||
export class NullCoder extends Coder {
|
||||
|
||||
constructor(localName: string) {
|
||||
super("null", "", localName, false);
|
||||
}
|
||||
|
||||
defaultValue(): null {
|
||||
return null;
|
||||
}
|
||||
|
||||
encode(writer: Writer, value: any): number {
|
||||
if (value != null) { this._throwError("not null", value); }
|
||||
return writer.writeBytes(Empty);
|
||||
}
|
||||
|
||||
decode(reader: Reader): any {
|
||||
reader.readBytes(0);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
63
dev/env/node_modules/ethers/src.ts/abi/coders/number.ts
generated
vendored
Executable file
63
dev/env/node_modules/ethers/src.ts/abi/coders/number.ts
generated
vendored
Executable file
@@ -0,0 +1,63 @@
|
||||
import {
|
||||
defineProperties, fromTwos, getBigInt, mask, toTwos
|
||||
} from "../../utils/index.js";
|
||||
|
||||
import { Typed } from "../typed.js";
|
||||
import { Coder, WordSize } from "./abstract-coder.js";
|
||||
|
||||
import type { BigNumberish } from "../../utils/index.js";
|
||||
|
||||
import type { Reader, Writer } from "./abstract-coder.js";
|
||||
|
||||
|
||||
const BN_0 = BigInt(0);
|
||||
const BN_1 = BigInt(1);
|
||||
const BN_MAX_UINT256 = BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
|
||||
|
||||
/**
|
||||
* @_ignore
|
||||
*/
|
||||
export class NumberCoder extends Coder {
|
||||
readonly size!: number;
|
||||
readonly signed!: boolean;
|
||||
|
||||
constructor(size: number, signed: boolean, localName: string) {
|
||||
const name = ((signed ? "int": "uint") + (size * 8));
|
||||
super(name, name, localName, false);
|
||||
|
||||
defineProperties<NumberCoder>(this, { size, signed }, { size: "number", signed: "boolean" });
|
||||
}
|
||||
|
||||
defaultValue(): number {
|
||||
return 0;
|
||||
}
|
||||
|
||||
encode(writer: Writer, _value: BigNumberish | Typed): number {
|
||||
let value = getBigInt(Typed.dereference(_value, this.type));
|
||||
|
||||
// Check bounds are safe for encoding
|
||||
let maxUintValue = mask(BN_MAX_UINT256, WordSize * 8);
|
||||
if (this.signed) {
|
||||
let bounds = mask(maxUintValue, (this.size * 8) - 1);
|
||||
if (value > bounds || value < -(bounds + BN_1)) {
|
||||
this._throwError("value out-of-bounds", _value);
|
||||
}
|
||||
value = toTwos(value, 8 * WordSize);
|
||||
} else if (value < BN_0 || value > mask(maxUintValue, this.size * 8)) {
|
||||
this._throwError("value out-of-bounds", _value);
|
||||
}
|
||||
|
||||
return writer.writeValue(value);
|
||||
}
|
||||
|
||||
decode(reader: Reader): any {
|
||||
let value = mask(reader.readValue(), this.size * 8);
|
||||
|
||||
if (this.signed) {
|
||||
value = fromTwos(value, this.size * 8);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
29
dev/env/node_modules/ethers/src.ts/abi/coders/string.ts
generated
vendored
Executable file
29
dev/env/node_modules/ethers/src.ts/abi/coders/string.ts
generated
vendored
Executable file
@@ -0,0 +1,29 @@
|
||||
import { toUtf8Bytes, toUtf8String } from "../../utils/utf8.js";
|
||||
|
||||
import { Typed } from "../typed.js";
|
||||
import { DynamicBytesCoder } from "./bytes.js";
|
||||
|
||||
import type { Reader, Writer } from "./abstract-coder.js";
|
||||
|
||||
|
||||
/**
|
||||
* @_ignore
|
||||
*/
|
||||
export class StringCoder extends DynamicBytesCoder {
|
||||
|
||||
constructor(localName: string) {
|
||||
super("string", localName);
|
||||
}
|
||||
|
||||
defaultValue(): string {
|
||||
return "";
|
||||
}
|
||||
|
||||
encode(writer: Writer, _value: string | Typed): number {
|
||||
return super.encode(writer, toUtf8Bytes(Typed.dereference(_value, "string")));
|
||||
}
|
||||
|
||||
decode(reader: Reader): any {
|
||||
return toUtf8String(super.decode(reader));
|
||||
}
|
||||
}
|
||||
69
dev/env/node_modules/ethers/src.ts/abi/coders/tuple.ts
generated
vendored
Executable file
69
dev/env/node_modules/ethers/src.ts/abi/coders/tuple.ts
generated
vendored
Executable file
@@ -0,0 +1,69 @@
|
||||
import { defineProperties } from "../../utils/properties.js";
|
||||
|
||||
import { Typed } from "../typed.js";
|
||||
import { Coder } from "./abstract-coder.js";
|
||||
|
||||
import { pack, unpack } from "./array.js";
|
||||
|
||||
import type { Reader, Writer } from "./abstract-coder.js";
|
||||
|
||||
/**
|
||||
* @_ignore
|
||||
*/
|
||||
export class TupleCoder extends Coder {
|
||||
readonly coders!: ReadonlyArray<Coder>;
|
||||
|
||||
constructor(coders: Array<Coder>, localName: string) {
|
||||
let dynamic = false;
|
||||
const types: Array<string> = [];
|
||||
coders.forEach((coder) => {
|
||||
if (coder.dynamic) { dynamic = true; }
|
||||
types.push(coder.type);
|
||||
});
|
||||
const type = ("tuple(" + types.join(",") + ")");
|
||||
|
||||
super("tuple", type, localName, dynamic);
|
||||
defineProperties<TupleCoder>(this, { coders: Object.freeze(coders.slice()) });
|
||||
}
|
||||
|
||||
defaultValue(): any {
|
||||
const values: any = [ ];
|
||||
this.coders.forEach((coder) => {
|
||||
values.push(coder.defaultValue());
|
||||
});
|
||||
|
||||
// We only output named properties for uniquely named coders
|
||||
const uniqueNames = this.coders.reduce((accum, coder) => {
|
||||
const name = coder.localName;
|
||||
if (name) {
|
||||
if (!accum[name]) { accum[name] = 0; }
|
||||
accum[name]++;
|
||||
}
|
||||
return accum;
|
||||
}, <{ [ name: string ]: number }>{ });
|
||||
|
||||
// Add named values
|
||||
this.coders.forEach((coder: Coder, index: number) => {
|
||||
let name = coder.localName;
|
||||
if (!name || uniqueNames[name] !== 1) { return; }
|
||||
|
||||
if (name === "length") { name = "_length"; }
|
||||
|
||||
if (values[name] != null) { return; }
|
||||
|
||||
values[name] = values[index];
|
||||
});
|
||||
|
||||
return Object.freeze(values);
|
||||
}
|
||||
|
||||
encode(writer: Writer, _value: Array<any> | { [ name: string ]: any } | Typed): number {
|
||||
const value = Typed.dereference(_value, "tuple");
|
||||
return pack(writer, this.coders, value);
|
||||
}
|
||||
|
||||
decode(reader: Reader): any {
|
||||
return unpack(reader, this.coders);
|
||||
}
|
||||
}
|
||||
|
||||
1617
dev/env/node_modules/ethers/src.ts/abi/fragments.ts
generated
vendored
Executable file
1617
dev/env/node_modules/ethers/src.ts/abi/fragments.ts
generated
vendored
Executable file
File diff suppressed because it is too large
Load Diff
41
dev/env/node_modules/ethers/src.ts/abi/index.ts
generated
vendored
Executable file
41
dev/env/node_modules/ethers/src.ts/abi/index.ts
generated
vendored
Executable file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* The Application Binary Interface (ABI) describes how method input
|
||||
* parameters should be encoded, their results decoded, and how to
|
||||
* decode events and errors.
|
||||
*
|
||||
* See [About ABIs](docs-abi) for more details how they are used.
|
||||
*
|
||||
* @_section api/abi:Application Binary Interface [about-abi]
|
||||
* @_navTitle: ABI
|
||||
*/
|
||||
|
||||
|
||||
//////
|
||||
export { AbiCoder } from "./abi-coder.js";
|
||||
|
||||
export { decodeBytes32String, encodeBytes32String } from "./bytes32.js";
|
||||
|
||||
export {
|
||||
ConstructorFragment, ErrorFragment, EventFragment, FallbackFragment,
|
||||
Fragment, FunctionFragment, NamedFragment, ParamType, StructFragment,
|
||||
} from "./fragments.js";
|
||||
|
||||
export {
|
||||
checkResultErrors,
|
||||
Indexed,
|
||||
Interface,
|
||||
ErrorDescription, LogDescription, TransactionDescription,
|
||||
Result
|
||||
} from "./interface.js";
|
||||
|
||||
export { Typed } from "./typed.js";
|
||||
|
||||
export type {
|
||||
JsonFragment, JsonFragmentType,
|
||||
FormatType, FragmentType, ParamTypeWalkAsyncFunc, ParamTypeWalkFunc
|
||||
} from "./fragments.js";
|
||||
|
||||
export type {
|
||||
InterfaceAbi,
|
||||
} from "./interface.js";
|
||||
|
||||
1271
dev/env/node_modules/ethers/src.ts/abi/interface.ts
generated
vendored
Executable file
1271
dev/env/node_modules/ethers/src.ts/abi/interface.ts
generated
vendored
Executable file
File diff suppressed because it is too large
Load Diff
796
dev/env/node_modules/ethers/src.ts/abi/typed.ts
generated
vendored
Executable file
796
dev/env/node_modules/ethers/src.ts/abi/typed.ts
generated
vendored
Executable file
@@ -0,0 +1,796 @@
|
||||
/**
|
||||
* A Typed object allows a value to have its type explicitly
|
||||
* specified.
|
||||
*
|
||||
* For example, in Solidity, the value ``45`` could represent a
|
||||
* ``uint8`` or a ``uint256``. The value ``0x1234`` could represent
|
||||
* a ``bytes2`` or ``bytes``.
|
||||
*
|
||||
* Since JavaScript has no meaningful way to explicitly inform any
|
||||
* APIs which what the type is, this allows transparent interoperation
|
||||
* with Soldity.
|
||||
*
|
||||
* @_subsection: api/abi:Typed Values
|
||||
*/
|
||||
|
||||
import { assertPrivate, defineProperties } from "../utils/index.js";
|
||||
|
||||
import type { Addressable } from "../address/index.js";
|
||||
import type { BigNumberish, BytesLike } from "../utils/index.js";
|
||||
|
||||
import type { Result } from "./coders/abstract-coder.js";
|
||||
|
||||
const _gaurd = { };
|
||||
|
||||
function n(value: BigNumberish, width: number): Typed {
|
||||
let signed = false;
|
||||
if (width < 0) {
|
||||
signed = true;
|
||||
width *= -1;
|
||||
}
|
||||
|
||||
// @TODO: Check range is valid for value
|
||||
return new Typed(_gaurd, `${ signed ? "": "u" }int${ width }`, value, { signed, width });
|
||||
}
|
||||
|
||||
function b(value: BytesLike, size?: number): Typed {
|
||||
// @TODO: Check range is valid for value
|
||||
return new Typed(_gaurd, `bytes${ (size) ? size: "" }`, value, { size });
|
||||
}
|
||||
|
||||
// @TODO: Remove this in v7, it was replaced by TypedBigInt
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
export interface TypedNumber extends Typed {
|
||||
value: number;
|
||||
defaultValue(): number;
|
||||
minValue(): number;
|
||||
maxValue(): number;
|
||||
}
|
||||
|
||||
/**
|
||||
* A **Typed** that represents a numeric value.
|
||||
*/
|
||||
export interface TypedBigInt extends Typed {
|
||||
/**
|
||||
* The value.
|
||||
*/
|
||||
value: bigint;
|
||||
|
||||
/**
|
||||
* The default value for all numeric types is ``0``.
|
||||
*/
|
||||
defaultValue(): bigint;
|
||||
|
||||
/**
|
||||
* The minimum value for this type, accounting for bit-width and signed-ness.
|
||||
*/
|
||||
minValue(): bigint;
|
||||
|
||||
/**
|
||||
* The minimum value for this type, accounting for bit-width.
|
||||
*/
|
||||
maxValue(): bigint;
|
||||
}
|
||||
|
||||
/**
|
||||
* A **Typed** that represents a binary sequence of data as bytes.
|
||||
*/
|
||||
export interface TypedData extends Typed {
|
||||
/**
|
||||
* The value.
|
||||
*/
|
||||
value: string;
|
||||
|
||||
/**
|
||||
* The default value for this type.
|
||||
*/
|
||||
defaultValue(): string;
|
||||
}
|
||||
|
||||
/**
|
||||
* A **Typed** that represents a UTF-8 sequence of bytes.
|
||||
*/
|
||||
export interface TypedString extends Typed {
|
||||
/**
|
||||
* The value.
|
||||
*/
|
||||
value: string;
|
||||
|
||||
/**
|
||||
* The default value for the string type is the empty string (i.e. ``""``).
|
||||
*/
|
||||
defaultValue(): string;
|
||||
}
|
||||
|
||||
const _typedSymbol = Symbol.for("_ethers_typed");
|
||||
|
||||
/**
|
||||
* The **Typed** class to wrap values providing explicit type information.
|
||||
*/
|
||||
export class Typed {
|
||||
|
||||
/**
|
||||
* The type, as a Solidity-compatible type.
|
||||
*/
|
||||
readonly type!: string;
|
||||
|
||||
/**
|
||||
* The actual value.
|
||||
*/
|
||||
readonly value!: any;
|
||||
|
||||
readonly #options: any;
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
readonly _typedSymbol!: Symbol;
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
constructor(gaurd: any, type: string, value: any, options?: any) {
|
||||
if (options == null) { options = null; }
|
||||
assertPrivate(_gaurd, gaurd, "Typed");
|
||||
defineProperties<Typed>(this, { _typedSymbol, type, value });
|
||||
this.#options = options;
|
||||
|
||||
// Check the value is valid
|
||||
this.format();
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the type as a Human-Readable type.
|
||||
*/
|
||||
format(): string {
|
||||
if (this.type === "array") {
|
||||
throw new Error("");
|
||||
} else if (this.type === "dynamicArray") {
|
||||
throw new Error("");
|
||||
} else if (this.type === "tuple") {
|
||||
return `tuple(${ this.value.map((v: Typed) => v.format()).join(",") })`
|
||||
}
|
||||
|
||||
return this.type;
|
||||
}
|
||||
|
||||
/**
|
||||
* The default value returned by this type.
|
||||
*/
|
||||
defaultValue(): string | number | bigint | Result {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* The minimum value for numeric types.
|
||||
*/
|
||||
minValue(): string | number | bigint {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* The maximum value for numeric types.
|
||||
*/
|
||||
maxValue(): string | number | bigint {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ``true`` and provides a type guard is this is a [[TypedBigInt]].
|
||||
*/
|
||||
isBigInt(): this is TypedBigInt {
|
||||
return !!(this.type.match(/^u?int[0-9]+$/));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ``true`` and provides a type guard is this is a [[TypedData]].
|
||||
*/
|
||||
isData(): this is TypedData {
|
||||
return this.type.startsWith("bytes");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ``true`` and provides a type guard is this is a [[TypedString]].
|
||||
*/
|
||||
isString(): this is TypedString {
|
||||
return (this.type === "string");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the tuple name, if this is a tuple. Throws otherwise.
|
||||
*/
|
||||
get tupleName(): null | string {
|
||||
if (this.type !== "tuple") { throw TypeError("not a tuple"); }
|
||||
return this.#options;
|
||||
}
|
||||
|
||||
// Returns the length of this type as an array
|
||||
// - `null` indicates the length is unforced, it could be dynamic
|
||||
// - `-1` indicates the length is dynamic
|
||||
// - any other value indicates it is a static array and is its length
|
||||
|
||||
/**
|
||||
* Returns the length of the array type or ``-1`` if it is dynamic.
|
||||
*
|
||||
* Throws if the type is not an array.
|
||||
*/
|
||||
get arrayLength(): null | number {
|
||||
if (this.type !== "array") { throw TypeError("not an array"); }
|
||||
if (this.#options === true) { return -1; }
|
||||
if (this.#options === false) { return (<Array<any>>(this.value)).length; }
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new **Typed** of %%type%% with the %%value%%.
|
||||
*/
|
||||
static from(type: string, value: any): Typed {
|
||||
return new Typed(_gaurd, type, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new ``uint8`` type for %%v%%.
|
||||
*/
|
||||
static uint8(v: BigNumberish): Typed { return n(v, 8); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint16`` type for %%v%%.
|
||||
*/
|
||||
static uint16(v: BigNumberish): Typed { return n(v, 16); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint24`` type for %%v%%.
|
||||
*/
|
||||
static uint24(v: BigNumberish): Typed { return n(v, 24); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint32`` type for %%v%%.
|
||||
*/
|
||||
static uint32(v: BigNumberish): Typed { return n(v, 32); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint40`` type for %%v%%.
|
||||
*/
|
||||
static uint40(v: BigNumberish): Typed { return n(v, 40); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint48`` type for %%v%%.
|
||||
*/
|
||||
static uint48(v: BigNumberish): Typed { return n(v, 48); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint56`` type for %%v%%.
|
||||
*/
|
||||
static uint56(v: BigNumberish): Typed { return n(v, 56); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint64`` type for %%v%%.
|
||||
*/
|
||||
static uint64(v: BigNumberish): Typed { return n(v, 64); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint72`` type for %%v%%.
|
||||
*/
|
||||
static uint72(v: BigNumberish): Typed { return n(v, 72); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint80`` type for %%v%%.
|
||||
*/
|
||||
static uint80(v: BigNumberish): Typed { return n(v, 80); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint88`` type for %%v%%.
|
||||
*/
|
||||
static uint88(v: BigNumberish): Typed { return n(v, 88); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint96`` type for %%v%%.
|
||||
*/
|
||||
static uint96(v: BigNumberish): Typed { return n(v, 96); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint104`` type for %%v%%.
|
||||
*/
|
||||
static uint104(v: BigNumberish): Typed { return n(v, 104); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint112`` type for %%v%%.
|
||||
*/
|
||||
static uint112(v: BigNumberish): Typed { return n(v, 112); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint120`` type for %%v%%.
|
||||
*/
|
||||
static uint120(v: BigNumberish): Typed { return n(v, 120); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint128`` type for %%v%%.
|
||||
*/
|
||||
static uint128(v: BigNumberish): Typed { return n(v, 128); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint136`` type for %%v%%.
|
||||
*/
|
||||
static uint136(v: BigNumberish): Typed { return n(v, 136); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint144`` type for %%v%%.
|
||||
*/
|
||||
static uint144(v: BigNumberish): Typed { return n(v, 144); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint152`` type for %%v%%.
|
||||
*/
|
||||
static uint152(v: BigNumberish): Typed { return n(v, 152); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint160`` type for %%v%%.
|
||||
*/
|
||||
static uint160(v: BigNumberish): Typed { return n(v, 160); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint168`` type for %%v%%.
|
||||
*/
|
||||
static uint168(v: BigNumberish): Typed { return n(v, 168); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint176`` type for %%v%%.
|
||||
*/
|
||||
static uint176(v: BigNumberish): Typed { return n(v, 176); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint184`` type for %%v%%.
|
||||
*/
|
||||
static uint184(v: BigNumberish): Typed { return n(v, 184); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint192`` type for %%v%%.
|
||||
*/
|
||||
static uint192(v: BigNumberish): Typed { return n(v, 192); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint200`` type for %%v%%.
|
||||
*/
|
||||
static uint200(v: BigNumberish): Typed { return n(v, 200); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint208`` type for %%v%%.
|
||||
*/
|
||||
static uint208(v: BigNumberish): Typed { return n(v, 208); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint216`` type for %%v%%.
|
||||
*/
|
||||
static uint216(v: BigNumberish): Typed { return n(v, 216); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint224`` type for %%v%%.
|
||||
*/
|
||||
static uint224(v: BigNumberish): Typed { return n(v, 224); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint232`` type for %%v%%.
|
||||
*/
|
||||
static uint232(v: BigNumberish): Typed { return n(v, 232); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint240`` type for %%v%%.
|
||||
*/
|
||||
static uint240(v: BigNumberish): Typed { return n(v, 240); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint248`` type for %%v%%.
|
||||
*/
|
||||
static uint248(v: BigNumberish): Typed { return n(v, 248); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint256`` type for %%v%%.
|
||||
*/
|
||||
static uint256(v: BigNumberish): Typed { return n(v, 256); }
|
||||
|
||||
/**
|
||||
* Return a new ``uint256`` type for %%v%%.
|
||||
*/
|
||||
static uint(v: BigNumberish): Typed { return n(v, 256); }
|
||||
|
||||
/**
|
||||
* Return a new ``int8`` type for %%v%%.
|
||||
*/
|
||||
static int8(v: BigNumberish): Typed { return n(v, -8); }
|
||||
|
||||
/**
|
||||
* Return a new ``int16`` type for %%v%%.
|
||||
*/
|
||||
static int16(v: BigNumberish): Typed { return n(v, -16); }
|
||||
|
||||
/**
|
||||
* Return a new ``int24`` type for %%v%%.
|
||||
*/
|
||||
static int24(v: BigNumberish): Typed { return n(v, -24); }
|
||||
|
||||
/**
|
||||
* Return a new ``int32`` type for %%v%%.
|
||||
*/
|
||||
static int32(v: BigNumberish): Typed { return n(v, -32); }
|
||||
|
||||
/**
|
||||
* Return a new ``int40`` type for %%v%%.
|
||||
*/
|
||||
static int40(v: BigNumberish): Typed { return n(v, -40); }
|
||||
|
||||
/**
|
||||
* Return a new ``int48`` type for %%v%%.
|
||||
*/
|
||||
static int48(v: BigNumberish): Typed { return n(v, -48); }
|
||||
|
||||
/**
|
||||
* Return a new ``int56`` type for %%v%%.
|
||||
*/
|
||||
static int56(v: BigNumberish): Typed { return n(v, -56); }
|
||||
|
||||
/**
|
||||
* Return a new ``int64`` type for %%v%%.
|
||||
*/
|
||||
static int64(v: BigNumberish): Typed { return n(v, -64); }
|
||||
|
||||
/**
|
||||
* Return a new ``int72`` type for %%v%%.
|
||||
*/
|
||||
static int72(v: BigNumberish): Typed { return n(v, -72); }
|
||||
|
||||
/**
|
||||
* Return a new ``int80`` type for %%v%%.
|
||||
*/
|
||||
static int80(v: BigNumberish): Typed { return n(v, -80); }
|
||||
|
||||
/**
|
||||
* Return a new ``int88`` type for %%v%%.
|
||||
*/
|
||||
static int88(v: BigNumberish): Typed { return n(v, -88); }
|
||||
|
||||
/**
|
||||
* Return a new ``int96`` type for %%v%%.
|
||||
*/
|
||||
static int96(v: BigNumberish): Typed { return n(v, -96); }
|
||||
|
||||
/**
|
||||
* Return a new ``int104`` type for %%v%%.
|
||||
*/
|
||||
static int104(v: BigNumberish): Typed { return n(v, -104); }
|
||||
|
||||
/**
|
||||
* Return a new ``int112`` type for %%v%%.
|
||||
*/
|
||||
static int112(v: BigNumberish): Typed { return n(v, -112); }
|
||||
|
||||
/**
|
||||
* Return a new ``int120`` type for %%v%%.
|
||||
*/
|
||||
static int120(v: BigNumberish): Typed { return n(v, -120); }
|
||||
|
||||
/**
|
||||
* Return a new ``int128`` type for %%v%%.
|
||||
*/
|
||||
static int128(v: BigNumberish): Typed { return n(v, -128); }
|
||||
|
||||
/**
|
||||
* Return a new ``int136`` type for %%v%%.
|
||||
*/
|
||||
static int136(v: BigNumberish): Typed { return n(v, -136); }
|
||||
|
||||
/**
|
||||
* Return a new ``int144`` type for %%v%%.
|
||||
*/
|
||||
static int144(v: BigNumberish): Typed { return n(v, -144); }
|
||||
|
||||
/**
|
||||
* Return a new ``int52`` type for %%v%%.
|
||||
*/
|
||||
static int152(v: BigNumberish): Typed { return n(v, -152); }
|
||||
|
||||
/**
|
||||
* Return a new ``int160`` type for %%v%%.
|
||||
*/
|
||||
static int160(v: BigNumberish): Typed { return n(v, -160); }
|
||||
|
||||
/**
|
||||
* Return a new ``int168`` type for %%v%%.
|
||||
*/
|
||||
static int168(v: BigNumberish): Typed { return n(v, -168); }
|
||||
|
||||
/**
|
||||
* Return a new ``int176`` type for %%v%%.
|
||||
*/
|
||||
static int176(v: BigNumberish): Typed { return n(v, -176); }
|
||||
|
||||
/**
|
||||
* Return a new ``int184`` type for %%v%%.
|
||||
*/
|
||||
static int184(v: BigNumberish): Typed { return n(v, -184); }
|
||||
|
||||
/**
|
||||
* Return a new ``int92`` type for %%v%%.
|
||||
*/
|
||||
static int192(v: BigNumberish): Typed { return n(v, -192); }
|
||||
|
||||
/**
|
||||
* Return a new ``int200`` type for %%v%%.
|
||||
*/
|
||||
static int200(v: BigNumberish): Typed { return n(v, -200); }
|
||||
|
||||
/**
|
||||
* Return a new ``int208`` type for %%v%%.
|
||||
*/
|
||||
static int208(v: BigNumberish): Typed { return n(v, -208); }
|
||||
|
||||
/**
|
||||
* Return a new ``int216`` type for %%v%%.
|
||||
*/
|
||||
static int216(v: BigNumberish): Typed { return n(v, -216); }
|
||||
|
||||
/**
|
||||
* Return a new ``int224`` type for %%v%%.
|
||||
*/
|
||||
static int224(v: BigNumberish): Typed { return n(v, -224); }
|
||||
|
||||
/**
|
||||
* Return a new ``int232`` type for %%v%%.
|
||||
*/
|
||||
static int232(v: BigNumberish): Typed { return n(v, -232); }
|
||||
|
||||
/**
|
||||
* Return a new ``int240`` type for %%v%%.
|
||||
*/
|
||||
static int240(v: BigNumberish): Typed { return n(v, -240); }
|
||||
|
||||
/**
|
||||
* Return a new ``int248`` type for %%v%%.
|
||||
*/
|
||||
static int248(v: BigNumberish): Typed { return n(v, -248); }
|
||||
|
||||
/**
|
||||
* Return a new ``int256`` type for %%v%%.
|
||||
*/
|
||||
static int256(v: BigNumberish): Typed { return n(v, -256); }
|
||||
|
||||
/**
|
||||
* Return a new ``int256`` type for %%v%%.
|
||||
*/
|
||||
static int(v: BigNumberish): Typed { return n(v, -256); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes1`` type for %%v%%.
|
||||
*/
|
||||
static bytes1(v: BytesLike): Typed { return b(v, 1); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes2`` type for %%v%%.
|
||||
*/
|
||||
static bytes2(v: BytesLike): Typed { return b(v, 2); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes3`` type for %%v%%.
|
||||
*/
|
||||
static bytes3(v: BytesLike): Typed { return b(v, 3); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes4`` type for %%v%%.
|
||||
*/
|
||||
static bytes4(v: BytesLike): Typed { return b(v, 4); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes5`` type for %%v%%.
|
||||
*/
|
||||
static bytes5(v: BytesLike): Typed { return b(v, 5); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes6`` type for %%v%%.
|
||||
*/
|
||||
static bytes6(v: BytesLike): Typed { return b(v, 6); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes7`` type for %%v%%.
|
||||
*/
|
||||
static bytes7(v: BytesLike): Typed { return b(v, 7); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes8`` type for %%v%%.
|
||||
*/
|
||||
static bytes8(v: BytesLike): Typed { return b(v, 8); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes9`` type for %%v%%.
|
||||
*/
|
||||
static bytes9(v: BytesLike): Typed { return b(v, 9); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes10`` type for %%v%%.
|
||||
*/
|
||||
static bytes10(v: BytesLike): Typed { return b(v, 10); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes11`` type for %%v%%.
|
||||
*/
|
||||
static bytes11(v: BytesLike): Typed { return b(v, 11); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes12`` type for %%v%%.
|
||||
*/
|
||||
static bytes12(v: BytesLike): Typed { return b(v, 12); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes13`` type for %%v%%.
|
||||
*/
|
||||
static bytes13(v: BytesLike): Typed { return b(v, 13); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes14`` type for %%v%%.
|
||||
*/
|
||||
static bytes14(v: BytesLike): Typed { return b(v, 14); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes15`` type for %%v%%.
|
||||
*/
|
||||
static bytes15(v: BytesLike): Typed { return b(v, 15); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes16`` type for %%v%%.
|
||||
*/
|
||||
static bytes16(v: BytesLike): Typed { return b(v, 16); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes17`` type for %%v%%.
|
||||
*/
|
||||
static bytes17(v: BytesLike): Typed { return b(v, 17); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes18`` type for %%v%%.
|
||||
*/
|
||||
static bytes18(v: BytesLike): Typed { return b(v, 18); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes19`` type for %%v%%.
|
||||
*/
|
||||
static bytes19(v: BytesLike): Typed { return b(v, 19); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes20`` type for %%v%%.
|
||||
*/
|
||||
static bytes20(v: BytesLike): Typed { return b(v, 20); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes21`` type for %%v%%.
|
||||
*/
|
||||
static bytes21(v: BytesLike): Typed { return b(v, 21); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes22`` type for %%v%%.
|
||||
*/
|
||||
static bytes22(v: BytesLike): Typed { return b(v, 22); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes23`` type for %%v%%.
|
||||
*/
|
||||
static bytes23(v: BytesLike): Typed { return b(v, 23); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes24`` type for %%v%%.
|
||||
*/
|
||||
static bytes24(v: BytesLike): Typed { return b(v, 24); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes25`` type for %%v%%.
|
||||
*/
|
||||
static bytes25(v: BytesLike): Typed { return b(v, 25); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes26`` type for %%v%%.
|
||||
*/
|
||||
static bytes26(v: BytesLike): Typed { return b(v, 26); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes27`` type for %%v%%.
|
||||
*/
|
||||
static bytes27(v: BytesLike): Typed { return b(v, 27); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes28`` type for %%v%%.
|
||||
*/
|
||||
static bytes28(v: BytesLike): Typed { return b(v, 28); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes29`` type for %%v%%.
|
||||
*/
|
||||
static bytes29(v: BytesLike): Typed { return b(v, 29); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes30`` type for %%v%%.
|
||||
*/
|
||||
static bytes30(v: BytesLike): Typed { return b(v, 30); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes31`` type for %%v%%.
|
||||
*/
|
||||
static bytes31(v: BytesLike): Typed { return b(v, 31); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes32`` type for %%v%%.
|
||||
*/
|
||||
static bytes32(v: BytesLike): Typed { return b(v, 32); }
|
||||
|
||||
|
||||
/**
|
||||
* Return a new ``address`` type for %%v%%.
|
||||
*/
|
||||
static address(v: string | Addressable): Typed { return new Typed(_gaurd, "address", v); }
|
||||
|
||||
/**
|
||||
* Return a new ``bool`` type for %%v%%.
|
||||
*/
|
||||
static bool(v: any): Typed { return new Typed(_gaurd, "bool", !!v); }
|
||||
|
||||
/**
|
||||
* Return a new ``bytes`` type for %%v%%.
|
||||
*/
|
||||
static bytes(v: BytesLike): Typed { return new Typed(_gaurd, "bytes", v); }
|
||||
|
||||
/**
|
||||
* Return a new ``string`` type for %%v%%.
|
||||
*/
|
||||
static string(v: string): Typed { return new Typed(_gaurd, "string", v); }
|
||||
|
||||
|
||||
/**
|
||||
* Return a new ``array`` type for %%v%%, allowing %%dynamic%% length.
|
||||
*/
|
||||
static array(v: Array<any | Typed>, dynamic?: null | boolean): Typed {
|
||||
throw new Error("not implemented yet");
|
||||
return new Typed(_gaurd, "array", v, dynamic);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a new ``tuple`` type for %%v%%, with the optional %%name%%.
|
||||
*/
|
||||
static tuple(v: Array<any | Typed> | Record<string, any | Typed>, name?: string): Typed {
|
||||
throw new Error("not implemented yet");
|
||||
return new Typed(_gaurd, "tuple", v, name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a new ``uint8`` type for %%v%%.
|
||||
*/
|
||||
static overrides(v: Record<string, any>): Typed {
|
||||
return new Typed(_gaurd, "overrides", Object.assign({ }, v));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true only if %%value%% is a [[Typed]] instance.
|
||||
*/
|
||||
static isTyped(value: any): value is Typed {
|
||||
return (value
|
||||
&& typeof(value) === "object"
|
||||
&& "_typedSymbol" in value
|
||||
&& value._typedSymbol === _typedSymbol);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the value is a [[Typed]] instance, validates the underlying value
|
||||
* and returns it, otherwise returns value directly.
|
||||
*
|
||||
* This is useful for functions that with to accept either a [[Typed]]
|
||||
* object or values.
|
||||
*/
|
||||
static dereference<T>(value: Typed | T, type: string): T {
|
||||
if (Typed.isTyped(value)) {
|
||||
if (value.type !== type) {
|
||||
throw new Error(`invalid type: expecetd ${ type }, got ${ value.type }`);
|
||||
}
|
||||
return value.value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
173
dev/env/node_modules/ethers/src.ts/address/address.ts
generated
vendored
Executable file
173
dev/env/node_modules/ethers/src.ts/address/address.ts
generated
vendored
Executable file
@@ -0,0 +1,173 @@
|
||||
import { keccak256 } from "../crypto/index.js";
|
||||
import { getBytes, assertArgument } from "../utils/index.js";
|
||||
|
||||
|
||||
const BN_0 = BigInt(0);
|
||||
const BN_36 = BigInt(36);
|
||||
|
||||
function getChecksumAddress(address: string): string {
|
||||
// if (!isHexString(address, 20)) {
|
||||
// logger.throwArgumentError("invalid address", "address", address);
|
||||
// }
|
||||
|
||||
address = address.toLowerCase();
|
||||
|
||||
const chars = address.substring(2).split("");
|
||||
|
||||
const expanded = new Uint8Array(40);
|
||||
for (let i = 0; i < 40; i++) {
|
||||
expanded[i] = chars[i].charCodeAt(0);
|
||||
}
|
||||
|
||||
const hashed = getBytes(keccak256(expanded));
|
||||
|
||||
for (let i = 0; i < 40; i += 2) {
|
||||
if ((hashed[i >> 1] >> 4) >= 8) {
|
||||
chars[i] = chars[i].toUpperCase();
|
||||
}
|
||||
if ((hashed[i >> 1] & 0x0f) >= 8) {
|
||||
chars[i + 1] = chars[i + 1].toUpperCase();
|
||||
}
|
||||
}
|
||||
|
||||
return "0x" + chars.join("");
|
||||
}
|
||||
|
||||
// See: https://en.wikipedia.org/wiki/International_Bank_Account_Number
|
||||
|
||||
// Create lookup table
|
||||
const ibanLookup: { [character: string]: string } = { };
|
||||
for (let i = 0; i < 10; i++) { ibanLookup[String(i)] = String(i); }
|
||||
for (let i = 0; i < 26; i++) { ibanLookup[String.fromCharCode(65 + i)] = String(10 + i); }
|
||||
|
||||
// How many decimal digits can we process? (for 64-bit float, this is 15)
|
||||
// i.e. Math.floor(Math.log10(Number.MAX_SAFE_INTEGER));
|
||||
const safeDigits = 15;
|
||||
|
||||
function ibanChecksum(address: string): string {
|
||||
address = address.toUpperCase();
|
||||
address = address.substring(4) + address.substring(0, 2) + "00";
|
||||
|
||||
let expanded = address.split("").map((c) => { return ibanLookup[c]; }).join("");
|
||||
|
||||
// Javascript can handle integers safely up to 15 (decimal) digits
|
||||
while (expanded.length >= safeDigits){
|
||||
let block = expanded.substring(0, safeDigits);
|
||||
expanded = parseInt(block, 10) % 97 + expanded.substring(block.length);
|
||||
}
|
||||
|
||||
let checksum = String(98 - (parseInt(expanded, 10) % 97));
|
||||
while (checksum.length < 2) { checksum = "0" + checksum; }
|
||||
|
||||
return checksum;
|
||||
};
|
||||
|
||||
const Base36 = (function() {;
|
||||
const result: Record<string, bigint> = { };
|
||||
for (let i = 0; i < 36; i++) {
|
||||
const key = "0123456789abcdefghijklmnopqrstuvwxyz"[i];
|
||||
result[key] = BigInt(i);
|
||||
}
|
||||
return result;
|
||||
})();
|
||||
|
||||
function fromBase36(value: string): bigint {
|
||||
value = value.toLowerCase();
|
||||
|
||||
let result = BN_0;
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
result = result * BN_36 + Base36[value[i]];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a normalized and checksumed address for %%address%%.
|
||||
* This accepts non-checksum addresses, checksum addresses and
|
||||
* [[getIcapAddress]] formats.
|
||||
*
|
||||
* The checksum in Ethereum uses the capitalization (upper-case
|
||||
* vs lower-case) of the characters within an address to encode
|
||||
* its checksum, which offers, on average, a checksum of 15-bits.
|
||||
*
|
||||
* If %%address%% contains both upper-case and lower-case, it is
|
||||
* assumed to already be a checksum address and its checksum is
|
||||
* validated, and if the address fails its expected checksum an
|
||||
* error is thrown.
|
||||
*
|
||||
* If you wish the checksum of %%address%% to be ignore, it should
|
||||
* be converted to lower-case (i.e. ``.toLowercase()``) before
|
||||
* being passed in. This should be a very rare situation though,
|
||||
* that you wish to bypass the safegaurds in place to protect
|
||||
* against an address that has been incorrectly copied from another
|
||||
* source.
|
||||
*
|
||||
* @example:
|
||||
* // Adds the checksum (via upper-casing specific letters)
|
||||
* getAddress("0x8ba1f109551bd432803012645ac136ddd64dba72")
|
||||
* //_result:
|
||||
*
|
||||
* // Converts ICAP address and adds checksum
|
||||
* getAddress("XE65GB6LDNXYOFTX0NSV3FUWKOWIXAMJK36");
|
||||
* //_result:
|
||||
*
|
||||
* // Throws an error if an address contains mixed case,
|
||||
* // but the checksum fails
|
||||
* getAddress("0x8Ba1f109551bD432803012645Ac136ddd64DBA72")
|
||||
* //_error:
|
||||
*/
|
||||
export function getAddress(address: string): string {
|
||||
|
||||
assertArgument(typeof(address) === "string", "invalid address", "address", address);
|
||||
|
||||
if (address.match(/^(0x)?[0-9a-fA-F]{40}$/)) {
|
||||
|
||||
// Missing the 0x prefix
|
||||
if (!address.startsWith("0x")) { address = "0x" + address; }
|
||||
|
||||
const result = getChecksumAddress(address);
|
||||
|
||||
// It is a checksummed address with a bad checksum
|
||||
assertArgument(!address.match(/([A-F].*[a-f])|([a-f].*[A-F])/) || result === address,
|
||||
"bad address checksum", "address", address);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Maybe ICAP? (we only support direct mode)
|
||||
if (address.match(/^XE[0-9]{2}[0-9A-Za-z]{30,31}$/)) {
|
||||
// It is an ICAP address with a bad checksum
|
||||
assertArgument(address.substring(2, 4) === ibanChecksum(address), "bad icap checksum", "address", address);
|
||||
|
||||
let result = fromBase36(address.substring(4)).toString(16);
|
||||
while (result.length < 40) { result = "0" + result; }
|
||||
return getChecksumAddress("0x" + result);
|
||||
}
|
||||
|
||||
assertArgument(false, "invalid address", "address", address);
|
||||
}
|
||||
|
||||
/**
|
||||
* The [ICAP Address format](link-icap) format is an early checksum
|
||||
* format which attempts to be compatible with the banking
|
||||
* industry [IBAN format](link-wiki-iban) for bank accounts.
|
||||
*
|
||||
* It is no longer common or a recommended format.
|
||||
*
|
||||
* @example:
|
||||
* getIcapAddress("0x8ba1f109551bd432803012645ac136ddd64dba72");
|
||||
* //_result:
|
||||
*
|
||||
* getIcapAddress("XE65GB6LDNXYOFTX0NSV3FUWKOWIXAMJK36");
|
||||
* //_result:
|
||||
*
|
||||
* // Throws an error if the ICAP checksum is wrong
|
||||
* getIcapAddress("XE65GB6LDNXYOFTX0NSV3FUWKOWIXAMJK37");
|
||||
* //_error:
|
||||
*/
|
||||
export function getIcapAddress(address: string): string {
|
||||
//let base36 = _base16To36(getAddress(address).substring(2)).toUpperCase();
|
||||
let base36 = BigInt(getAddress(address)).toString(36).toUpperCase();
|
||||
while (base36.length < 30) { base36 = "0" + base36; }
|
||||
return "XE" + ibanChecksum("XE00" + base36) + base36;
|
||||
}
|
||||
123
dev/env/node_modules/ethers/src.ts/address/checks.ts
generated
vendored
Executable file
123
dev/env/node_modules/ethers/src.ts/address/checks.ts
generated
vendored
Executable file
@@ -0,0 +1,123 @@
|
||||
import { assert, assertArgument } from "../utils/index.js";
|
||||
|
||||
import { getAddress } from "./address.js";
|
||||
|
||||
import type { Addressable, AddressLike, NameResolver } from "./index.js";
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if %%value%% is an object which implements the
|
||||
* [[Addressable]] interface.
|
||||
*
|
||||
* @example:
|
||||
* // Wallets and AbstractSigner sub-classes
|
||||
* isAddressable(Wallet.createRandom())
|
||||
* //_result:
|
||||
*
|
||||
* // Contracts
|
||||
* contract = new Contract("dai.tokens.ethers.eth", [ ], provider)
|
||||
* isAddressable(contract)
|
||||
* //_result:
|
||||
*/
|
||||
export function isAddressable(value: any): value is Addressable {
|
||||
return (value && typeof(value.getAddress) === "function");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if %%value%% is a valid address.
|
||||
*
|
||||
* @example:
|
||||
* // Valid address
|
||||
* isAddress("0x8ba1f109551bD432803012645Ac136ddd64DBA72")
|
||||
* //_result:
|
||||
*
|
||||
* // Valid ICAP address
|
||||
* isAddress("XE65GB6LDNXYOFTX0NSV3FUWKOWIXAMJK36")
|
||||
* //_result:
|
||||
*
|
||||
* // Invalid checksum
|
||||
* isAddress("0x8Ba1f109551bD432803012645Ac136ddd64DBa72")
|
||||
* //_result:
|
||||
*
|
||||
* // Invalid ICAP checksum
|
||||
* isAddress("0x8Ba1f109551bD432803012645Ac136ddd64DBA72")
|
||||
* //_result:
|
||||
*
|
||||
* // Not an address (an ENS name requires a provided and an
|
||||
* // asynchronous API to access)
|
||||
* isAddress("ricmoo.eth")
|
||||
* //_result:
|
||||
*/
|
||||
export function isAddress(value: any): value is string {
|
||||
try {
|
||||
getAddress(value);
|
||||
return true;
|
||||
} catch (error) { }
|
||||
return false;
|
||||
}
|
||||
|
||||
async function checkAddress(target: any, promise: Promise<null | string>): Promise<string> {
|
||||
const result = await promise;
|
||||
if (result == null || result === "0x0000000000000000000000000000000000000000") {
|
||||
assert(typeof(target) !== "string", "unconfigured name", "UNCONFIGURED_NAME", { value: target });
|
||||
assertArgument(false, "invalid AddressLike value; did not resolve to a value address", "target", target);
|
||||
}
|
||||
return getAddress(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to an address for the %%target%%, which may be any
|
||||
* supported address type, an [[Addressable]] or a Promise which
|
||||
* resolves to an address.
|
||||
*
|
||||
* If an ENS name is provided, but that name has not been correctly
|
||||
* configured a [[UnconfiguredNameError]] is thrown.
|
||||
*
|
||||
* @example:
|
||||
* addr = "0x6B175474E89094C44Da98b954EedeAC495271d0F"
|
||||
*
|
||||
* // Addresses are return synchronously
|
||||
* resolveAddress(addr, provider)
|
||||
* //_result:
|
||||
*
|
||||
* // Address promises are resolved asynchronously
|
||||
* resolveAddress(Promise.resolve(addr))
|
||||
* //_result:
|
||||
*
|
||||
* // ENS names are resolved asynchronously
|
||||
* resolveAddress("dai.tokens.ethers.eth", provider)
|
||||
* //_result:
|
||||
*
|
||||
* // Addressable objects are resolved asynchronously
|
||||
* contract = new Contract(addr, [ ])
|
||||
* resolveAddress(contract, provider)
|
||||
* //_result:
|
||||
*
|
||||
* // Unconfigured ENS names reject
|
||||
* resolveAddress("nothing-here.ricmoo.eth", provider)
|
||||
* //_error:
|
||||
*
|
||||
* // ENS names require a NameResolver object passed in
|
||||
* // (notice the provider was omitted)
|
||||
* resolveAddress("nothing-here.ricmoo.eth")
|
||||
* //_error:
|
||||
*/
|
||||
export function resolveAddress(target: AddressLike, resolver?: null | NameResolver): string | Promise<string> {
|
||||
|
||||
if (typeof(target) === "string") {
|
||||
if (target.match(/^0x[0-9a-f]{40}$/i)) { return getAddress(target); }
|
||||
|
||||
assert(resolver != null, "ENS resolution requires a provider",
|
||||
"UNSUPPORTED_OPERATION", { operation: "resolveName" });
|
||||
|
||||
return checkAddress(target, resolver.resolveName(target));
|
||||
|
||||
} else if (isAddressable(target)) {
|
||||
return checkAddress(target, target.getAddress());
|
||||
|
||||
} else if (target && typeof(target.then) === "function") {
|
||||
return checkAddress(target, target);
|
||||
}
|
||||
|
||||
assertArgument(false, "unsupported addressable value", "target", target);
|
||||
}
|
||||
80
dev/env/node_modules/ethers/src.ts/address/contract-address.ts
generated
vendored
Executable file
80
dev/env/node_modules/ethers/src.ts/address/contract-address.ts
generated
vendored
Executable file
@@ -0,0 +1,80 @@
|
||||
import { keccak256 } from "../crypto/index.js";
|
||||
import {
|
||||
concat, dataSlice, getBigInt, getBytes, encodeRlp, assertArgument
|
||||
} from "../utils/index.js";
|
||||
|
||||
import { getAddress } from "./address.js";
|
||||
|
||||
import type { BigNumberish, BytesLike } from "../utils/index.js";
|
||||
|
||||
|
||||
// http://ethereum.stackexchange.com/questions/760/how-is-the-address-of-an-ethereum-contract-computed
|
||||
|
||||
/**
|
||||
* Returns the address that would result from a ``CREATE`` for %%tx%%.
|
||||
*
|
||||
* This can be used to compute the address a contract will be
|
||||
* deployed to by an EOA when sending a deployment transaction (i.e.
|
||||
* when the ``to`` address is ``null``).
|
||||
*
|
||||
* This can also be used to compute the address a contract will be
|
||||
* deployed to by a contract, by using the contract's address as the
|
||||
* ``to`` and the contract's nonce.
|
||||
*
|
||||
* @example
|
||||
* from = "0x8ba1f109551bD432803012645Ac136ddd64DBA72";
|
||||
* nonce = 5;
|
||||
*
|
||||
* getCreateAddress({ from, nonce });
|
||||
* //_result:
|
||||
*/
|
||||
export function getCreateAddress(tx: { from: string, nonce: BigNumberish }): string {
|
||||
const from = getAddress(tx.from);
|
||||
const nonce = getBigInt(tx.nonce, "tx.nonce");
|
||||
|
||||
let nonceHex = nonce.toString(16);
|
||||
if (nonceHex === "0") {
|
||||
nonceHex = "0x";
|
||||
} else if (nonceHex.length % 2) {
|
||||
nonceHex = "0x0" + nonceHex;
|
||||
} else {
|
||||
nonceHex = "0x" + nonceHex;
|
||||
}
|
||||
|
||||
return getAddress(dataSlice(keccak256(encodeRlp([ from, nonceHex ])), 12));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the address that would result from a ``CREATE2`` operation
|
||||
* with the given %%from%%, %%salt%% and %%initCodeHash%%.
|
||||
*
|
||||
* To compute the %%initCodeHash%% from a contract's init code, use
|
||||
* the [[keccak256]] function.
|
||||
*
|
||||
* For a quick overview and example of ``CREATE2``, see [[link-ricmoo-wisps]].
|
||||
*
|
||||
* @example
|
||||
* // The address of the contract
|
||||
* from = "0x8ba1f109551bD432803012645Ac136ddd64DBA72"
|
||||
*
|
||||
* // The salt
|
||||
* salt = id("HelloWorld")
|
||||
*
|
||||
* // The hash of the initCode
|
||||
* initCode = "0x6394198df16000526103ff60206004601c335afa6040516060f3";
|
||||
* initCodeHash = keccak256(initCode)
|
||||
*
|
||||
* getCreate2Address(from, salt, initCodeHash)
|
||||
* //_result:
|
||||
*/
|
||||
export function getCreate2Address(_from: string, _salt: BytesLike, _initCodeHash: BytesLike): string {
|
||||
const from = getAddress(_from);
|
||||
const salt = getBytes(_salt, "salt");
|
||||
const initCodeHash = getBytes(_initCodeHash, "initCodeHash");
|
||||
|
||||
assertArgument(salt.length === 32, "salt must be 32 bytes", "salt", _salt);
|
||||
|
||||
assertArgument(initCodeHash.length === 32, "initCodeHash must be 32 bytes", "initCodeHash", _initCodeHash);
|
||||
|
||||
return getAddress(dataSlice(keccak256(concat([ "0xff", from, salt, initCodeHash ])), 12))
|
||||
}
|
||||
57
dev/env/node_modules/ethers/src.ts/address/index.ts
generated
vendored
Executable file
57
dev/env/node_modules/ethers/src.ts/address/index.ts
generated
vendored
Executable file
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Addresses are a fundamental part of interacting with Ethereum. They
|
||||
* represent the global identity of Externally Owned Accounts (accounts
|
||||
* backed by a private key) and contracts.
|
||||
*
|
||||
* The Ethereum Naming Service (ENS) provides an interconnected ecosystem
|
||||
* of contracts, standards and libraries which enable looking up an
|
||||
* address for an ENS name.
|
||||
*
|
||||
* These functions help convert between various formats, validate
|
||||
* addresses and safely resolve ENS names.
|
||||
*
|
||||
* @_section: api/address:Addresses [about-addresses]
|
||||
*/
|
||||
|
||||
null;
|
||||
|
||||
/**
|
||||
* An interface for objects which have an address, and can
|
||||
* resolve it asyncronously.
|
||||
*
|
||||
* This allows objects such as [[Signer]] or [[Contract]] to
|
||||
* be used most places an address can be, for example getting
|
||||
* the [balance](Provider-getBalance).
|
||||
*/
|
||||
export interface Addressable {
|
||||
/**
|
||||
* Get the object address.
|
||||
*/
|
||||
getAddress(): Promise<string>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Anything that can be used to return or resolve an address.
|
||||
*/
|
||||
export type AddressLike = string | Promise<string> | Addressable;
|
||||
|
||||
/**
|
||||
* An interface for any object which can resolve an ENS name.
|
||||
*/
|
||||
export interface NameResolver {
|
||||
/**
|
||||
* Resolve to the address for the ENS %%name%%.
|
||||
*
|
||||
* Resolves to ``null`` if the name is unconfigued. Use
|
||||
* [[resolveAddress]] (passing this object as %%resolver%%) to
|
||||
* throw for names that are unconfigured.
|
||||
*/
|
||||
resolveName(name: string): Promise<null | string>;
|
||||
}
|
||||
|
||||
export { getAddress, getIcapAddress } from "./address.js";
|
||||
|
||||
export { getCreateAddress, getCreate2Address } from "./contract-address.js";
|
||||
|
||||
|
||||
export { isAddressable, isAddress, resolveAddress } from "./checks.js";
|
||||
8
dev/env/node_modules/ethers/src.ts/constants/addresses.ts
generated
vendored
Executable file
8
dev/env/node_modules/ethers/src.ts/constants/addresses.ts
generated
vendored
Executable file
@@ -0,0 +1,8 @@
|
||||
|
||||
/**
|
||||
* A constant for the zero address.
|
||||
*
|
||||
* (**i.e.** ``"0x0000000000000000000000000000000000000000"``)
|
||||
*/
|
||||
export const ZeroAddress: string = "0x0000000000000000000000000000000000000000";
|
||||
|
||||
7
dev/env/node_modules/ethers/src.ts/constants/hashes.ts
generated
vendored
Executable file
7
dev/env/node_modules/ethers/src.ts/constants/hashes.ts
generated
vendored
Executable file
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* A constant for the zero hash.
|
||||
*
|
||||
* (**i.e.** ``"0x0000000000000000000000000000000000000000000000000000000000000000"``)
|
||||
*/
|
||||
export const ZeroHash: string = "0x0000000000000000000000000000000000000000000000000000000000000000";
|
||||
|
||||
16
dev/env/node_modules/ethers/src.ts/constants/index.ts
generated
vendored
Executable file
16
dev/env/node_modules/ethers/src.ts/constants/index.ts
generated
vendored
Executable file
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Some common constants useful for Ethereum.
|
||||
*
|
||||
* @_section: api/constants: Constants [about-constants]
|
||||
*/
|
||||
|
||||
export { ZeroAddress } from "./addresses.js";
|
||||
export { ZeroHash } from "./hashes.js";
|
||||
export {
|
||||
N,
|
||||
WeiPerEther,
|
||||
MaxUint256,
|
||||
MinInt256,
|
||||
MaxInt256
|
||||
} from "./numbers.js";
|
||||
export { EtherSymbol, MessagePrefix } from "./strings.js";
|
||||
35
dev/env/node_modules/ethers/src.ts/constants/numbers.ts
generated
vendored
Executable file
35
dev/env/node_modules/ethers/src.ts/constants/numbers.ts
generated
vendored
Executable file
@@ -0,0 +1,35 @@
|
||||
|
||||
/**
|
||||
* A constant for the order N for the secp256k1 curve.
|
||||
*
|
||||
* (**i.e.** ``0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n``)
|
||||
*/
|
||||
export const N: bigint = BigInt("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141");
|
||||
|
||||
/**
|
||||
* A constant for the number of wei in a single ether.
|
||||
*
|
||||
* (**i.e.** ``1000000000000000000n``)
|
||||
*/
|
||||
export const WeiPerEther: bigint = BigInt("1000000000000000000");
|
||||
|
||||
/**
|
||||
* A constant for the maximum value for a ``uint256``.
|
||||
*
|
||||
* (**i.e.** ``0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn``)
|
||||
*/
|
||||
export const MaxUint256: bigint = BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
|
||||
|
||||
/**
|
||||
* A constant for the minimum value for an ``int256``.
|
||||
*
|
||||
* (**i.e.** ``-8000000000000000000000000000000000000000000000000000000000000000n``)
|
||||
*/
|
||||
export const MinInt256: bigint = BigInt("0x8000000000000000000000000000000000000000000000000000000000000000") * BigInt(-1);
|
||||
|
||||
/**
|
||||
* A constant for the maximum value for an ``int256``.
|
||||
*
|
||||
* (**i.e.** ``0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn``)
|
||||
*/
|
||||
export const MaxInt256: bigint = BigInt("0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
|
||||
16
dev/env/node_modules/ethers/src.ts/constants/strings.ts
generated
vendored
Executable file
16
dev/env/node_modules/ethers/src.ts/constants/strings.ts
generated
vendored
Executable file
@@ -0,0 +1,16 @@
|
||||
// NFKC (composed) // (decomposed)
|
||||
|
||||
/**
|
||||
* A constant for the ether symbol (normalized using NFKC).
|
||||
*
|
||||
* (**i.e.** ``"\\u039e"``)
|
||||
*/
|
||||
export const EtherSymbol: string = "\u039e"; // "\uD835\uDF63";
|
||||
|
||||
|
||||
/**
|
||||
* A constant for the [[link-eip-191]] personal message prefix.
|
||||
*
|
||||
* (**i.e.** ``"\\x19Ethereum Signed Message:\\n"``)
|
||||
*/
|
||||
export const MessagePrefix: string = "\x19Ethereum Signed Message:\n";
|
||||
1120
dev/env/node_modules/ethers/src.ts/contract/contract.ts
generated
vendored
Executable file
1120
dev/env/node_modules/ethers/src.ts/contract/contract.ts
generated
vendored
Executable file
File diff suppressed because it is too large
Load Diff
143
dev/env/node_modules/ethers/src.ts/contract/factory.ts
generated
vendored
Executable file
143
dev/env/node_modules/ethers/src.ts/contract/factory.ts
generated
vendored
Executable file
@@ -0,0 +1,143 @@
|
||||
|
||||
import { Interface } from "../abi/index.js";
|
||||
import { getCreateAddress } from "../address/index.js";
|
||||
import {
|
||||
concat, defineProperties, getBytes, hexlify,
|
||||
assert, assertArgument
|
||||
} from "../utils/index.js";
|
||||
|
||||
import { BaseContract, copyOverrides, resolveArgs } from "./contract.js";
|
||||
|
||||
import type { InterfaceAbi } from "../abi/index.js";
|
||||
import type { Addressable } from "../address/index.js";
|
||||
import type { ContractRunner } from "../providers/index.js";
|
||||
import type { BytesLike } from "../utils/index.js";
|
||||
|
||||
import type {
|
||||
ContractInterface, ContractMethodArgs, ContractDeployTransaction,
|
||||
} from "./types.js";
|
||||
import type { ContractTransactionResponse } from "./wrappers.js";
|
||||
|
||||
|
||||
// A = Arguments to the constructor
|
||||
// I = Interface of deployed contracts
|
||||
|
||||
/**
|
||||
* A **ContractFactory** is used to deploy a Contract to the blockchain.
|
||||
*/
|
||||
export class ContractFactory<A extends Array<any> = Array<any>, I = BaseContract> {
|
||||
|
||||
/**
|
||||
* The Contract Interface.
|
||||
*/
|
||||
readonly interface!: Interface;
|
||||
|
||||
/**
|
||||
* The Contract deployment bytecode. Often called the initcode.
|
||||
*/
|
||||
readonly bytecode!: string;
|
||||
|
||||
/**
|
||||
* The ContractRunner to deploy the Contract as.
|
||||
*/
|
||||
readonly runner!: null | ContractRunner;
|
||||
|
||||
/**
|
||||
* Create a new **ContractFactory** with %%abi%% and %%bytecode%%,
|
||||
* optionally connected to %%runner%%.
|
||||
*
|
||||
* The %%bytecode%% may be the ``bytecode`` property within the
|
||||
* standard Solidity JSON output.
|
||||
*/
|
||||
constructor(abi: Interface | InterfaceAbi, bytecode: BytesLike | { object: string }, runner?: null | ContractRunner) {
|
||||
const iface = Interface.from(abi);
|
||||
|
||||
// Dereference Solidity bytecode objects and allow a missing `0x`-prefix
|
||||
if (bytecode instanceof Uint8Array) {
|
||||
bytecode = hexlify(getBytes(bytecode));
|
||||
} else {
|
||||
if (typeof(bytecode) === "object") { bytecode = bytecode.object; }
|
||||
if (!bytecode.startsWith("0x")) { bytecode = "0x" + bytecode; }
|
||||
bytecode = hexlify(getBytes(bytecode));
|
||||
}
|
||||
|
||||
defineProperties<ContractFactory>(this, {
|
||||
bytecode, interface: iface, runner: (runner || null)
|
||||
});
|
||||
}
|
||||
|
||||
attach(target: string | Addressable): BaseContract & Omit<I, keyof BaseContract> {
|
||||
return new (<any>BaseContract)(target, this.interface, this.runner);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to the transaction to deploy the contract, passing %%args%%
|
||||
* into the constructor.
|
||||
*/
|
||||
async getDeployTransaction(...args: ContractMethodArgs<A>): Promise<ContractDeployTransaction> {
|
||||
let overrides: Omit<ContractDeployTransaction, "data"> = { };
|
||||
|
||||
const fragment = this.interface.deploy;
|
||||
|
||||
if (fragment.inputs.length + 1 === args.length) {
|
||||
overrides = await copyOverrides(args.pop());
|
||||
}
|
||||
|
||||
if (fragment.inputs.length !== args.length) {
|
||||
throw new Error("incorrect number of arguments to constructor");
|
||||
}
|
||||
|
||||
const resolvedArgs = await resolveArgs(this.runner, fragment.inputs, args);
|
||||
|
||||
const data = concat([ this.bytecode, this.interface.encodeDeploy(resolvedArgs) ]);
|
||||
return Object.assign({ }, overrides, { data });
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to the Contract deployed by passing %%args%% into the
|
||||
* constructor.
|
||||
*
|
||||
* This will resolve to the Contract before it has been deployed to the
|
||||
* network, so the [[BaseContract-waitForDeployment]] should be used before
|
||||
* sending any transactions to it.
|
||||
*/
|
||||
async deploy(...args: ContractMethodArgs<A>): Promise<BaseContract & { deploymentTransaction(): ContractTransactionResponse } & Omit<I, keyof BaseContract>> {
|
||||
const tx = await this.getDeployTransaction(...args);
|
||||
|
||||
assert(this.runner && typeof(this.runner.sendTransaction) === "function",
|
||||
"factory runner does not support sending transactions", "UNSUPPORTED_OPERATION", {
|
||||
operation: "sendTransaction" });
|
||||
|
||||
const sentTx = await this.runner.sendTransaction(tx);
|
||||
const address = getCreateAddress(sentTx);
|
||||
return new (<any>BaseContract)(address, this.interface, this.runner, sentTx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new **ContractFactory** with the same ABI and bytecode,
|
||||
* but connected to %%runner%%.
|
||||
*/
|
||||
connect(runner: null | ContractRunner): ContractFactory<A, I> {
|
||||
return new ContractFactory(this.interface, this.bytecode, runner);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new **ContractFactory** from the standard Solidity JSON output.
|
||||
*/
|
||||
static fromSolidity<A extends Array<any> = Array<any>, I = ContractInterface>(output: any, runner?: ContractRunner): ContractFactory<A, I> {
|
||||
assertArgument(output != null, "bad compiler output", "output", output);
|
||||
|
||||
if (typeof(output) === "string") { output = JSON.parse(output); }
|
||||
|
||||
const abi = output.abi;
|
||||
|
||||
let bytecode = "";
|
||||
if (output.bytecode) {
|
||||
bytecode = output.bytecode;
|
||||
} else if (output.evm && output.evm.bytecode) {
|
||||
bytecode = output.evm.bytecode;
|
||||
}
|
||||
|
||||
return new this(abi, bytecode, runner);
|
||||
}
|
||||
}
|
||||
31
dev/env/node_modules/ethers/src.ts/contract/index.ts
generated
vendored
Executable file
31
dev/env/node_modules/ethers/src.ts/contract/index.ts
generated
vendored
Executable file
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* A **Contract** object is a meta-class (a class whose definition is
|
||||
* defined at runtime), which communicates with a deployed smart contract
|
||||
* on the blockchain and provides a simple JavaScript interface to call
|
||||
* methods, send transaction, query historic logs and listen for its events.
|
||||
*
|
||||
* @_section: api/contract:Contracts [about-contracts]
|
||||
*/
|
||||
export {
|
||||
BaseContract, Contract
|
||||
} from "./contract.js";
|
||||
|
||||
export {
|
||||
ContractFactory
|
||||
} from "./factory.js";
|
||||
|
||||
export {
|
||||
ContractEventPayload, ContractUnknownEventPayload,
|
||||
ContractTransactionReceipt, ContractTransactionResponse,
|
||||
EventLog, UndecodedEventLog
|
||||
} from "./wrappers.js";
|
||||
|
||||
export type {
|
||||
BaseContractMethod, ConstantContractMethod,
|
||||
PostfixOverrides,
|
||||
ContractEvent, ContractEventArgs, ContractEventName,
|
||||
ContractDeployTransaction,
|
||||
ContractInterface, ContractMethod, ContractMethodArgs, ContractTransaction,
|
||||
DeferredTopicFilter, Overrides,
|
||||
WrappedFallback
|
||||
} from "./types.js";
|
||||
236
dev/env/node_modules/ethers/src.ts/contract/types.ts
generated
vendored
Executable file
236
dev/env/node_modules/ethers/src.ts/contract/types.ts
generated
vendored
Executable file
@@ -0,0 +1,236 @@
|
||||
import type {
|
||||
EventFragment, FunctionFragment, Result, Typed
|
||||
} from "../abi/index.js";
|
||||
import type {
|
||||
TransactionRequest, PreparedTransactionRequest, TopicFilter
|
||||
} from "../providers/index.js";
|
||||
|
||||
import type { ContractTransactionResponse } from "./wrappers.js";
|
||||
|
||||
|
||||
/**
|
||||
* The name for an event used for subscribing to Contract events.
|
||||
*
|
||||
* **``string``** - An event by name. The event must be non-ambiguous.
|
||||
* The parameters will be dereferenced when passed into the listener.
|
||||
*
|
||||
* [[ContractEvent]] - A filter from the ``contract.filters``, which will
|
||||
* pass only the EventPayload as a single parameter, which includes a
|
||||
* ``.signature`` property that can be used to further filter the event.
|
||||
*
|
||||
* [[TopicFilter]] - A filter defined using the standard Ethereum API
|
||||
* which provides the specific topic hash or topic hashes to watch for along
|
||||
* with any additional values to filter by. This will only pass a single
|
||||
* parameter to the listener, the EventPayload which will include additional
|
||||
* details to refine by, such as the event name and signature.
|
||||
*
|
||||
* [[DeferredTopicFilter]] - A filter created by calling a [[ContractEvent]]
|
||||
* with parameters, which will create a filter for a specific event
|
||||
* signature and dereference each parameter when calling the listener.
|
||||
*/
|
||||
export type ContractEventName = string | ContractEvent | TopicFilter | DeferredTopicFilter;
|
||||
|
||||
/**
|
||||
* A Contract with no method constraints.
|
||||
*/
|
||||
export interface ContractInterface {
|
||||
[ name: string ]: BaseContractMethod;
|
||||
};
|
||||
|
||||
/**
|
||||
* When creating a filter using the ``contract.filters``, this is returned.
|
||||
*/
|
||||
export interface DeferredTopicFilter {
|
||||
getTopicFilter(): Promise<TopicFilter>;
|
||||
fragment: EventFragment;
|
||||
}
|
||||
|
||||
/**
|
||||
* When populating a transaction this type is returned.
|
||||
*/
|
||||
export interface ContractTransaction extends PreparedTransactionRequest {
|
||||
/**
|
||||
* The target address.
|
||||
*/
|
||||
to: string;
|
||||
|
||||
/**
|
||||
* The transaction data.
|
||||
*/
|
||||
data: string;
|
||||
|
||||
/**
|
||||
* The from address, if any.
|
||||
*/
|
||||
from?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* A deployment transaction for a contract.
|
||||
*/
|
||||
export interface ContractDeployTransaction extends Omit<ContractTransaction, "to"> { }
|
||||
|
||||
/**
|
||||
* The overrides for a contract transaction.
|
||||
*/
|
||||
export interface Overrides extends Omit<TransactionRequest, "to" | "data"> { };
|
||||
|
||||
|
||||
/**
|
||||
* Arguments to a Contract method can always include an additional and
|
||||
* optional overrides parameter.
|
||||
*
|
||||
* @_ignore:
|
||||
*/
|
||||
export type PostfixOverrides<A extends Array<any>> = A | [ ...A, Overrides ];
|
||||
|
||||
/**
|
||||
* Arguments to a Contract method can always include an additional and
|
||||
* optional overrides parameter, and each parameter can optionally be
|
||||
* [[Typed]].
|
||||
*
|
||||
* @_ignore:
|
||||
*/
|
||||
export type ContractMethodArgs<A extends Array<any>> = PostfixOverrides<{ [ I in keyof A ]-?: A[I] | Typed }>;
|
||||
|
||||
// A = Arguments passed in as a tuple
|
||||
// R = The result type of the call (i.e. if only one return type,
|
||||
// the qualified type, otherwise Result)
|
||||
// D = The type the default call will return (i.e. R for view/pure,
|
||||
// TransactionResponse otherwise)
|
||||
|
||||
/**
|
||||
* A Contract method can be called directly, or used in various ways.
|
||||
*/
|
||||
export interface BaseContractMethod<A extends Array<any> = Array<any>, R = any, D extends R | ContractTransactionResponse = R | ContractTransactionResponse> {
|
||||
(...args: ContractMethodArgs<A>): Promise<D>;
|
||||
|
||||
/**
|
||||
* The name of the Contract method.
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* The fragment of the Contract method. This will throw on ambiguous
|
||||
* method names.
|
||||
*/
|
||||
fragment: FunctionFragment;
|
||||
|
||||
/**
|
||||
* Returns the fragment constrained by %%args%%. This can be used to
|
||||
* resolve ambiguous method names.
|
||||
*/
|
||||
getFragment(...args: ContractMethodArgs<A>): FunctionFragment;
|
||||
|
||||
/**
|
||||
* Returns a populated transaction that can be used to perform the
|
||||
* contract method with %%args%%.
|
||||
*/
|
||||
populateTransaction(...args: ContractMethodArgs<A>): Promise<ContractTransaction>;
|
||||
|
||||
/**
|
||||
* Call the contract method with %%args%% and return the value.
|
||||
*
|
||||
* If the return value is a single type, it will be dereferenced and
|
||||
* returned directly, otherwise the full Result will be returned.
|
||||
*/
|
||||
staticCall(...args: ContractMethodArgs<A>): Promise<R>;
|
||||
|
||||
/**
|
||||
* Send a transaction for the contract method with %%args%%.
|
||||
*/
|
||||
send(...args: ContractMethodArgs<A>): Promise<ContractTransactionResponse>;
|
||||
|
||||
/**
|
||||
* Estimate the gas to send the contract method with %%args%%.
|
||||
*/
|
||||
estimateGas(...args: ContractMethodArgs<A>): Promise<bigint>;
|
||||
|
||||
/**
|
||||
* Call the contract method with %%args%% and return the Result
|
||||
* without any dereferencing.
|
||||
*/
|
||||
staticCallResult(...args: ContractMethodArgs<A>): Promise<Result>;
|
||||
}
|
||||
|
||||
/**
|
||||
* A contract method on a Contract.
|
||||
*/
|
||||
export interface ContractMethod<
|
||||
A extends Array<any> = Array<any>,
|
||||
R = any,
|
||||
D extends R | ContractTransactionResponse = R | ContractTransactionResponse
|
||||
> extends BaseContractMethod<A, R, D> { }
|
||||
|
||||
/**
|
||||
* A pure of view method on a Contract.
|
||||
*/
|
||||
export interface ConstantContractMethod<
|
||||
A extends Array<any>,
|
||||
R = any
|
||||
> extends ContractMethod<A, R, R> { }
|
||||
|
||||
|
||||
/**
|
||||
* Each argument of an event is nullable (to indicate matching //any//.
|
||||
*
|
||||
* @_ignore:
|
||||
*/
|
||||
export type ContractEventArgs<A extends Array<any>> = { [ I in keyof A ]?: A[I] | Typed | null };
|
||||
|
||||
export interface ContractEvent<A extends Array<any> = Array<any>> {
|
||||
(...args: ContractEventArgs<A>): DeferredTopicFilter;
|
||||
|
||||
/**
|
||||
* The name of the Contract event.
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* The fragment of the Contract event. This will throw on ambiguous
|
||||
* method names.
|
||||
*/
|
||||
fragment: EventFragment;
|
||||
|
||||
/**
|
||||
* Returns the fragment constrained by %%args%%. This can be used to
|
||||
* resolve ambiguous event names.
|
||||
*/
|
||||
getFragment(...args: ContractEventArgs<A>): EventFragment;
|
||||
};
|
||||
|
||||
/**
|
||||
* A Fallback or Receive function on a Contract.
|
||||
*/
|
||||
export interface WrappedFallback {
|
||||
(overrides?: Omit<TransactionRequest, "to">): Promise<ContractTransactionResponse>;
|
||||
|
||||
/**
|
||||
* Returns a populated transaction that can be used to perform the
|
||||
* fallback method.
|
||||
*
|
||||
* For non-receive fallback, ``data`` may be overridden.
|
||||
*/
|
||||
populateTransaction(overrides?: Omit<TransactionRequest, "to">): Promise<ContractTransaction>;
|
||||
|
||||
/**
|
||||
* Call the contract fallback and return the result.
|
||||
*
|
||||
* For non-receive fallback, ``data`` may be overridden.
|
||||
*/
|
||||
staticCall(overrides?: Omit<TransactionRequest, "to">): Promise<string>;
|
||||
|
||||
/**
|
||||
* Send a transaction to the contract fallback.
|
||||
*
|
||||
* For non-receive fallback, ``data`` may be overridden.
|
||||
*/
|
||||
send(overrides?: Omit<TransactionRequest, "to">): Promise<ContractTransactionResponse>;
|
||||
|
||||
/**
|
||||
* Estimate the gas to send a transaction to the contract fallback.
|
||||
*
|
||||
* For non-receive fallback, ``data`` may be overridden.
|
||||
*/
|
||||
estimateGas(overrides?: Omit<TransactionRequest, "to">): Promise<bigint>;
|
||||
}
|
||||
225
dev/env/node_modules/ethers/src.ts/contract/wrappers.ts
generated
vendored
Executable file
225
dev/env/node_modules/ethers/src.ts/contract/wrappers.ts
generated
vendored
Executable file
@@ -0,0 +1,225 @@
|
||||
// import from provider.ts instead of index.ts to prevent circular dep
|
||||
// from EtherscanProvider
|
||||
import {
|
||||
Block, Log, TransactionReceipt, TransactionResponse
|
||||
} from "../providers/provider.js";
|
||||
import { defineProperties, EventPayload } from "../utils/index.js";
|
||||
|
||||
import type { EventFragment, Interface, Result } from "../abi/index.js";
|
||||
import type { Listener } from "../utils/index.js";
|
||||
import type {
|
||||
Provider
|
||||
} from "../providers/index.js";
|
||||
|
||||
import type { BaseContract } from "./contract.js";
|
||||
import type { ContractEventName } from "./types.js";
|
||||
|
||||
/**
|
||||
* An **EventLog** contains additional properties parsed from the [[Log]].
|
||||
*/
|
||||
export class EventLog extends Log {
|
||||
/**
|
||||
* The Contract Interface.
|
||||
*/
|
||||
readonly interface!: Interface;
|
||||
|
||||
/**
|
||||
* The matching event.
|
||||
*/
|
||||
readonly fragment!: EventFragment;
|
||||
|
||||
/**
|
||||
* The parsed arguments passed to the event by ``emit``.
|
||||
*/
|
||||
readonly args!: Result;
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
constructor(log: Log, iface: Interface, fragment: EventFragment) {
|
||||
super(log, log.provider);
|
||||
const args = iface.decodeEventLog(fragment, log.data, log.topics);
|
||||
defineProperties<EventLog>(this, { args, fragment, interface: iface });
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the event.
|
||||
*/
|
||||
get eventName(): string { return this.fragment.name; }
|
||||
|
||||
/**
|
||||
* The signature of the event.
|
||||
*/
|
||||
get eventSignature(): string { return this.fragment.format(); }
|
||||
}
|
||||
|
||||
/**
|
||||
* An **EventLog** contains additional properties parsed from the [[Log]].
|
||||
*/
|
||||
export class UndecodedEventLog extends Log {
|
||||
|
||||
/**
|
||||
* The error encounted when trying to decode the log.
|
||||
*/
|
||||
readonly error!: Error;
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
constructor(log: Log, error: Error) {
|
||||
super(log, log.provider);
|
||||
defineProperties<UndecodedEventLog>(this, { error });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A **ContractTransactionReceipt** includes the parsed logs from a
|
||||
* [[TransactionReceipt]].
|
||||
*/
|
||||
export class ContractTransactionReceipt extends TransactionReceipt {
|
||||
readonly #iface: Interface;
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
constructor(iface: Interface, provider: Provider, tx: TransactionReceipt) {
|
||||
super(tx, provider);
|
||||
this.#iface = iface;
|
||||
}
|
||||
|
||||
/**
|
||||
* The parsed logs for any [[Log]] which has a matching event in the
|
||||
* Contract ABI.
|
||||
*/
|
||||
get logs(): Array<EventLog | Log> {
|
||||
return super.logs.map((log) => {
|
||||
const fragment = log.topics.length ? this.#iface.getEvent(log.topics[0]): null;
|
||||
if (fragment) {
|
||||
try {
|
||||
return new EventLog(log, this.#iface, fragment)
|
||||
} catch (error: any) {
|
||||
return new UndecodedEventLog(log, error);
|
||||
}
|
||||
}
|
||||
|
||||
return log;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A **ContractTransactionResponse** will return a
|
||||
* [[ContractTransactionReceipt]] when waited on.
|
||||
*/
|
||||
export class ContractTransactionResponse extends TransactionResponse {
|
||||
readonly #iface: Interface;
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
constructor(iface: Interface, provider: Provider, tx: TransactionResponse) {
|
||||
super(tx, provider);
|
||||
this.#iface = iface;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves once this transaction has been mined and has
|
||||
* %%confirms%% blocks including it (default: ``1``) with an
|
||||
* optional %%timeout%%.
|
||||
*
|
||||
* This can resolve to ``null`` only if %%confirms%% is ``0``
|
||||
* and the transaction has not been mined, otherwise this will
|
||||
* wait until enough confirmations have completed.
|
||||
*/
|
||||
async wait(confirms?: number, timeout?: number): Promise<null | ContractTransactionReceipt> {
|
||||
const receipt = await super.wait(confirms, timeout);
|
||||
if (receipt == null) { return null; }
|
||||
return new ContractTransactionReceipt(this.#iface, this.provider, receipt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A **ContractUnknownEventPayload** is included as the last parameter to
|
||||
* Contract Events when the event does not match any events in the ABI.
|
||||
*/
|
||||
export class ContractUnknownEventPayload extends EventPayload<ContractEventName> {
|
||||
/**
|
||||
* The log with no matching events.
|
||||
*/
|
||||
readonly log!: Log;
|
||||
|
||||
/**
|
||||
* @_event:
|
||||
*/
|
||||
constructor(contract: BaseContract, listener: null | Listener, filter: ContractEventName, log: Log) {
|
||||
super(contract, listener, filter);
|
||||
defineProperties<ContractUnknownEventPayload>(this, { log });
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to the block the event occured in.
|
||||
*/
|
||||
async getBlock(): Promise<Block> {
|
||||
return await this.log.getBlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to the transaction the event occured in.
|
||||
*/
|
||||
async getTransaction(): Promise<TransactionResponse> {
|
||||
return await this.log.getTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to the transaction receipt the event occured in.
|
||||
*/
|
||||
async getTransactionReceipt(): Promise<TransactionReceipt> {
|
||||
return await this.log.getTransactionReceipt();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A **ContractEventPayload** is included as the last parameter to
|
||||
* Contract Events when the event is known.
|
||||
*/
|
||||
export class ContractEventPayload extends ContractUnknownEventPayload {
|
||||
|
||||
/**
|
||||
* The matching event.
|
||||
*/
|
||||
declare readonly fragment: EventFragment;
|
||||
|
||||
/**
|
||||
* The log, with parsed properties.
|
||||
*/
|
||||
declare readonly log: EventLog;
|
||||
|
||||
/**
|
||||
* The parsed arguments passed to the event by ``emit``.
|
||||
*/
|
||||
declare readonly args: Result;
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
constructor(contract: BaseContract, listener: null | Listener, filter: ContractEventName, fragment: EventFragment, _log: Log) {
|
||||
super(contract, listener, filter, new EventLog(_log, contract.interface, fragment));
|
||||
const args = contract.interface.decodeEventLog(fragment, this.log.data, this.log.topics);
|
||||
defineProperties<ContractEventPayload>(this, { args, fragment });
|
||||
}
|
||||
|
||||
/**
|
||||
* The event name.
|
||||
*/
|
||||
get eventName(): string {
|
||||
return this.fragment.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* The event signature.
|
||||
*/
|
||||
get eventSignature(): string {
|
||||
return this.fragment.format();
|
||||
}
|
||||
}
|
||||
64
dev/env/node_modules/ethers/src.ts/crypto/crypto-browser.ts
generated
vendored
Executable file
64
dev/env/node_modules/ethers/src.ts/crypto/crypto-browser.ts
generated
vendored
Executable file
@@ -0,0 +1,64 @@
|
||||
/* Browser Crypto Shims */
|
||||
|
||||
import { hmac } from "@noble/hashes/hmac";
|
||||
import { pbkdf2 } from "@noble/hashes/pbkdf2";
|
||||
import { sha256 } from "@noble/hashes/sha256";
|
||||
import { sha512 } from "@noble/hashes/sha512";
|
||||
|
||||
import { assert, assertArgument } from "../utils/index.js";
|
||||
|
||||
|
||||
declare global {
|
||||
interface Window { }
|
||||
|
||||
const window: Window;
|
||||
const self: Window;
|
||||
}
|
||||
|
||||
|
||||
function getGlobal(): any {
|
||||
if (typeof self !== 'undefined') { return self; }
|
||||
if (typeof window !== 'undefined') { return window; }
|
||||
if (typeof global !== 'undefined') { return global; }
|
||||
throw new Error('unable to locate global object');
|
||||
};
|
||||
|
||||
const anyGlobal = getGlobal();
|
||||
const crypto: any = anyGlobal.crypto || anyGlobal.msCrypto;
|
||||
|
||||
|
||||
export interface CryptoHasher {
|
||||
update(data: Uint8Array): CryptoHasher;
|
||||
digest(): Uint8Array;
|
||||
}
|
||||
|
||||
export function createHash(algo: string): CryptoHasher {
|
||||
switch (algo) {
|
||||
case "sha256": return sha256.create();
|
||||
case "sha512": return sha512.create();
|
||||
}
|
||||
assertArgument(false, "invalid hashing algorithm name", "algorithm", algo);
|
||||
}
|
||||
|
||||
export function createHmac(_algo: string, key: Uint8Array): CryptoHasher {
|
||||
const algo = ({ sha256, sha512 }[_algo]);
|
||||
assertArgument(algo != null, "invalid hmac algorithm", "algorithm", _algo);
|
||||
return hmac.create(algo, key);
|
||||
}
|
||||
|
||||
export function pbkdf2Sync(password: Uint8Array, salt: Uint8Array, iterations: number, keylen: number, _algo: "sha256" | "sha512"): Uint8Array {
|
||||
const algo = ({ sha256, sha512 }[_algo]);
|
||||
assertArgument(algo != null, "invalid pbkdf2 algorithm", "algorithm", _algo);
|
||||
return pbkdf2(algo, password, salt, { c: iterations, dkLen: keylen });
|
||||
}
|
||||
|
||||
export function randomBytes(length: number): Uint8Array {
|
||||
assert(crypto != null, "platform does not support secure random numbers", "UNSUPPORTED_OPERATION", {
|
||||
operation: "randomBytes" });
|
||||
|
||||
assertArgument(Number.isInteger(length) && length > 0 && length <= 1024, "invalid length", "length", length);
|
||||
|
||||
const result = new Uint8Array(length);
|
||||
crypto.getRandomValues(result);
|
||||
return result;
|
||||
}
|
||||
4
dev/env/node_modules/ethers/src.ts/crypto/crypto.ts
generated
vendored
Executable file
4
dev/env/node_modules/ethers/src.ts/crypto/crypto.ts
generated
vendored
Executable file
@@ -0,0 +1,4 @@
|
||||
|
||||
export {
|
||||
createHash, createHmac, pbkdf2Sync, randomBytes
|
||||
} from "crypto";
|
||||
51
dev/env/node_modules/ethers/src.ts/crypto/hmac.ts
generated
vendored
Executable file
51
dev/env/node_modules/ethers/src.ts/crypto/hmac.ts
generated
vendored
Executable file
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* An **HMAC** enables verification that a given key was used
|
||||
* to authenticate a payload.
|
||||
*
|
||||
* See: [[link-wiki-hmac]]
|
||||
*
|
||||
* @_subsection: api/crypto:HMAC [about-hmac]
|
||||
*/
|
||||
import { createHmac } from "./crypto.js";
|
||||
import { getBytes, hexlify } from "../utils/index.js";
|
||||
|
||||
import type { BytesLike } from "../utils/index.js";
|
||||
|
||||
|
||||
let locked = false;
|
||||
|
||||
const _computeHmac = function(algorithm: "sha256" | "sha512", key: Uint8Array, data: Uint8Array): BytesLike {
|
||||
return createHmac(algorithm, key).update(data).digest();
|
||||
}
|
||||
|
||||
let __computeHmac = _computeHmac;
|
||||
|
||||
/**
|
||||
* Return the HMAC for %%data%% using the %%key%% key with the underlying
|
||||
* %%algo%% used for compression.
|
||||
*
|
||||
* @example:
|
||||
* key = id("some-secret")
|
||||
*
|
||||
* // Compute the HMAC
|
||||
* computeHmac("sha256", key, "0x1337")
|
||||
* //_result:
|
||||
*
|
||||
* // To compute the HMAC of UTF-8 data, the data must be
|
||||
* // converted to UTF-8 bytes
|
||||
* computeHmac("sha256", key, toUtf8Bytes("Hello World"))
|
||||
* //_result:
|
||||
*
|
||||
*/
|
||||
export function computeHmac(algorithm: "sha256" | "sha512", _key: BytesLike, _data: BytesLike): string {
|
||||
const key = getBytes(_key, "key");
|
||||
const data = getBytes(_data, "data");
|
||||
return hexlify(__computeHmac(algorithm, key, data));
|
||||
}
|
||||
computeHmac._ = _computeHmac;
|
||||
computeHmac.lock = function() { locked = true; }
|
||||
computeHmac.register = function(func: (algorithm: "sha256" | "sha512", key: Uint8Array, data: Uint8Array) => BytesLike) {
|
||||
if (locked) { throw new Error("computeHmac is locked"); }
|
||||
__computeHmac = func;
|
||||
}
|
||||
Object.freeze(computeHmac);
|
||||
59
dev/env/node_modules/ethers/src.ts/crypto/index.ts
generated
vendored
Executable file
59
dev/env/node_modules/ethers/src.ts/crypto/index.ts
generated
vendored
Executable file
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* A fundamental building block of Ethereum is the underlying
|
||||
* cryptographic primitives.
|
||||
*
|
||||
* @_section: api/crypto:Cryptographic Functions [about-crypto]
|
||||
*/
|
||||
|
||||
null
|
||||
|
||||
// We import all these so we can export lock()
|
||||
import { computeHmac } from "./hmac.js";
|
||||
import { keccak256 } from "./keccak.js";
|
||||
import { ripemd160 } from "./ripemd160.js";
|
||||
import { pbkdf2 } from "./pbkdf2.js";
|
||||
import { randomBytes } from "./random.js";
|
||||
import { scrypt, scryptSync } from "./scrypt.js";
|
||||
import { sha256, sha512 } from "./sha2.js";
|
||||
|
||||
export {
|
||||
computeHmac,
|
||||
|
||||
randomBytes,
|
||||
|
||||
keccak256,
|
||||
ripemd160,
|
||||
sha256, sha512,
|
||||
|
||||
pbkdf2,
|
||||
scrypt, scryptSync
|
||||
};
|
||||
|
||||
export { SigningKey } from "./signing-key.js";
|
||||
export { Signature } from "./signature.js";
|
||||
|
||||
/**
|
||||
* Once called, prevents any future change to the underlying cryptographic
|
||||
* primitives using the ``.register`` feature for hooks.
|
||||
*/
|
||||
function lock(): void {
|
||||
computeHmac.lock();
|
||||
keccak256.lock();
|
||||
pbkdf2.lock();
|
||||
randomBytes.lock();
|
||||
ripemd160.lock();
|
||||
scrypt.lock();
|
||||
scryptSync.lock();
|
||||
sha256.lock();
|
||||
sha512.lock();
|
||||
randomBytes.lock();
|
||||
}
|
||||
|
||||
export { lock };
|
||||
|
||||
/////////////////////////////
|
||||
// Types
|
||||
|
||||
export type { ProgressCallback } from "./scrypt.js";
|
||||
|
||||
export type { SignatureLike } from "./signature.js";
|
||||
54
dev/env/node_modules/ethers/src.ts/crypto/keccak.ts
generated
vendored
Executable file
54
dev/env/node_modules/ethers/src.ts/crypto/keccak.ts
generated
vendored
Executable file
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Cryptographic hashing functions
|
||||
*
|
||||
* @_subsection: api/crypto:Hash Functions [about-crypto-hashing]
|
||||
*/
|
||||
|
||||
import { keccak_256 } from "@noble/hashes/sha3";
|
||||
|
||||
import { getBytes, hexlify } from "../utils/index.js";
|
||||
|
||||
import type { BytesLike } from "../utils/index.js";
|
||||
|
||||
|
||||
let locked = false;
|
||||
|
||||
const _keccak256 = function(data: Uint8Array): Uint8Array {
|
||||
return keccak_256(data);
|
||||
}
|
||||
|
||||
let __keccak256: (data: Uint8Array) => BytesLike = _keccak256;
|
||||
|
||||
/**
|
||||
* Compute the cryptographic KECCAK256 hash of %%data%%.
|
||||
*
|
||||
* The %%data%% **must** be a data representation, to compute the
|
||||
* hash of UTF-8 data use the [[id]] function.
|
||||
*
|
||||
* @returns DataHexstring
|
||||
* @example:
|
||||
* keccak256("0x")
|
||||
* //_result:
|
||||
*
|
||||
* keccak256("0x1337")
|
||||
* //_result:
|
||||
*
|
||||
* keccak256(new Uint8Array([ 0x13, 0x37 ]))
|
||||
* //_result:
|
||||
*
|
||||
* // Strings are assumed to be DataHexString, otherwise it will
|
||||
* // throw. To hash UTF-8 data, see the note above.
|
||||
* keccak256("Hello World")
|
||||
* //_error:
|
||||
*/
|
||||
export function keccak256(_data: BytesLike): string {
|
||||
const data = getBytes(_data, "data");
|
||||
return hexlify(__keccak256(data));
|
||||
}
|
||||
keccak256._ = _keccak256;
|
||||
keccak256.lock = function(): void { locked = true; }
|
||||
keccak256.register = function(func: (data: Uint8Array) => BytesLike) {
|
||||
if (locked) { throw new TypeError("keccak256 is locked"); }
|
||||
__keccak256 = func;
|
||||
}
|
||||
Object.freeze(keccak256);
|
||||
55
dev/env/node_modules/ethers/src.ts/crypto/pbkdf2.ts
generated
vendored
Executable file
55
dev/env/node_modules/ethers/src.ts/crypto/pbkdf2.ts
generated
vendored
Executable file
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* A **Password-Based Key-Derivation Function** is designed to create
|
||||
* a sequence of bytes suitible as a **key** from a human-rememberable
|
||||
* password.
|
||||
*
|
||||
* @_subsection: api/crypto:Passwords [about-pbkdf]
|
||||
*/
|
||||
|
||||
import { pbkdf2Sync } from "./crypto.js";
|
||||
|
||||
import { getBytes, hexlify } from "../utils/index.js";
|
||||
|
||||
import type { BytesLike } from "../utils/index.js";
|
||||
|
||||
|
||||
let locked = false;
|
||||
|
||||
const _pbkdf2 = function(password: Uint8Array, salt: Uint8Array, iterations: number, keylen: number, algo: "sha256" | "sha512"): BytesLike {
|
||||
return pbkdf2Sync(password, salt, iterations, keylen, algo);
|
||||
}
|
||||
|
||||
let __pbkdf2 = _pbkdf2;
|
||||
|
||||
/**
|
||||
* Return the [[link-pbkdf2]] for %%keylen%% bytes for %%password%% using
|
||||
* the %%salt%% and using %%iterations%% of %%algo%%.
|
||||
*
|
||||
* This PBKDF is outdated and should not be used in new projects, but is
|
||||
* required to decrypt older files.
|
||||
*
|
||||
* @example:
|
||||
* // The password must be converted to bytes, and it is generally
|
||||
* // best practices to ensure the string has been normalized. Many
|
||||
* // formats explicitly indicate the normalization form to use.
|
||||
* password = "hello"
|
||||
* passwordBytes = toUtf8Bytes(password, "NFKC")
|
||||
*
|
||||
* salt = id("some-salt")
|
||||
*
|
||||
* // Compute the PBKDF2
|
||||
* pbkdf2(passwordBytes, salt, 1024, 16, "sha256")
|
||||
* //_result:
|
||||
*/
|
||||
export function pbkdf2(_password: BytesLike, _salt: BytesLike, iterations: number, keylen: number, algo: "sha256" | "sha512"): string {
|
||||
const password = getBytes(_password, "password");
|
||||
const salt = getBytes(_salt, "salt");
|
||||
return hexlify(__pbkdf2(password, salt, iterations, keylen, algo));
|
||||
}
|
||||
pbkdf2._ = _pbkdf2;
|
||||
pbkdf2.lock = function(): void { locked = true; }
|
||||
pbkdf2.register = function(func: (password: Uint8Array, salt: Uint8Array, iterations: number, keylen: number, algo: "sha256" | "sha512") => BytesLike) {
|
||||
if (locked) { throw new Error("pbkdf2 is locked"); }
|
||||
__pbkdf2 = func;
|
||||
}
|
||||
Object.freeze(pbkdf2);
|
||||
36
dev/env/node_modules/ethers/src.ts/crypto/random.ts
generated
vendored
Executable file
36
dev/env/node_modules/ethers/src.ts/crypto/random.ts
generated
vendored
Executable file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* A **Cryptographically Secure Random Value** is one that has been
|
||||
* generated with additional care take to prevent side-channels
|
||||
* from allowing others to detect it and prevent others from through
|
||||
* coincidence generate the same values.
|
||||
*
|
||||
* @_subsection: api/crypto:Random Values [about-crypto-random]
|
||||
*/
|
||||
import { randomBytes as crypto_random } from "./crypto.js";
|
||||
|
||||
let locked = false;
|
||||
|
||||
const _randomBytes = function(length: number): Uint8Array {
|
||||
return new Uint8Array(crypto_random(length));
|
||||
}
|
||||
|
||||
let __randomBytes = _randomBytes;
|
||||
|
||||
/**
|
||||
* Return %%length%% bytes of cryptographically secure random data.
|
||||
*
|
||||
* @example:
|
||||
* randomBytes(8)
|
||||
* //_result:
|
||||
*/
|
||||
export function randomBytes(length: number): Uint8Array {
|
||||
return __randomBytes(length);
|
||||
}
|
||||
|
||||
randomBytes._ = _randomBytes;
|
||||
randomBytes.lock = function(): void { locked = true; }
|
||||
randomBytes.register = function(func: (length: number) => Uint8Array) {
|
||||
if (locked) { throw new Error("randomBytes is locked"); }
|
||||
__randomBytes = func;
|
||||
}
|
||||
Object.freeze(randomBytes);
|
||||
43
dev/env/node_modules/ethers/src.ts/crypto/ripemd160.ts
generated
vendored
Executable file
43
dev/env/node_modules/ethers/src.ts/crypto/ripemd160.ts
generated
vendored
Executable file
@@ -0,0 +1,43 @@
|
||||
import { ripemd160 as noble_ripemd160 } from "@noble/hashes/ripemd160";
|
||||
|
||||
import { getBytes, hexlify } from "../utils/index.js";
|
||||
|
||||
import type { BytesLike } from "../utils/index.js";
|
||||
|
||||
|
||||
let locked = false;
|
||||
|
||||
const _ripemd160 = function(data: Uint8Array): Uint8Array {
|
||||
return noble_ripemd160(data);
|
||||
}
|
||||
|
||||
let __ripemd160: (data: Uint8Array) => BytesLike = _ripemd160;
|
||||
|
||||
/**
|
||||
* Compute the cryptographic RIPEMD-160 hash of %%data%%.
|
||||
*
|
||||
* @_docloc: api/crypto:Hash Functions
|
||||
* @returns DataHexstring
|
||||
*
|
||||
* @example:
|
||||
* ripemd160("0x")
|
||||
* //_result:
|
||||
*
|
||||
* ripemd160("0x1337")
|
||||
* //_result:
|
||||
*
|
||||
* ripemd160(new Uint8Array([ 0x13, 0x37 ]))
|
||||
* //_result:
|
||||
*
|
||||
*/
|
||||
export function ripemd160(_data: BytesLike): string {
|
||||
const data = getBytes(_data, "data");
|
||||
return hexlify(__ripemd160(data));
|
||||
}
|
||||
ripemd160._ = _ripemd160;
|
||||
ripemd160.lock = function(): void { locked = true; }
|
||||
ripemd160.register = function(func: (data: Uint8Array) => BytesLike) {
|
||||
if (locked) { throw new TypeError("ripemd160 is locked"); }
|
||||
__ripemd160 = func;
|
||||
}
|
||||
Object.freeze(ripemd160);
|
||||
114
dev/env/node_modules/ethers/src.ts/crypto/scrypt.ts
generated
vendored
Executable file
114
dev/env/node_modules/ethers/src.ts/crypto/scrypt.ts
generated
vendored
Executable file
@@ -0,0 +1,114 @@
|
||||
import { scrypt as _nobleSync, scryptAsync as _nobleAsync } from "@noble/hashes/scrypt";
|
||||
|
||||
import { getBytes, hexlify as H } from "../utils/index.js";
|
||||
|
||||
import type { BytesLike } from "../utils/index.js";
|
||||
|
||||
/**
|
||||
* A callback during long-running operations to update any
|
||||
* UI or provide programatic access to the progress.
|
||||
*
|
||||
* The %%percent%% is a value between ``0`` and ``1``.
|
||||
*
|
||||
* @_docloc: api/crypto:Passwords
|
||||
*/
|
||||
export type ProgressCallback = (percent: number) => void;
|
||||
|
||||
|
||||
let lockedSync = false, lockedAsync = false;
|
||||
|
||||
const _scryptAsync = async function(passwd: Uint8Array, salt: Uint8Array, N: number, r: number, p: number, dkLen: number, onProgress?: ProgressCallback) {
|
||||
return await _nobleAsync(passwd, salt, { N, r, p, dkLen, onProgress });
|
||||
}
|
||||
const _scryptSync = function(passwd: Uint8Array, salt: Uint8Array, N: number, r: number, p: number, dkLen: number) {
|
||||
return _nobleSync(passwd, salt, { N, r, p, dkLen });
|
||||
}
|
||||
|
||||
let __scryptAsync: (passwd: Uint8Array, salt: Uint8Array, N: number, r: number, p: number, dkLen: number, onProgress?: ProgressCallback) => Promise<BytesLike> = _scryptAsync;
|
||||
let __scryptSync: (passwd: Uint8Array, salt: Uint8Array, N: number, r: number, p: number, dkLen: number) => BytesLike = _scryptSync
|
||||
|
||||
|
||||
/**
|
||||
* The [[link-wiki-scrypt]] uses a memory and cpu hard method of
|
||||
* derivation to increase the resource cost to brute-force a password
|
||||
* for a given key.
|
||||
*
|
||||
* This means this algorithm is intentionally slow, and can be tuned to
|
||||
* become slower. As computation and memory speed improve over time,
|
||||
* increasing the difficulty maintains the cost of an attacker.
|
||||
*
|
||||
* For example, if a target time of 5 seconds is used, a legitimate user
|
||||
* which knows their password requires only 5 seconds to unlock their
|
||||
* account. A 6 character password has 68 billion possibilities, which
|
||||
* would require an attacker to invest over 10,000 years of CPU time. This
|
||||
* is of course a crude example (as password generally aren't random),
|
||||
* but demonstrates to value of imposing large costs to decryption.
|
||||
*
|
||||
* For this reason, if building a UI which involved decrypting or
|
||||
* encrypting datsa using scrypt, it is recommended to use a
|
||||
* [[ProgressCallback]] (as event short periods can seem lik an eternity
|
||||
* if the UI freezes). Including the phrase //"decrypting"// in the UI
|
||||
* can also help, assuring the user their waiting is for a good reason.
|
||||
*
|
||||
* @_docloc: api/crypto:Passwords
|
||||
*
|
||||
* @example:
|
||||
* // The password must be converted to bytes, and it is generally
|
||||
* // best practices to ensure the string has been normalized. Many
|
||||
* // formats explicitly indicate the normalization form to use.
|
||||
* password = "hello"
|
||||
* passwordBytes = toUtf8Bytes(password, "NFKC")
|
||||
*
|
||||
* salt = id("some-salt")
|
||||
*
|
||||
* // Compute the scrypt
|
||||
* scrypt(passwordBytes, salt, 1024, 8, 1, 16)
|
||||
* //_result:
|
||||
*/
|
||||
export async function scrypt(_passwd: BytesLike, _salt: BytesLike, N: number, r: number, p: number, dkLen: number, progress?: ProgressCallback): Promise<string> {
|
||||
const passwd = getBytes(_passwd, "passwd");
|
||||
const salt = getBytes(_salt, "salt");
|
||||
return H(await __scryptAsync(passwd, salt, N, r, p, dkLen, progress));
|
||||
}
|
||||
scrypt._ = _scryptAsync;
|
||||
scrypt.lock = function(): void { lockedAsync = true; }
|
||||
scrypt.register = function(func: (passwd: Uint8Array, salt: Uint8Array, N: number, r: number, p: number, dkLen: number, progress?: ProgressCallback) => Promise<BytesLike>) {
|
||||
if (lockedAsync) { throw new Error("scrypt is locked"); }
|
||||
__scryptAsync = func;
|
||||
}
|
||||
Object.freeze(scrypt);
|
||||
|
||||
/**
|
||||
* Provides a synchronous variant of [[scrypt]].
|
||||
*
|
||||
* This will completely lock up and freeze the UI in a browser and will
|
||||
* prevent any event loop from progressing. For this reason, it is
|
||||
* preferred to use the [async variant](scrypt).
|
||||
*
|
||||
* @_docloc: api/crypto:Passwords
|
||||
*
|
||||
* @example:
|
||||
* // The password must be converted to bytes, and it is generally
|
||||
* // best practices to ensure the string has been normalized. Many
|
||||
* // formats explicitly indicate the normalization form to use.
|
||||
* password = "hello"
|
||||
* passwordBytes = toUtf8Bytes(password, "NFKC")
|
||||
*
|
||||
* salt = id("some-salt")
|
||||
*
|
||||
* // Compute the scrypt
|
||||
* scryptSync(passwordBytes, salt, 1024, 8, 1, 16)
|
||||
* //_result:
|
||||
*/
|
||||
export function scryptSync(_passwd: BytesLike, _salt: BytesLike, N: number, r: number, p: number, dkLen: number): string {
|
||||
const passwd = getBytes(_passwd, "passwd");
|
||||
const salt = getBytes(_salt, "salt");
|
||||
return H(__scryptSync(passwd, salt, N, r, p, dkLen));
|
||||
}
|
||||
scryptSync._ = _scryptSync;
|
||||
scryptSync.lock = function(): void { lockedSync = true; }
|
||||
scryptSync.register = function(func: (passwd: Uint8Array, salt: Uint8Array, N: number, r: number, p: number, dkLen: number) => BytesLike) {
|
||||
if (lockedSync) { throw new Error("scryptSync is locked"); }
|
||||
__scryptSync = func;
|
||||
}
|
||||
Object.freeze(scryptSync);
|
||||
78
dev/env/node_modules/ethers/src.ts/crypto/sha2.ts
generated
vendored
Executable file
78
dev/env/node_modules/ethers/src.ts/crypto/sha2.ts
generated
vendored
Executable file
@@ -0,0 +1,78 @@
|
||||
import { createHash } from "./crypto.js";
|
||||
|
||||
import { getBytes, hexlify } from "../utils/index.js";
|
||||
|
||||
import type { BytesLike } from "../utils/index.js";
|
||||
|
||||
|
||||
const _sha256 = function(data: Uint8Array): Uint8Array {
|
||||
return createHash("sha256").update(data).digest();
|
||||
}
|
||||
|
||||
const _sha512 = function(data: Uint8Array): Uint8Array {
|
||||
return createHash("sha512").update(data).digest();
|
||||
}
|
||||
|
||||
let __sha256: (data: Uint8Array) => BytesLike = _sha256;
|
||||
let __sha512: (data: Uint8Array) => BytesLike = _sha512;
|
||||
|
||||
let locked256 = false, locked512 = false;
|
||||
|
||||
|
||||
/**
|
||||
* Compute the cryptographic SHA2-256 hash of %%data%%.
|
||||
*
|
||||
* @_docloc: api/crypto:Hash Functions
|
||||
* @returns DataHexstring
|
||||
*
|
||||
* @example:
|
||||
* sha256("0x")
|
||||
* //_result:
|
||||
*
|
||||
* sha256("0x1337")
|
||||
* //_result:
|
||||
*
|
||||
* sha256(new Uint8Array([ 0x13, 0x37 ]))
|
||||
* //_result:
|
||||
*
|
||||
*/
|
||||
export function sha256(_data: BytesLike): string {
|
||||
const data = getBytes(_data, "data");
|
||||
return hexlify(__sha256(data));
|
||||
}
|
||||
sha256._ = _sha256;
|
||||
sha256.lock = function(): void { locked256 = true; }
|
||||
sha256.register = function(func: (data: Uint8Array) => BytesLike): void {
|
||||
if (locked256) { throw new Error("sha256 is locked"); }
|
||||
__sha256 = func;
|
||||
}
|
||||
Object.freeze(sha256);
|
||||
|
||||
|
||||
/**
|
||||
* Compute the cryptographic SHA2-512 hash of %%data%%.
|
||||
*
|
||||
* @_docloc: api/crypto:Hash Functions
|
||||
* @returns DataHexstring
|
||||
*
|
||||
* @example:
|
||||
* sha512("0x")
|
||||
* //_result:
|
||||
*
|
||||
* sha512("0x1337")
|
||||
* //_result:
|
||||
*
|
||||
* sha512(new Uint8Array([ 0x13, 0x37 ]))
|
||||
* //_result:
|
||||
*/
|
||||
export function sha512(_data: BytesLike): string {
|
||||
const data = getBytes(_data, "data");
|
||||
return hexlify(__sha512(data));
|
||||
}
|
||||
sha512._ = _sha512;
|
||||
sha512.lock = function(): void { locked512 = true; }
|
||||
sha512.register = function(func: (data: Uint8Array) => BytesLike): void {
|
||||
if (locked512) { throw new Error("sha512 is locked"); }
|
||||
__sha512 = func;
|
||||
}
|
||||
Object.freeze(sha256);
|
||||
410
dev/env/node_modules/ethers/src.ts/crypto/signature.ts
generated
vendored
Executable file
410
dev/env/node_modules/ethers/src.ts/crypto/signature.ts
generated
vendored
Executable file
@@ -0,0 +1,410 @@
|
||||
|
||||
import { ZeroHash } from "../constants/index.js";
|
||||
import {
|
||||
concat, dataLength, getBigInt, getBytes, getNumber, hexlify,
|
||||
toBeArray, isHexString, zeroPadValue,
|
||||
assertArgument, assertPrivate
|
||||
} from "../utils/index.js";
|
||||
|
||||
import type {
|
||||
BigNumberish, BytesLike, Numeric
|
||||
} from "../utils/index.js";
|
||||
|
||||
|
||||
// Constants
|
||||
const BN_0 = BigInt(0);
|
||||
const BN_1 = BigInt(1);
|
||||
const BN_2 = BigInt(2);
|
||||
const BN_27 = BigInt(27);
|
||||
const BN_28 = BigInt(28);
|
||||
const BN_35 = BigInt(35);
|
||||
const BN_N = BigInt("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141");
|
||||
const BN_N_2 = BN_N / BN_2; // Must be integer (floor) division; do NOT shifts
|
||||
|
||||
const inspect = Symbol.for("nodejs.util.inspect.custom");
|
||||
|
||||
const _guard = { };
|
||||
|
||||
// @TODO: Allow Uint8Array
|
||||
|
||||
/**
|
||||
* A SignatureLike
|
||||
*
|
||||
* @_docloc: api/crypto:Signing
|
||||
*/
|
||||
export type SignatureLike = Signature | string | {
|
||||
r: string;
|
||||
s: string;
|
||||
v: BigNumberish;
|
||||
yParity?: 0 | 1;
|
||||
yParityAndS?: string;
|
||||
} | {
|
||||
r: string;
|
||||
yParityAndS: string;
|
||||
yParity?: 0 | 1;
|
||||
s?: string;
|
||||
v?: number;
|
||||
} | {
|
||||
r: string;
|
||||
s: string;
|
||||
yParity: 0 | 1;
|
||||
v?: BigNumberish;
|
||||
yParityAndS?: string;
|
||||
};
|
||||
|
||||
function toUint256(value: BigNumberish): string {
|
||||
return zeroPadValue(toBeArray(value), 32);
|
||||
}
|
||||
|
||||
/**
|
||||
* A Signature @TODO
|
||||
*
|
||||
*
|
||||
* @_docloc: api/crypto:Signing
|
||||
*/
|
||||
export class Signature {
|
||||
#r: string;
|
||||
#s: string;
|
||||
#v: 27 | 28;
|
||||
#networkV: null | bigint;
|
||||
|
||||
/**
|
||||
* The ``r`` value for a signature.
|
||||
*
|
||||
* This represents the ``x`` coordinate of a "reference" or
|
||||
* challenge point, from which the ``y`` can be computed.
|
||||
*/
|
||||
get r(): string { return this.#r; }
|
||||
set r(value: BytesLike) {
|
||||
assertArgument(dataLength(value) === 32, "invalid r", "value", value);
|
||||
this.#r = hexlify(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The ``s`` value for a signature.
|
||||
*/
|
||||
get s(): string {
|
||||
assertArgument(parseInt(this.#s.substring(0, 3)) < 8, "non-canonical s; use ._s", "s", this.#s);
|
||||
return this.#s;
|
||||
}
|
||||
set s(_value: BytesLike) {
|
||||
assertArgument(dataLength(_value) === 32, "invalid s", "value", _value);
|
||||
this.#s = hexlify(_value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the s value, unchecked for EIP-2 compliance.
|
||||
*
|
||||
* This should generally not be used and is for situations where
|
||||
* a non-canonical S value might be relevant, such as Frontier blocks
|
||||
* that were mined prior to EIP-2 or invalid Authorization List
|
||||
* signatures.
|
||||
*/
|
||||
get _s(): string { return this.#s; }
|
||||
|
||||
/**
|
||||
* Returns true if the Signature is valid for [[link-eip-2]] signatures.
|
||||
*/
|
||||
isValid(): boolean {
|
||||
const s = BigInt(this.#s);
|
||||
return (s <= BN_N_2);
|
||||
}
|
||||
|
||||
/**
|
||||
* The ``v`` value for a signature.
|
||||
*
|
||||
* Since a given ``x`` value for ``r`` has two possible values for
|
||||
* its correspondin ``y``, the ``v`` indicates which of the two ``y``
|
||||
* values to use.
|
||||
*
|
||||
* It is normalized to the values ``27`` or ``28`` for legacy
|
||||
* purposes.
|
||||
*/
|
||||
get v(): 27 | 28 { return this.#v; }
|
||||
set v(value: BigNumberish) {
|
||||
const v = getNumber(value, "value");
|
||||
assertArgument(v === 27 || v === 28, "invalid v", "v", value);
|
||||
this.#v = v;
|
||||
}
|
||||
|
||||
/**
|
||||
* The EIP-155 ``v`` for legacy transactions. For non-legacy
|
||||
* transactions, this value is ``null``.
|
||||
*/
|
||||
get networkV(): null | bigint { return this.#networkV; }
|
||||
|
||||
/**
|
||||
* The chain ID for EIP-155 legacy transactions. For non-legacy
|
||||
* transactions, this value is ``null``.
|
||||
*/
|
||||
get legacyChainId(): null | bigint {
|
||||
const v = this.networkV;
|
||||
if (v == null) { return null; }
|
||||
return Signature.getChainId(v);
|
||||
}
|
||||
|
||||
/**
|
||||
* The ``yParity`` for the signature.
|
||||
*
|
||||
* See ``v`` for more details on how this value is used.
|
||||
*/
|
||||
get yParity(): 0 | 1 {
|
||||
return (this.v === 27) ? 0: 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* The [[link-eip-2098]] compact representation of the ``yParity``
|
||||
* and ``s`` compacted into a single ``bytes32``.
|
||||
*/
|
||||
get yParityAndS(): string {
|
||||
// The EIP-2098 compact representation
|
||||
const yParityAndS = getBytes(this.s);
|
||||
if (this.yParity) { yParityAndS[0] |= 0x80; }
|
||||
return hexlify(yParityAndS);
|
||||
}
|
||||
|
||||
/**
|
||||
* The [[link-eip-2098]] compact representation.
|
||||
*/
|
||||
get compactSerialized(): string {
|
||||
return concat([ this.r, this.yParityAndS ]);
|
||||
}
|
||||
|
||||
/**
|
||||
* The serialized representation.
|
||||
*/
|
||||
get serialized(): string {
|
||||
return concat([ this.r, this.s, (this.yParity ? "0x1c": "0x1b") ]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
constructor(guard: any, r: string, s: string, v: 27 | 28) {
|
||||
assertPrivate(guard, _guard, "Signature");
|
||||
this.#r = r;
|
||||
this.#s = s;
|
||||
this.#v = v;
|
||||
this.#networkV = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the canonical signature.
|
||||
*
|
||||
* This is only necessary when dealing with legacy transaction which
|
||||
* did not enforce canonical S values (i.e. [[link-eip-2]]. Most
|
||||
* developers should never require this.
|
||||
*/
|
||||
getCanonical(): Signature {
|
||||
if (this.isValid()) { return this; }
|
||||
|
||||
// Compute the canonical signature; s' = N - s, v = !v
|
||||
const s = BN_N - BigInt(this._s);
|
||||
const v = <27 | 28>(55 - this.v);
|
||||
const result = new Signature(_guard, this.r, toUint256(s), v);
|
||||
|
||||
// Populate the networkV if necessary
|
||||
if (this.networkV) { result.#networkV = this.networkV; }
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new identical [[Signature]].
|
||||
*/
|
||||
clone(): Signature {
|
||||
const clone = new Signature(_guard, this.r, this._s, this.v);
|
||||
if (this.networkV) { clone.#networkV = this.networkV; }
|
||||
return clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a representation that is compatible with ``JSON.stringify``.
|
||||
*/
|
||||
toJSON(): any {
|
||||
const networkV = this.networkV;
|
||||
return {
|
||||
_type: "signature",
|
||||
networkV: ((networkV != null) ? networkV.toString(): null),
|
||||
r: this.r, s: this._s, v: this.v,
|
||||
};
|
||||
}
|
||||
|
||||
[inspect](): string {
|
||||
return this.toString();
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
if (this.isValid()) {
|
||||
return `Signature { r: ${ this.r }, s: ${ this._s }, v: ${ this.v } }`;
|
||||
}
|
||||
return `Signature { r: ${ this.r }, s: ${ this._s }, v: ${ this.v }, valid: false }`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the chain ID from the ``v`` in a legacy EIP-155 transactions.
|
||||
*
|
||||
* @example:
|
||||
* Signature.getChainId(45)
|
||||
* //_result:
|
||||
*
|
||||
* Signature.getChainId(46)
|
||||
* //_result:
|
||||
*/
|
||||
static getChainId(v: BigNumberish): bigint {
|
||||
const bv = getBigInt(v, "v");
|
||||
|
||||
// The v is not an EIP-155 v, so it is the unspecified chain ID
|
||||
if ((bv == BN_27) || (bv == BN_28)) { return BN_0; }
|
||||
|
||||
// Bad value for an EIP-155 v
|
||||
assertArgument(bv >= BN_35, "invalid EIP-155 v", "v", v);
|
||||
|
||||
return (bv - BN_35) / BN_2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the ``v`` for a chain ID for a legacy EIP-155 transactions.
|
||||
*
|
||||
* Legacy transactions which use [[link-eip-155]] hijack the ``v``
|
||||
* property to include the chain ID.
|
||||
*
|
||||
* @example:
|
||||
* Signature.getChainIdV(5, 27)
|
||||
* //_result:
|
||||
*
|
||||
* Signature.getChainIdV(5, 28)
|
||||
* //_result:
|
||||
*
|
||||
*/
|
||||
static getChainIdV(chainId: BigNumberish, v: 27 | 28): bigint {
|
||||
return (getBigInt(chainId) * BN_2) + BigInt(35 + v - 27);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the normalized legacy transaction ``v`` from a ``yParirty``,
|
||||
* a legacy transaction ``v`` or a legacy [[link-eip-155]] transaction.
|
||||
*
|
||||
* @example:
|
||||
* // The values 0 and 1 imply v is actually yParity
|
||||
* Signature.getNormalizedV(0)
|
||||
* //_result:
|
||||
*
|
||||
* // Legacy non-EIP-1559 transaction (i.e. 27 or 28)
|
||||
* Signature.getNormalizedV(27)
|
||||
* //_result:
|
||||
*
|
||||
* // Legacy EIP-155 transaction (i.e. >= 35)
|
||||
* Signature.getNormalizedV(46)
|
||||
* //_result:
|
||||
*
|
||||
* // Invalid values throw
|
||||
* Signature.getNormalizedV(5)
|
||||
* //_error:
|
||||
*/
|
||||
static getNormalizedV(v: BigNumberish): 27 | 28 {
|
||||
const bv = getBigInt(v);
|
||||
|
||||
if (bv === BN_0 || bv === BN_27) { return 27; }
|
||||
if (bv === BN_1 || bv === BN_28) { return 28; }
|
||||
|
||||
assertArgument(bv >= BN_35, "invalid v", "v", v);
|
||||
|
||||
// Otherwise, EIP-155 v means odd is 27 and even is 28
|
||||
return (bv & BN_1) ? 27: 28;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new [[Signature]].
|
||||
*
|
||||
* If no %%sig%% is provided, a new [[Signature]] is created
|
||||
* with default values.
|
||||
*
|
||||
* If %%sig%% is a string, it is parsed.
|
||||
*/
|
||||
static from(sig?: SignatureLike): Signature {
|
||||
function assertError(check: unknown, message: string): asserts check {
|
||||
assertArgument(check, message, "signature", sig);
|
||||
};
|
||||
|
||||
if (sig == null) {
|
||||
return new Signature(_guard, ZeroHash, ZeroHash, 27);
|
||||
}
|
||||
|
||||
if (typeof(sig) === "string") {
|
||||
const bytes = getBytes(sig, "signature");
|
||||
if (bytes.length === 64) {
|
||||
const r = hexlify(bytes.slice(0, 32));
|
||||
const s = bytes.slice(32, 64);
|
||||
const v = (s[0] & 0x80) ? 28: 27;
|
||||
s[0] &= 0x7f;
|
||||
return new Signature(_guard, r, hexlify(s), v);
|
||||
}
|
||||
|
||||
if (bytes.length === 65) {
|
||||
const r = hexlify(bytes.slice(0, 32));
|
||||
const s = hexlify(bytes.slice(32, 64));
|
||||
const v = Signature.getNormalizedV(bytes[64]);
|
||||
return new Signature(_guard, r, s, v);
|
||||
}
|
||||
|
||||
assertError(false, "invalid raw signature length");
|
||||
}
|
||||
|
||||
if (sig instanceof Signature) { return sig.clone(); }
|
||||
|
||||
// Get r
|
||||
const _r = sig.r;
|
||||
assertError(_r != null, "missing r");
|
||||
const r = toUint256(_r);
|
||||
|
||||
// Get s; by any means necessary (we check consistency below)
|
||||
const s = (function(s?: string, yParityAndS?: string) {
|
||||
if (s != null) { return toUint256(s); }
|
||||
|
||||
if (yParityAndS != null) {
|
||||
assertError(isHexString(yParityAndS, 32), "invalid yParityAndS");
|
||||
const bytes = getBytes(yParityAndS);
|
||||
bytes[0] &= 0x7f;
|
||||
return hexlify(bytes);
|
||||
}
|
||||
|
||||
assertError(false, "missing s");
|
||||
})(sig.s, sig.yParityAndS);
|
||||
|
||||
// Get v; by any means necessary (we check consistency below)
|
||||
const { networkV, v } = (function(_v?: BigNumberish, yParityAndS?: string, yParity?: Numeric): { networkV?: bigint, v: 27 | 28 } {
|
||||
if (_v != null) {
|
||||
const v = getBigInt(_v);
|
||||
return {
|
||||
networkV: ((v >= BN_35) ? v: undefined),
|
||||
v: Signature.getNormalizedV(v)
|
||||
};
|
||||
}
|
||||
|
||||
if (yParityAndS != null) {
|
||||
assertError(isHexString(yParityAndS, 32), "invalid yParityAndS");
|
||||
return { v: ((getBytes(yParityAndS)[0] & 0x80) ? 28: 27) };
|
||||
}
|
||||
|
||||
if (yParity != null) {
|
||||
switch (getNumber(yParity, "sig.yParity")) {
|
||||
case 0: return { v: 27 };
|
||||
case 1: return { v: 28 };
|
||||
}
|
||||
assertError(false, "invalid yParity");
|
||||
}
|
||||
|
||||
assertError(false, "missing v");
|
||||
})(sig.v, sig.yParityAndS, sig.yParity);
|
||||
|
||||
const result = new Signature(_guard, r, s, v);
|
||||
if (networkV) { result.#networkV = networkV; }
|
||||
|
||||
// If multiple of v, yParity, yParityAndS we given, check they match
|
||||
assertError(sig.yParity == null || getNumber(sig.yParity, "sig.yParity") === result.yParity, "yParity mismatch");
|
||||
assertError(sig.yParityAndS == null || sig.yParityAndS === result.yParityAndS, "yParityAndS mismatch");
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
196
dev/env/node_modules/ethers/src.ts/crypto/signing-key.ts
generated
vendored
Executable file
196
dev/env/node_modules/ethers/src.ts/crypto/signing-key.ts
generated
vendored
Executable file
@@ -0,0 +1,196 @@
|
||||
/**
|
||||
* Add details about signing here.
|
||||
*
|
||||
* @_subsection: api/crypto:Signing [about-signing]
|
||||
*/
|
||||
|
||||
import { secp256k1 } from "@noble/curves/secp256k1";
|
||||
|
||||
import {
|
||||
concat, dataLength, getBytes, getBytesCopy, hexlify, toBeHex,
|
||||
assertArgument
|
||||
} from "../utils/index.js";
|
||||
|
||||
import { Signature } from "./signature.js";
|
||||
|
||||
import type { BytesLike } from "../utils/index.js";
|
||||
|
||||
import type { SignatureLike } from "./index.js";
|
||||
|
||||
|
||||
/**
|
||||
* A **SigningKey** provides high-level access to the elliptic curve
|
||||
* cryptography (ECC) operations and key management.
|
||||
*/
|
||||
export class SigningKey {
|
||||
#privateKey: string;
|
||||
|
||||
/**
|
||||
* Creates a new **SigningKey** for %%privateKey%%.
|
||||
*/
|
||||
constructor(privateKey: BytesLike) {
|
||||
assertArgument(dataLength(privateKey) === 32, "invalid private key", "privateKey", "[REDACTED]");
|
||||
this.#privateKey = hexlify(privateKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* The private key.
|
||||
*/
|
||||
get privateKey(): string { return this.#privateKey; }
|
||||
|
||||
/**
|
||||
* The uncompressed public key.
|
||||
*
|
||||
* This will always begin with the prefix ``0x04`` and be 132
|
||||
* characters long (the ``0x`` prefix and 130 hexadecimal nibbles).
|
||||
*/
|
||||
get publicKey(): string { return SigningKey.computePublicKey(this.#privateKey); }
|
||||
|
||||
/**
|
||||
* The compressed public key.
|
||||
*
|
||||
* This will always begin with either the prefix ``0x02`` or ``0x03``
|
||||
* and be 68 characters long (the ``0x`` prefix and 33 hexadecimal
|
||||
* nibbles)
|
||||
*/
|
||||
get compressedPublicKey(): string { return SigningKey.computePublicKey(this.#privateKey, true); }
|
||||
|
||||
/**
|
||||
* Return the signature of the signed %%digest%%.
|
||||
*/
|
||||
sign(digest: BytesLike): Signature {
|
||||
assertArgument(dataLength(digest) === 32, "invalid digest length", "digest", digest);
|
||||
|
||||
const sig = secp256k1.sign(getBytesCopy(digest), getBytesCopy(this.#privateKey), {
|
||||
lowS: true
|
||||
});
|
||||
|
||||
return Signature.from({
|
||||
r: toBeHex(sig.r, 32),
|
||||
s: toBeHex(sig.s, 32),
|
||||
v: (sig.recovery ? 0x1c: 0x1b)
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the [[link-wiki-ecdh]] shared secret between this
|
||||
* private key and the %%other%% key.
|
||||
*
|
||||
* The %%other%% key may be any type of key, a raw public key,
|
||||
* a compressed/uncompressed pubic key or aprivate key.
|
||||
*
|
||||
* Best practice is usually to use a cryptographic hash on the
|
||||
* returned value before using it as a symetric secret.
|
||||
*
|
||||
* @example:
|
||||
* sign1 = new SigningKey(id("some-secret-1"))
|
||||
* sign2 = new SigningKey(id("some-secret-2"))
|
||||
*
|
||||
* // Notice that privA.computeSharedSecret(pubB)...
|
||||
* sign1.computeSharedSecret(sign2.publicKey)
|
||||
* //_result:
|
||||
*
|
||||
* // ...is equal to privB.computeSharedSecret(pubA).
|
||||
* sign2.computeSharedSecret(sign1.publicKey)
|
||||
* //_result:
|
||||
*/
|
||||
computeSharedSecret(other: BytesLike): string {
|
||||
const pubKey = SigningKey.computePublicKey(other);
|
||||
return hexlify(secp256k1.getSharedSecret(getBytesCopy(this.#privateKey), getBytes(pubKey), false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the public key for %%key%%, optionally %%compressed%%.
|
||||
*
|
||||
* The %%key%% may be any type of key, a raw public key, a
|
||||
* compressed/uncompressed public key or private key.
|
||||
*
|
||||
* @example:
|
||||
* sign = new SigningKey(id("some-secret"));
|
||||
*
|
||||
* // Compute the uncompressed public key for a private key
|
||||
* SigningKey.computePublicKey(sign.privateKey)
|
||||
* //_result:
|
||||
*
|
||||
* // Compute the compressed public key for a private key
|
||||
* SigningKey.computePublicKey(sign.privateKey, true)
|
||||
* //_result:
|
||||
*
|
||||
* // Compute the uncompressed public key
|
||||
* SigningKey.computePublicKey(sign.publicKey, false);
|
||||
* //_result:
|
||||
*
|
||||
* // Compute the Compressed a public key
|
||||
* SigningKey.computePublicKey(sign.publicKey, true);
|
||||
* //_result:
|
||||
*/
|
||||
static computePublicKey(key: BytesLike, compressed?: boolean): string {
|
||||
let bytes = getBytes(key, "key");
|
||||
|
||||
// private key
|
||||
if (bytes.length === 32) {
|
||||
const pubKey = secp256k1.getPublicKey(bytes, !!compressed);
|
||||
return hexlify(pubKey);
|
||||
}
|
||||
|
||||
// raw public key; use uncompressed key with 0x04 prefix
|
||||
if (bytes.length === 64) {
|
||||
const pub = new Uint8Array(65);
|
||||
pub[0] = 0x04;
|
||||
pub.set(bytes, 1);
|
||||
bytes = pub;
|
||||
}
|
||||
|
||||
const point = secp256k1.ProjectivePoint.fromHex(bytes);
|
||||
return hexlify(point.toRawBytes(compressed));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the public key for the private key which produced the
|
||||
* %%signature%% for the given %%digest%%.
|
||||
*
|
||||
* @example:
|
||||
* key = new SigningKey(id("some-secret"))
|
||||
* digest = id("hello world")
|
||||
* sig = key.sign(digest)
|
||||
*
|
||||
* // Notice the signer public key...
|
||||
* key.publicKey
|
||||
* //_result:
|
||||
*
|
||||
* // ...is equal to the recovered public key
|
||||
* SigningKey.recoverPublicKey(digest, sig)
|
||||
* //_result:
|
||||
*
|
||||
*/
|
||||
static recoverPublicKey(digest: BytesLike, signature: SignatureLike): string {
|
||||
assertArgument(dataLength(digest) === 32, "invalid digest length", "digest", digest);
|
||||
|
||||
const sig = Signature.from(signature);
|
||||
|
||||
let secpSig = secp256k1.Signature.fromCompact(getBytesCopy(concat([ sig.r, sig.s ])));
|
||||
secpSig = secpSig.addRecoveryBit(sig.yParity);
|
||||
|
||||
const pubKey = secpSig.recoverPublicKey(getBytesCopy(digest));
|
||||
assertArgument(pubKey != null, "invalid signature for digest", "signature", signature);
|
||||
|
||||
return "0x" + pubKey.toHex(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the point resulting from adding the ellipic curve points
|
||||
* %%p0%% and %%p1%%.
|
||||
*
|
||||
* This is not a common function most developers should require, but
|
||||
* can be useful for certain privacy-specific techniques.
|
||||
*
|
||||
* For example, it is used by [[HDNodeWallet]] to compute child
|
||||
* addresses from parent public keys and chain codes.
|
||||
*/
|
||||
static addPoints(p0: BytesLike, p1: BytesLike, compressed?: boolean): string {
|
||||
const pub0 = secp256k1.ProjectivePoint.fromHex(SigningKey.computePublicKey(p0).substring(2));
|
||||
const pub1 = secp256k1.ProjectivePoint.fromHex(SigningKey.computePublicKey(p1).substring(2));
|
||||
return "0x" + pub0.add(pub1).toHex(!!compressed)
|
||||
}
|
||||
}
|
||||
|
||||
221
dev/env/node_modules/ethers/src.ts/ethers.ts
generated
vendored
Executable file
221
dev/env/node_modules/ethers/src.ts/ethers.ts
generated
vendored
Executable file
@@ -0,0 +1,221 @@
|
||||
|
||||
|
||||
/////////////////////////////
|
||||
//
|
||||
|
||||
export { version } from "./_version.js";
|
||||
|
||||
export {
|
||||
decodeBytes32String, encodeBytes32String,
|
||||
|
||||
AbiCoder,
|
||||
ConstructorFragment, ErrorFragment, EventFragment, Fragment, FallbackFragment, FunctionFragment, NamedFragment, ParamType, StructFragment,
|
||||
|
||||
checkResultErrors, ErrorDescription, Indexed, Interface, LogDescription, Result, TransactionDescription,
|
||||
Typed,
|
||||
} from "./abi/index.js";
|
||||
|
||||
export {
|
||||
getAddress, getIcapAddress,
|
||||
getCreateAddress, getCreate2Address,
|
||||
isAddressable, isAddress, resolveAddress
|
||||
} from "./address/index.js";
|
||||
|
||||
export {
|
||||
ZeroAddress,
|
||||
WeiPerEther, MaxUint256, MinInt256, MaxInt256, N,
|
||||
ZeroHash,
|
||||
EtherSymbol, MessagePrefix
|
||||
} from "./constants/index.js";
|
||||
|
||||
export {
|
||||
BaseContract, Contract,
|
||||
ContractFactory,
|
||||
ContractEventPayload, ContractTransactionReceipt, ContractTransactionResponse, ContractUnknownEventPayload, EventLog, UndecodedEventLog
|
||||
} from "./contract/index.js";
|
||||
|
||||
export {
|
||||
computeHmac,
|
||||
randomBytes,
|
||||
keccak256,
|
||||
ripemd160,
|
||||
sha256, sha512,
|
||||
pbkdf2,
|
||||
scrypt, scryptSync,
|
||||
lock,
|
||||
Signature, SigningKey
|
||||
} from "./crypto/index.js";
|
||||
|
||||
export {
|
||||
id,
|
||||
ensNormalize, isValidName, namehash, dnsEncode,
|
||||
hashAuthorization, verifyAuthorization,
|
||||
hashMessage, verifyMessage,
|
||||
solidityPacked, solidityPackedKeccak256, solidityPackedSha256,
|
||||
TypedDataEncoder,
|
||||
verifyTypedData
|
||||
} from "./hash/index.js";
|
||||
|
||||
export {
|
||||
getDefaultProvider,
|
||||
|
||||
Block, FeeData, Log, TransactionReceipt, TransactionResponse,
|
||||
|
||||
AbstractSigner, NonceManager, VoidSigner,
|
||||
|
||||
AbstractProvider,
|
||||
|
||||
FallbackProvider,
|
||||
JsonRpcApiProvider, JsonRpcProvider, JsonRpcSigner,
|
||||
|
||||
BrowserProvider,
|
||||
|
||||
AlchemyProvider, AnkrProvider, BlockscoutProvider, ChainstackProvider,
|
||||
CloudflareProvider, EtherscanProvider, InfuraProvider,
|
||||
InfuraWebSocketProvider, PocketProvider, QuickNodeProvider,
|
||||
|
||||
IpcSocketProvider, SocketProvider, WebSocketProvider,
|
||||
|
||||
EnsResolver,
|
||||
Network,
|
||||
|
||||
EnsPlugin, EtherscanPlugin,
|
||||
FeeDataNetworkPlugin, FetchUrlFeeDataNetworkPlugin,
|
||||
GasCostPlugin, NetworkPlugin, MulticoinProviderPlugin,
|
||||
|
||||
SocketBlockSubscriber, SocketEventSubscriber, SocketPendingSubscriber,
|
||||
SocketSubscriber, UnmanagedSubscriber,
|
||||
|
||||
copyRequest, showThrottleMessage
|
||||
} from "./providers/index.js";
|
||||
|
||||
export {
|
||||
accessListify, authorizationify,
|
||||
computeAddress, recoverAddress,
|
||||
Transaction
|
||||
} from "./transaction/index.js";
|
||||
|
||||
export {
|
||||
decodeBase58, encodeBase58,
|
||||
decodeBase64, encodeBase64,
|
||||
concat, dataLength, dataSlice, getBytes, getBytesCopy, hexlify,
|
||||
isHexString, isBytesLike, stripZerosLeft, zeroPadBytes, zeroPadValue,
|
||||
defineProperties, resolveProperties,
|
||||
assert, assertArgument, assertArgumentCount, assertNormalize, assertPrivate,
|
||||
makeError,
|
||||
isCallException, isError,
|
||||
EventPayload,
|
||||
FetchRequest, FetchResponse, FetchCancelSignal,
|
||||
FixedNumber,
|
||||
getBigInt, getNumber, getUint, toBeArray, toBigInt, toBeHex, toNumber, toQuantity,
|
||||
fromTwos, toTwos, mask,
|
||||
formatEther, parseEther, formatUnits, parseUnits,
|
||||
toUtf8Bytes, toUtf8CodePoints, toUtf8String,
|
||||
Utf8ErrorFuncs,
|
||||
decodeRlp, encodeRlp,
|
||||
uuidV4,
|
||||
} from "./utils/index.js";
|
||||
|
||||
export {
|
||||
Mnemonic,
|
||||
BaseWallet, HDNodeWallet, HDNodeVoidWallet,
|
||||
Wallet,
|
||||
|
||||
defaultPath,
|
||||
|
||||
getAccountPath, getIndexedAccountPath,
|
||||
isCrowdsaleJson, isKeystoreJson,
|
||||
|
||||
decryptCrowdsaleJson, decryptKeystoreJsonSync, decryptKeystoreJson,
|
||||
encryptKeystoreJson, encryptKeystoreJsonSync,
|
||||
} from "./wallet/index.js";
|
||||
|
||||
export {
|
||||
Wordlist, LangEn, WordlistOwl, WordlistOwlA, wordlists
|
||||
} from "./wordlists/index.js";
|
||||
|
||||
|
||||
|
||||
/////////////////////////////
|
||||
// Types
|
||||
|
||||
export type {
|
||||
JsonFragment, JsonFragmentType,
|
||||
FormatType, FragmentType,
|
||||
InterfaceAbi,
|
||||
ParamTypeWalkFunc, ParamTypeWalkAsyncFunc
|
||||
} from "./abi/index.js";
|
||||
|
||||
export type {
|
||||
Addressable, AddressLike, NameResolver
|
||||
} from "./address/index.js";
|
||||
|
||||
export type {
|
||||
ConstantContractMethod, ContractEvent, ContractEventArgs, ContractEventName,
|
||||
ContractInterface, ContractMethod, ContractMethodArgs, ContractTransaction,
|
||||
DeferredTopicFilter, Overrides,
|
||||
BaseContractMethod, ContractDeployTransaction, PostfixOverrides,
|
||||
WrappedFallback
|
||||
} from "./contract/index.js";
|
||||
|
||||
export type { ProgressCallback, SignatureLike } from "./crypto/index.js";
|
||||
|
||||
export type {
|
||||
AuthorizationRequest, TypedDataDomain, TypedDataField
|
||||
} from "./hash/index.js";
|
||||
|
||||
export type {
|
||||
Provider, Signer,
|
||||
|
||||
CommunityResourcable,
|
||||
|
||||
AbstractProviderOptions, BrowserProviderOptions, FallbackProviderOptions,
|
||||
|
||||
AbstractProviderPlugin, BlockParams, BlockTag, BrowserDiscoverOptions,
|
||||
ContractRunner, DebugEventBrowserProvider, Eip1193Provider,
|
||||
Eip6963ProviderInfo, EventFilter, Filter, FilterByBlockHash,
|
||||
GasCostParameters, JsonRpcApiProviderOptions, JsonRpcError,
|
||||
JsonRpcPayload, JsonRpcResult, JsonRpcTransactionRequest, LogParams,
|
||||
MinedBlock, MinedTransactionResponse, Networkish, OrphanFilter,
|
||||
PerformActionFilter, PerformActionRequest, PerformActionTransaction,
|
||||
PreparedTransactionRequest, ProviderEvent, Subscriber, Subscription,
|
||||
TopicFilter, TransactionReceiptParams, TransactionRequest,
|
||||
TransactionResponseParams, WebSocketCreator, WebSocketLike
|
||||
} from "./providers/index.js";
|
||||
|
||||
export type {
|
||||
AccessList, AccessListish, AccessListEntry,
|
||||
Authorization, AuthorizationLike,
|
||||
Blob, BlobLike, KzgLibrary, KzgLibraryLike,
|
||||
TransactionLike
|
||||
} from "./transaction/index.js";
|
||||
|
||||
export type {
|
||||
BytesLike,
|
||||
BigNumberish, Numeric,
|
||||
ErrorCode,
|
||||
FixedFormat,
|
||||
Utf8ErrorFunc, UnicodeNormalizationForm, Utf8ErrorReason,
|
||||
RlpStructuredData, RlpStructuredDataish,
|
||||
|
||||
GetUrlResponse,
|
||||
FetchPreflightFunc, FetchProcessFunc, FetchRetryFunc,
|
||||
FetchGatewayFunc, FetchGetUrlFunc,
|
||||
|
||||
EthersError, UnknownError, NotImplementedError, UnsupportedOperationError, NetworkError,
|
||||
ServerError, TimeoutError, BadDataError, CancelledError, BufferOverrunError,
|
||||
NumericFaultError, InvalidArgumentError, MissingArgumentError, UnexpectedArgumentError,
|
||||
CallExceptionError, InsufficientFundsError, NonceExpiredError, OffchainFaultError,
|
||||
ReplacementUnderpricedError, TransactionReplacedError, UnconfiguredNameError,
|
||||
ActionRejectedError,
|
||||
CodedEthersError,
|
||||
|
||||
CallExceptionAction, CallExceptionTransaction,
|
||||
EventEmitterable, Listener
|
||||
} from "./utils/index.js";
|
||||
|
||||
export type {
|
||||
CrowdsaleAccount, KeystoreAccount, EncryptOptions
|
||||
} from "./wallet/index.js";
|
||||
|
||||
// dummy change; to pick-up ws security issue changes
|
||||
38
dev/env/node_modules/ethers/src.ts/hash/authorization.ts
generated
vendored
Executable file
38
dev/env/node_modules/ethers/src.ts/hash/authorization.ts
generated
vendored
Executable file
@@ -0,0 +1,38 @@
|
||||
import { getAddress } from "../address/index.js";
|
||||
import { keccak256 } from "../crypto/index.js";
|
||||
import { recoverAddress } from "../transaction/index.js";
|
||||
import {
|
||||
assertArgument, concat, encodeRlp, toBeArray
|
||||
} from "../utils/index.js";
|
||||
|
||||
import type { Addressable } from "../address/index.js";
|
||||
import type { SignatureLike } from "../crypto/index.js";
|
||||
import type { BigNumberish, Numeric } from "../utils/index.js";
|
||||
|
||||
export interface AuthorizationRequest {
|
||||
address: string | Addressable;
|
||||
nonce?: Numeric;
|
||||
chainId?: BigNumberish;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the [[link-eip-7702]] authorization digest to sign.
|
||||
*/
|
||||
export function hashAuthorization(auth: AuthorizationRequest): string {
|
||||
assertArgument(typeof(auth.address) === "string", "invalid address for hashAuthorization", "auth.address", auth);
|
||||
return keccak256(concat([
|
||||
"0x05", encodeRlp([
|
||||
(auth.chainId != null) ? toBeArray(auth.chainId): "0x",
|
||||
getAddress(auth.address),
|
||||
(auth.nonce != null) ? toBeArray(auth.nonce): "0x",
|
||||
])
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the address of the private key that produced
|
||||
* the signature %%sig%% during signing for %%message%%.
|
||||
*/
|
||||
export function verifyAuthorization(auth: AuthorizationRequest, sig: SignatureLike): string {
|
||||
return recoverAddress(hashAuthorization(auth), sig);
|
||||
}
|
||||
17
dev/env/node_modules/ethers/src.ts/hash/id.ts
generated
vendored
Executable file
17
dev/env/node_modules/ethers/src.ts/hash/id.ts
generated
vendored
Executable file
@@ -0,0 +1,17 @@
|
||||
import { keccak256 } from "../crypto/index.js";
|
||||
import { toUtf8Bytes } from "../utils/index.js";
|
||||
|
||||
/**
|
||||
* A simple hashing function which operates on UTF-8 strings to
|
||||
* compute an 32-byte identifier.
|
||||
*
|
||||
* This simply computes the [UTF-8 bytes](toUtf8Bytes) and computes
|
||||
* the [[keccak256]].
|
||||
*
|
||||
* @example:
|
||||
* id("hello world")
|
||||
* //_result:
|
||||
*/
|
||||
export function id(value: string): string {
|
||||
return keccak256(toUtf8Bytes(value));
|
||||
}
|
||||
18
dev/env/node_modules/ethers/src.ts/hash/index.ts
generated
vendored
Executable file
18
dev/env/node_modules/ethers/src.ts/hash/index.ts
generated
vendored
Executable file
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Utilities for common tasks involving hashing. Also see
|
||||
* [cryptographic hashing](about-crypto-hashing).
|
||||
*
|
||||
* @_section: api/hashing:Hashing Utilities [about-hashing]
|
||||
*/
|
||||
|
||||
export { hashAuthorization, verifyAuthorization } from "./authorization.js";
|
||||
export { id } from "./id.js"
|
||||
export { ensNormalize, isValidName, namehash, dnsEncode } from "./namehash.js";
|
||||
export { hashMessage, verifyMessage } from "./message.js";
|
||||
export {
|
||||
solidityPacked, solidityPackedKeccak256, solidityPackedSha256
|
||||
} from "./solidity.js";
|
||||
export { TypedDataEncoder, verifyTypedData } from "./typed-data.js";
|
||||
|
||||
export type { AuthorizationRequest } from "./authorization.js";
|
||||
export type { TypedDataDomain, TypedDataField } from "./typed-data.js";
|
||||
51
dev/env/node_modules/ethers/src.ts/hash/message.ts
generated
vendored
Executable file
51
dev/env/node_modules/ethers/src.ts/hash/message.ts
generated
vendored
Executable file
@@ -0,0 +1,51 @@
|
||||
import { keccak256 } from "../crypto/index.js";
|
||||
import { MessagePrefix } from "../constants/index.js";
|
||||
import { recoverAddress } from "../transaction/index.js";
|
||||
import { concat, toUtf8Bytes } from "../utils/index.js";
|
||||
|
||||
import type { SignatureLike } from "../crypto/index.js";
|
||||
/**
|
||||
* Computes the [[link-eip-191]] personal-sign message digest to sign.
|
||||
*
|
||||
* This prefixes the message with [[MessagePrefix]] and the decimal length
|
||||
* of %%message%% and computes the [[keccak256]] digest.
|
||||
*
|
||||
* If %%message%% is a string, it is converted to its UTF-8 bytes
|
||||
* first. To compute the digest of a [[DataHexString]], it must be converted
|
||||
* to [bytes](getBytes).
|
||||
*
|
||||
* @example:
|
||||
* hashMessage("Hello World")
|
||||
* //_result:
|
||||
*
|
||||
* // Hashes the SIX (6) string characters, i.e.
|
||||
* // [ "0", "x", "4", "2", "4", "3" ]
|
||||
* hashMessage("0x4243")
|
||||
* //_result:
|
||||
*
|
||||
* // Hashes the TWO (2) bytes [ 0x42, 0x43 ]...
|
||||
* hashMessage(getBytes("0x4243"))
|
||||
* //_result:
|
||||
*
|
||||
* // ...which is equal to using data
|
||||
* hashMessage(new Uint8Array([ 0x42, 0x43 ]))
|
||||
* //_result:
|
||||
*
|
||||
*/
|
||||
export function hashMessage(message: Uint8Array | string): string {
|
||||
if (typeof(message) === "string") { message = toUtf8Bytes(message); }
|
||||
return keccak256(concat([
|
||||
toUtf8Bytes(MessagePrefix),
|
||||
toUtf8Bytes(String(message.length)),
|
||||
message
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the address of the private key that produced
|
||||
* the signature %%sig%% during signing for %%message%%.
|
||||
*/
|
||||
export function verifyMessage(message: Uint8Array | string, sig: SignatureLike): string {
|
||||
const digest = hashMessage(message);
|
||||
return recoverAddress(digest, sig);
|
||||
}
|
||||
101
dev/env/node_modules/ethers/src.ts/hash/namehash.ts
generated
vendored
Executable file
101
dev/env/node_modules/ethers/src.ts/hash/namehash.ts
generated
vendored
Executable file
@@ -0,0 +1,101 @@
|
||||
|
||||
import { keccak256 } from "../crypto/index.js";
|
||||
import {
|
||||
concat, hexlify, assertArgument, toUtf8Bytes
|
||||
} from "../utils/index.js";
|
||||
|
||||
|
||||
import { ens_normalize } from "@adraffy/ens-normalize";
|
||||
|
||||
const Zeros = new Uint8Array(32);
|
||||
Zeros.fill(0);
|
||||
|
||||
function checkComponent(comp: Uint8Array): Uint8Array {
|
||||
assertArgument(comp.length !== 0, "invalid ENS name; empty component", "comp", comp)
|
||||
return comp;
|
||||
}
|
||||
|
||||
function ensNameSplit(name: string): Array<Uint8Array> {
|
||||
const bytes = toUtf8Bytes(ensNormalize(name));
|
||||
const comps: Array<Uint8Array> = [ ];
|
||||
|
||||
if (name.length === 0) { return comps; }
|
||||
|
||||
let last = 0;
|
||||
for (let i = 0; i < bytes.length; i++) {
|
||||
const d = bytes[i];
|
||||
|
||||
// A separator (i.e. "."); copy this component
|
||||
if (d === 0x2e) {
|
||||
comps.push(checkComponent(bytes.slice(last, i)));
|
||||
last = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// There was a stray separator at the end of the name
|
||||
assertArgument(last < bytes.length, "invalid ENS name; empty component", "name", name);
|
||||
|
||||
comps.push(checkComponent(bytes.slice(last)));
|
||||
return comps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ENS %%name%% normalized.
|
||||
*/
|
||||
export function ensNormalize(name: string): string {
|
||||
try {
|
||||
if (name.length === 0) { throw new Error("empty label"); }
|
||||
return ens_normalize(name);
|
||||
} catch (error: any) {
|
||||
assertArgument(false, `invalid ENS name (${ error.message })`, "name", name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ``true`` if %%name%% is a valid ENS name.
|
||||
*/
|
||||
export function isValidName(name: string): name is string {
|
||||
try {
|
||||
return (ensNameSplit(name).length !== 0);
|
||||
} catch (error) { }
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the [[link-namehash]] for %%name%%.
|
||||
*/
|
||||
export function namehash(name: string): string {
|
||||
assertArgument(typeof(name) === "string", "invalid ENS name; not a string", "name", name);
|
||||
|
||||
assertArgument(name.length, `invalid ENS name (empty label)`, "name", name);
|
||||
|
||||
let result: string | Uint8Array = Zeros;
|
||||
|
||||
const comps = ensNameSplit(name);
|
||||
while (comps.length) {
|
||||
result = keccak256(concat([ result, keccak256(<Uint8Array>(comps.pop()))] ));
|
||||
}
|
||||
|
||||
return hexlify(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the DNS encoded %%name%%.
|
||||
*
|
||||
* This is used for various parts of ENS name resolution, such
|
||||
* as the wildcard resolution.
|
||||
*/
|
||||
export function dnsEncode(name: string, _maxLength?: number): string {
|
||||
const length = (_maxLength != null) ? _maxLength: 63;
|
||||
|
||||
assertArgument(length <= 255, "DNS encoded label cannot exceed 255", "length", length);
|
||||
|
||||
return hexlify(concat(ensNameSplit(name).map((comp) => {
|
||||
assertArgument(comp.length <= length, `label ${ JSON.stringify(name) } exceeds ${ length } bytes`, "name", name);
|
||||
|
||||
const bytes = new Uint8Array(comp.length + 1);
|
||||
bytes.set(comp, 1);
|
||||
bytes[0] = bytes.length - 1;
|
||||
return bytes;
|
||||
}))) + "00";
|
||||
}
|
||||
117
dev/env/node_modules/ethers/src.ts/hash/solidity.ts
generated
vendored
Executable file
117
dev/env/node_modules/ethers/src.ts/hash/solidity.ts
generated
vendored
Executable file
@@ -0,0 +1,117 @@
|
||||
import { getAddress } from "../address/index.js";
|
||||
import {
|
||||
keccak256 as _keccak256, sha256 as _sha256
|
||||
} from "../crypto/index.js";
|
||||
import {
|
||||
concat, dataLength, getBytes, hexlify, toBeArray, toTwos, toUtf8Bytes, zeroPadBytes, zeroPadValue,
|
||||
assertArgument
|
||||
} from "../utils/index.js";
|
||||
|
||||
|
||||
const regexBytes = new RegExp("^bytes([0-9]+)$");
|
||||
const regexNumber = new RegExp("^(u?int)([0-9]*)$");
|
||||
const regexArray = new RegExp("^(.*)\\[([0-9]*)\\]$");
|
||||
|
||||
|
||||
function _pack(type: string, value: any, isArray?: boolean): Uint8Array {
|
||||
switch(type) {
|
||||
case "address":
|
||||
if (isArray) { return getBytes(zeroPadValue(value, 32)); }
|
||||
return getBytes(getAddress(value));
|
||||
case "string":
|
||||
return toUtf8Bytes(value);
|
||||
case "bytes":
|
||||
return getBytes(value);
|
||||
case "bool":
|
||||
value = (!!value ? "0x01": "0x00");
|
||||
if (isArray) { return getBytes(zeroPadValue(value, 32)); }
|
||||
return getBytes(value);
|
||||
}
|
||||
|
||||
let match = type.match(regexNumber);
|
||||
if (match) {
|
||||
let signed = (match[1] === "int");
|
||||
let size = parseInt(match[2] || "256")
|
||||
|
||||
assertArgument((!match[2] || match[2] === String(size)) && (size % 8 === 0) && size !== 0 && size <= 256, "invalid number type", "type", type);
|
||||
|
||||
if (isArray) { size = 256; }
|
||||
|
||||
if (signed) { value = toTwos(value, size); }
|
||||
|
||||
return getBytes(zeroPadValue(toBeArray(value), size / 8));
|
||||
}
|
||||
|
||||
match = type.match(regexBytes);
|
||||
if (match) {
|
||||
const size = parseInt(match[1]);
|
||||
|
||||
assertArgument(String(size) === match[1] && size !== 0 && size <= 32, "invalid bytes type", "type", type);
|
||||
assertArgument(dataLength(value) === size, `invalid value for ${ type }`, "value", value);
|
||||
|
||||
if (isArray) { return getBytes(zeroPadBytes(value, 32)); }
|
||||
return value;
|
||||
}
|
||||
|
||||
match = type.match(regexArray);
|
||||
if (match && Array.isArray(value)) {
|
||||
const baseType = match[1];
|
||||
const count = parseInt(match[2] || String(value.length));
|
||||
assertArgument(count === value.length, `invalid array length for ${ type }`, "value", value);
|
||||
|
||||
const result: Array<Uint8Array> = [];
|
||||
value.forEach(function(value) {
|
||||
result.push(_pack(baseType, value, true));
|
||||
});
|
||||
return getBytes(concat(result));
|
||||
}
|
||||
|
||||
assertArgument(false, "invalid type", "type", type)
|
||||
}
|
||||
|
||||
// @TODO: Array Enum
|
||||
|
||||
/**
|
||||
* Computes the [[link-solc-packed]] representation of %%values%%
|
||||
* respectively to their %%types%%.
|
||||
*
|
||||
* @example:
|
||||
* addr = "0x8ba1f109551bd432803012645ac136ddd64dba72"
|
||||
* solidityPacked([ "address", "uint" ], [ addr, 45 ]);
|
||||
* //_result:
|
||||
*/
|
||||
export function solidityPacked(types: ReadonlyArray<string>, values: ReadonlyArray<any>): string {
|
||||
assertArgument(types.length === values.length, "wrong number of values; expected ${ types.length }", "values", values);
|
||||
|
||||
const tight: Array<Uint8Array> = [];
|
||||
types.forEach(function(type, index) {
|
||||
tight.push(_pack(type, values[index]));
|
||||
});
|
||||
return hexlify(concat(tight));
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the [[link-solc-packed]] [[keccak256]] hash of %%values%%
|
||||
* respectively to their %%types%%.
|
||||
*
|
||||
* @example:
|
||||
* addr = "0x8ba1f109551bd432803012645ac136ddd64dba72"
|
||||
* solidityPackedKeccak256([ "address", "uint" ], [ addr, 45 ]);
|
||||
* //_result:
|
||||
*/
|
||||
export function solidityPackedKeccak256(types: ReadonlyArray<string>, values: ReadonlyArray<any>): string {
|
||||
return _keccak256(solidityPacked(types, values));
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the [[link-solc-packed]] [[sha256]] hash of %%values%%
|
||||
* respectively to their %%types%%.
|
||||
*
|
||||
* @example:
|
||||
* addr = "0x8ba1f109551bd432803012645ac136ddd64dba72"
|
||||
* solidityPackedSha256([ "address", "uint" ], [ addr, 45 ]);
|
||||
* //_result:
|
||||
*/
|
||||
export function solidityPackedSha256(types: ReadonlyArray<string>, values: ReadonlyArray<any>): string {
|
||||
return _sha256(solidityPacked(types, values));
|
||||
}
|
||||
658
dev/env/node_modules/ethers/src.ts/hash/typed-data.ts
generated
vendored
Executable file
658
dev/env/node_modules/ethers/src.ts/hash/typed-data.ts
generated
vendored
Executable file
@@ -0,0 +1,658 @@
|
||||
//import { TypedDataDomain, TypedDataField } from "@ethersproject/providerabstract-signer";
|
||||
import { getAddress } from "../address/index.js";
|
||||
import { keccak256 } from "../crypto/index.js";
|
||||
import { recoverAddress } from "../transaction/index.js";
|
||||
import {
|
||||
concat, defineProperties, getBigInt, getBytes, hexlify, isHexString, mask, toBeHex, toQuantity, toTwos, zeroPadValue,
|
||||
assertArgument
|
||||
} from "../utils/index.js";
|
||||
|
||||
import { id } from "./id.js";
|
||||
|
||||
import type { SignatureLike } from "../crypto/index.js";
|
||||
import type { BigNumberish, BytesLike } from "../utils/index.js";
|
||||
|
||||
|
||||
const padding = new Uint8Array(32);
|
||||
padding.fill(0);
|
||||
|
||||
const BN__1 = BigInt(-1);
|
||||
const BN_0 = BigInt(0);
|
||||
const BN_1 = BigInt(1);
|
||||
const BN_MAX_UINT256 = BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
|
||||
|
||||
// @TODO: in v7, verifyingContract should be an AddressLike and use resolveAddress
|
||||
|
||||
/**
|
||||
* The domain for an [[link-eip-712]] payload.
|
||||
*/
|
||||
export interface TypedDataDomain {
|
||||
/**
|
||||
* The human-readable name of the signing domain.
|
||||
*/
|
||||
name?: null | string;
|
||||
|
||||
/**
|
||||
* The major version of the signing domain.
|
||||
*/
|
||||
version?: null | string;
|
||||
|
||||
/**
|
||||
* The chain ID of the signing domain.
|
||||
*/
|
||||
chainId?: null | BigNumberish;
|
||||
|
||||
/**
|
||||
* The the address of the contract that will verify the signature.
|
||||
*/
|
||||
verifyingContract?: null | string;
|
||||
|
||||
/**
|
||||
* A salt used for purposes decided by the specific domain.
|
||||
*/
|
||||
salt?: null | BytesLike;
|
||||
};
|
||||
|
||||
/**
|
||||
* A specific field of a structured [[link-eip-712]] type.
|
||||
*/
|
||||
export interface TypedDataField {
|
||||
/**
|
||||
* The field name.
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* The type of the field.
|
||||
*/
|
||||
type: string;
|
||||
};
|
||||
|
||||
function hexPadRight(value: BytesLike): string {
|
||||
const bytes = getBytes(value);
|
||||
const padOffset = bytes.length % 32
|
||||
if (padOffset) {
|
||||
return concat([ bytes, padding.slice(padOffset) ]);
|
||||
}
|
||||
return hexlify(bytes);
|
||||
}
|
||||
|
||||
const hexTrue = toBeHex(BN_1, 32);
|
||||
const hexFalse = toBeHex(BN_0, 32);
|
||||
|
||||
const domainFieldTypes: Record<string, string> = {
|
||||
name: "string",
|
||||
version: "string",
|
||||
chainId: "uint256",
|
||||
verifyingContract: "address",
|
||||
salt: "bytes32"
|
||||
};
|
||||
|
||||
const domainFieldNames: Array<string> = [
|
||||
"name", "version", "chainId", "verifyingContract", "salt"
|
||||
];
|
||||
|
||||
function checkString(key: string): (value: any) => string {
|
||||
return function (value: any){
|
||||
assertArgument(typeof(value) === "string", `invalid domain value for ${ JSON.stringify(key) }`, `domain.${ key }`, value);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
const domainChecks: Record<string, (value: any) => any> = {
|
||||
name: checkString("name"),
|
||||
version: checkString("version"),
|
||||
chainId: function(_value: any) {
|
||||
const value = getBigInt(_value, "domain.chainId");
|
||||
assertArgument(value >= 0, "invalid chain ID", "domain.chainId", _value);
|
||||
if (Number.isSafeInteger(value)) { return Number(value); }
|
||||
return toQuantity(value);
|
||||
},
|
||||
verifyingContract: function(value: any) {
|
||||
try {
|
||||
return getAddress(value).toLowerCase();
|
||||
} catch (error) { }
|
||||
assertArgument(false, `invalid domain value "verifyingContract"`, "domain.verifyingContract", value);
|
||||
},
|
||||
salt: function(value: any) {
|
||||
const bytes = getBytes(value, "domain.salt");
|
||||
assertArgument(bytes.length === 32, `invalid domain value "salt"`, "domain.salt", value);
|
||||
return hexlify(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
function getBaseEncoder(type: string): null | ((value: any) => string) {
|
||||
// intXX and uintXX
|
||||
{
|
||||
const match = type.match(/^(u?)int(\d+)$/);
|
||||
if (match) {
|
||||
const signed = (match[1] === "");
|
||||
|
||||
const width = parseInt(match[2]);
|
||||
assertArgument(width % 8 === 0 && width !== 0 && width <= 256 && match[2] === String(width), "invalid numeric width", "type", type);
|
||||
|
||||
const boundsUpper = mask(BN_MAX_UINT256, signed ? (width - 1): width);
|
||||
const boundsLower = signed ? ((boundsUpper + BN_1) * BN__1): BN_0;
|
||||
|
||||
return function(_value: BigNumberish) {
|
||||
const value = getBigInt(_value, "value");
|
||||
|
||||
assertArgument(value >= boundsLower && value <= boundsUpper, `value out-of-bounds for ${ type }`, "value", value);
|
||||
|
||||
return toBeHex(signed ? toTwos(value, 256): value, 32);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// bytesXX
|
||||
{
|
||||
const match = type.match(/^bytes(\d+)$/);
|
||||
if (match) {
|
||||
const width = parseInt(match[1]);
|
||||
assertArgument(width !== 0 && width <= 32 && match[1] === String(width), "invalid bytes width", "type", type);
|
||||
|
||||
return function(value: BytesLike) {
|
||||
const bytes = getBytes(value);
|
||||
assertArgument(bytes.length === width, `invalid length for ${ type }`, "value", value);
|
||||
return hexPadRight(value);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case "address": return function(value: string) {
|
||||
return zeroPadValue(getAddress(value), 32);
|
||||
};
|
||||
case "bool": return function(value: boolean) {
|
||||
return ((!value) ? hexFalse: hexTrue);
|
||||
};
|
||||
case "bytes": return function(value: BytesLike) {
|
||||
return keccak256(value);
|
||||
};
|
||||
case "string": return function(value: string) {
|
||||
return id(value);
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function encodeType(name: string, fields: Array<TypedDataField>): string {
|
||||
return `${ name }(${ fields.map(({ name, type }) => (type + " " + name)).join(",") })`;
|
||||
}
|
||||
|
||||
type ArrayResult = {
|
||||
base: string; // The base type
|
||||
index?: string; // the full Index (if any)
|
||||
array?: { // The Array... (if index)
|
||||
base: string; // ...base type (same as above)
|
||||
prefix: string; // ...sans the final Index
|
||||
count: number; // ...the final Index (-1 for dynamic)
|
||||
}
|
||||
};
|
||||
|
||||
// foo[][3] => { base: "foo", index: "[][3]", array: {
|
||||
// base: "foo", prefix: "foo[]", count: 3 } }
|
||||
function splitArray(type: string): ArrayResult {
|
||||
const match = type.match(/^([^\x5b]*)((\x5b\d*\x5d)*)(\x5b(\d*)\x5d)$/);
|
||||
if (match) {
|
||||
return {
|
||||
base: match[1],
|
||||
index: (match[2] + match[4]),
|
||||
array: {
|
||||
base: match[1],
|
||||
prefix: (match[1] + match[2]),
|
||||
count: (match[5] ? parseInt(match[5]): -1),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return { base: type };
|
||||
}
|
||||
|
||||
/**
|
||||
* A **TypedDataEncode** prepares and encodes [[link-eip-712]] payloads
|
||||
* for signed typed data.
|
||||
*
|
||||
* This is useful for those that wish to compute various components of a
|
||||
* typed data hash, primary types, or sub-components, but generally the
|
||||
* higher level [[Signer-signTypedData]] is more useful.
|
||||
*/
|
||||
export class TypedDataEncoder {
|
||||
/**
|
||||
* The primary type for the structured [[types]].
|
||||
*
|
||||
* This is derived automatically from the [[types]], since no
|
||||
* recursion is possible, once the DAG for the types is consturcted
|
||||
* internally, the primary type must be the only remaining type with
|
||||
* no parent nodes.
|
||||
*/
|
||||
readonly primaryType!: string;
|
||||
|
||||
readonly #types: string;
|
||||
|
||||
/**
|
||||
* The types.
|
||||
*/
|
||||
get types(): Record<string, Array<TypedDataField>> {
|
||||
return JSON.parse(this.#types);
|
||||
}
|
||||
|
||||
readonly #fullTypes: Map<string, string>
|
||||
|
||||
readonly #encoderCache: Map<string, (value: any) => string>;
|
||||
|
||||
/**
|
||||
* Create a new **TypedDataEncoder** for %%types%%.
|
||||
*
|
||||
* This performs all necessary checking that types are valid and
|
||||
* do not violate the [[link-eip-712]] structural constraints as
|
||||
* well as computes the [[primaryType]].
|
||||
*/
|
||||
constructor(_types: Record<string, Array<TypedDataField>>) {
|
||||
this.#fullTypes = new Map();
|
||||
this.#encoderCache = new Map();
|
||||
|
||||
// Link struct types to their direct child structs
|
||||
const links: Map<string, Set<string>> = new Map();
|
||||
|
||||
// Link structs to structs which contain them as a child
|
||||
const parents: Map<string, Array<string>> = new Map();
|
||||
|
||||
// Link all subtypes within a given struct
|
||||
const subtypes: Map<string, Set<string>> = new Map();
|
||||
|
||||
const types: Record<string, Array<TypedDataField>> = { };
|
||||
Object.keys(_types).forEach((type) => {
|
||||
types[type] = _types[type].map(({ name, type }) => {
|
||||
|
||||
// Normalize the base type (unless name conflict)
|
||||
let { base, index } = splitArray(type);
|
||||
if (base === "int" && !_types["int"]) { base = "int256"; }
|
||||
if (base === "uint" && !_types["uint"]) { base = "uint256"; }
|
||||
|
||||
return { name, type: (base + (index || "")) };
|
||||
});
|
||||
|
||||
links.set(type, new Set());
|
||||
parents.set(type, [ ]);
|
||||
subtypes.set(type, new Set());
|
||||
});
|
||||
this.#types = JSON.stringify(types);
|
||||
|
||||
for (const name in types) {
|
||||
const uniqueNames: Set<string> = new Set();
|
||||
|
||||
for (const field of types[name]) {
|
||||
|
||||
// Check each field has a unique name
|
||||
assertArgument(!uniqueNames.has(field.name), `duplicate variable name ${ JSON.stringify(field.name) } in ${ JSON.stringify(name) }`, "types", _types);
|
||||
uniqueNames.add(field.name);
|
||||
|
||||
// Get the base type (drop any array specifiers)
|
||||
const baseType = splitArray(field.type).base;
|
||||
assertArgument(baseType !== name, `circular type reference to ${ JSON.stringify(baseType) }`, "types", _types);
|
||||
|
||||
// Is this a base encoding type?
|
||||
const encoder = getBaseEncoder(baseType);
|
||||
if (encoder) { continue; }
|
||||
|
||||
assertArgument(parents.has(baseType), `unknown type ${ JSON.stringify(baseType) }`, "types", _types);
|
||||
|
||||
// Add linkage
|
||||
(parents.get(baseType) as Array<string>).push(name);
|
||||
(links.get(name) as Set<string>).add(baseType);
|
||||
}
|
||||
}
|
||||
|
||||
// Deduce the primary type
|
||||
const primaryTypes = Array.from(parents.keys()).filter((n) => ((parents.get(n) as Array<string>).length === 0));
|
||||
assertArgument(primaryTypes.length !== 0, "missing primary type", "types", _types);
|
||||
assertArgument(primaryTypes.length === 1, `ambiguous primary types or unused types: ${ primaryTypes.map((t) => (JSON.stringify(t))).join(", ") }`, "types", _types);
|
||||
|
||||
defineProperties<TypedDataEncoder>(this, { primaryType: primaryTypes[0] });
|
||||
|
||||
// Check for circular type references
|
||||
function checkCircular(type: string, found: Set<string>) {
|
||||
assertArgument(!found.has(type), `circular type reference to ${ JSON.stringify(type) }`, "types", _types);
|
||||
|
||||
found.add(type);
|
||||
|
||||
for (const child of (links.get(type) as Set<string>)) {
|
||||
if (!parents.has(child)) { continue; }
|
||||
|
||||
// Recursively check children
|
||||
checkCircular(child, found);
|
||||
|
||||
// Mark all ancestors as having this decendant
|
||||
for (const subtype of found) {
|
||||
(subtypes.get(subtype) as Set<string>).add(child);
|
||||
}
|
||||
}
|
||||
|
||||
found.delete(type);
|
||||
}
|
||||
checkCircular(this.primaryType, new Set());
|
||||
|
||||
// Compute each fully describe type
|
||||
for (const [ name, set ] of subtypes) {
|
||||
const st = Array.from(set);
|
||||
st.sort();
|
||||
this.#fullTypes.set(name, encodeType(name, types[name]) + st.map((t) => encodeType(t, types[t])).join(""));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returnthe encoder for the specific %%type%%.
|
||||
*/
|
||||
getEncoder(type: string): (value: any) => string {
|
||||
let encoder = this.#encoderCache.get(type);
|
||||
if (!encoder) {
|
||||
encoder = this.#getEncoder(type);
|
||||
this.#encoderCache.set(type, encoder);
|
||||
}
|
||||
return encoder;
|
||||
}
|
||||
|
||||
#getEncoder(type: string): (value: any) => string {
|
||||
|
||||
// Basic encoder type (address, bool, uint256, etc)
|
||||
{
|
||||
const encoder = getBaseEncoder(type);
|
||||
if (encoder) { return encoder; }
|
||||
}
|
||||
|
||||
// Array
|
||||
const array = splitArray(type).array;
|
||||
if (array) {
|
||||
const subtype = array.prefix;
|
||||
const subEncoder = this.getEncoder(subtype);
|
||||
return (value: Array<any>) => {
|
||||
assertArgument(array.count === -1 || array.count === value.length, `array length mismatch; expected length ${ array.count }`, "value", value);
|
||||
|
||||
let result = value.map(subEncoder);
|
||||
if (this.#fullTypes.has(subtype)) {
|
||||
result = result.map(keccak256);
|
||||
}
|
||||
|
||||
return keccak256(concat(result));
|
||||
};
|
||||
}
|
||||
|
||||
// Struct
|
||||
const fields = this.types[type];
|
||||
if (fields) {
|
||||
const encodedType = id(this.#fullTypes.get(type) as string);
|
||||
return (value: Record<string, any>) => {
|
||||
const values = fields.map(({ name, type }) => {
|
||||
const result = this.getEncoder(type)(value[name]);
|
||||
if (this.#fullTypes.has(type)) { return keccak256(result); }
|
||||
return result;
|
||||
});
|
||||
values.unshift(encodedType);
|
||||
return concat(values);
|
||||
}
|
||||
}
|
||||
|
||||
assertArgument(false, `unknown type: ${ type }`, "type", type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the full type for %%name%%.
|
||||
*/
|
||||
encodeType(name: string): string {
|
||||
const result = this.#fullTypes.get(name);
|
||||
assertArgument(result, `unknown type: ${ JSON.stringify(name) }`, "name", name);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the encoded %%value%% for the %%type%%.
|
||||
*/
|
||||
encodeData(type: string, value: any): string {
|
||||
return this.getEncoder(type)(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hash of %%value%% for the type of %%name%%.
|
||||
*/
|
||||
hashStruct(name: string, value: Record<string, any>): string {
|
||||
return keccak256(this.encodeData(name, value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the fulled encoded %%value%% for the [[types]].
|
||||
*/
|
||||
encode(value: Record<string, any>): string {
|
||||
return this.encodeData(this.primaryType, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hash of the fully encoded %%value%% for the [[types]].
|
||||
*/
|
||||
hash(value: Record<string, any>): string {
|
||||
return this.hashStruct(this.primaryType, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
_visit(type: string, value: any, callback: (type: string, data: any) => any): any {
|
||||
// Basic encoder type (address, bool, uint256, etc)
|
||||
{
|
||||
const encoder = getBaseEncoder(type);
|
||||
if (encoder) { return callback(type, value); }
|
||||
}
|
||||
|
||||
// Array
|
||||
const array = splitArray(type).array;
|
||||
if (array) {
|
||||
assertArgument(array.count === -1 || array.count === value.length, `array length mismatch; expected length ${ array.count }`, "value", value);
|
||||
return value.map((v: any) => this._visit(array.prefix, v, callback));
|
||||
}
|
||||
|
||||
// Struct
|
||||
const fields = this.types[type];
|
||||
if (fields) {
|
||||
return fields.reduce((accum, { name, type }) => {
|
||||
accum[name] = this._visit(type, value[name], callback);
|
||||
return accum;
|
||||
}, <Record<string, any>>{});
|
||||
}
|
||||
|
||||
assertArgument(false, `unknown type: ${ type }`, "type", type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call %%calback%% for each value in %%value%%, passing the type and
|
||||
* component within %%value%%.
|
||||
*
|
||||
* This is useful for replacing addresses or other transformation that
|
||||
* may be desired on each component, based on its type.
|
||||
*/
|
||||
visit(value: Record<string, any>, callback: (type: string, data: any) => any): any {
|
||||
return this._visit(this.primaryType, value, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new **TypedDataEncoder** for %%types%%.
|
||||
*/
|
||||
static from(types: Record<string, Array<TypedDataField>>): TypedDataEncoder {
|
||||
return new TypedDataEncoder(types);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the primary type for %%types%%.
|
||||
*/
|
||||
static getPrimaryType(types: Record<string, Array<TypedDataField>>): string {
|
||||
return TypedDataEncoder.from(types).primaryType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hashed struct for %%value%% using %%types%% and %%name%%.
|
||||
*/
|
||||
static hashStruct(name: string, types: Record<string, Array<TypedDataField>>, value: Record<string, any>): string {
|
||||
return TypedDataEncoder.from(types).hashStruct(name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the domain hash for %%domain%%.
|
||||
*/
|
||||
static hashDomain(domain: TypedDataDomain): string {
|
||||
const domainFields: Array<TypedDataField> = [ ];
|
||||
for (const name in domain) {
|
||||
if ((<Record<string, any>>domain)[name] == null) { continue; }
|
||||
const type = domainFieldTypes[name];
|
||||
assertArgument(type, `invalid typed-data domain key: ${ JSON.stringify(name) }`, "domain", domain);
|
||||
domainFields.push({ name, type });
|
||||
}
|
||||
|
||||
domainFields.sort((a, b) => {
|
||||
return domainFieldNames.indexOf(a.name) - domainFieldNames.indexOf(b.name);
|
||||
});
|
||||
|
||||
return TypedDataEncoder.hashStruct("EIP712Domain", { EIP712Domain: domainFields }, domain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the fully encoded [[link-eip-712]] %%value%% for %%types%% with %%domain%%.
|
||||
*/
|
||||
static encode(domain: TypedDataDomain, types: Record<string, Array<TypedDataField>>, value: Record<string, any>): string {
|
||||
return concat([
|
||||
"0x1901",
|
||||
TypedDataEncoder.hashDomain(domain),
|
||||
TypedDataEncoder.from(types).hash(value)
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hash of the fully encoded [[link-eip-712]] %%value%% for %%types%% with %%domain%%.
|
||||
*/
|
||||
static hash(domain: TypedDataDomain, types: Record<string, Array<TypedDataField>>, value: Record<string, any>): string {
|
||||
return keccak256(TypedDataEncoder.encode(domain, types, value));
|
||||
}
|
||||
|
||||
// Replaces all address types with ENS names with their looked up address
|
||||
/**
|
||||
* Resolves to the value from resolving all addresses in %%value%% for
|
||||
* %%types%% and the %%domain%%.
|
||||
*/
|
||||
static async resolveNames(domain: TypedDataDomain, types: Record<string, Array<TypedDataField>>, value: Record<string, any>, resolveName: (name: string) => Promise<string>): Promise<{ domain: TypedDataDomain, value: any }> {
|
||||
// Make a copy to isolate it from the object passed in
|
||||
domain = Object.assign({ }, domain);
|
||||
|
||||
// Allow passing null to ignore value
|
||||
for (const key in domain) {
|
||||
if ((<Record<string, any>>domain)[key] == null) {
|
||||
delete (<Record<string, any>>domain)[key];
|
||||
}
|
||||
}
|
||||
|
||||
// Look up all ENS names
|
||||
const ensCache: Record<string, string> = { };
|
||||
|
||||
// Do we need to look up the domain's verifyingContract?
|
||||
if (domain.verifyingContract && !isHexString(domain.verifyingContract, 20)) {
|
||||
ensCache[domain.verifyingContract] = "0x";
|
||||
}
|
||||
|
||||
// We are going to use the encoder to visit all the base values
|
||||
const encoder = TypedDataEncoder.from(types);
|
||||
|
||||
// Get a list of all the addresses
|
||||
encoder.visit(value, (type: string, value: any) => {
|
||||
if (type === "address" && !isHexString(value, 20)) {
|
||||
ensCache[value] = "0x";
|
||||
}
|
||||
return value;
|
||||
});
|
||||
|
||||
// Lookup each name
|
||||
for (const name in ensCache) {
|
||||
ensCache[name] = await resolveName(name);
|
||||
}
|
||||
|
||||
// Replace the domain verifyingContract if needed
|
||||
if (domain.verifyingContract && ensCache[domain.verifyingContract]) {
|
||||
domain.verifyingContract = ensCache[domain.verifyingContract];
|
||||
}
|
||||
|
||||
// Replace all ENS names with their address
|
||||
value = encoder.visit(value, (type: string, value: any) => {
|
||||
if (type === "address" && ensCache[value]) { return ensCache[value]; }
|
||||
return value;
|
||||
});
|
||||
|
||||
return { domain, value };
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the JSON-encoded payload expected by nodes which implement
|
||||
* the JSON-RPC [[link-eip-712]] method.
|
||||
*/
|
||||
static getPayload(domain: TypedDataDomain, types: Record<string, Array<TypedDataField>>, value: Record<string, any>): any {
|
||||
// Validate the domain fields
|
||||
TypedDataEncoder.hashDomain(domain);
|
||||
|
||||
// Derive the EIP712Domain Struct reference type
|
||||
const domainValues: Record<string, any> = { };
|
||||
const domainTypes: Array<{ name: string, type:string }> = [ ];
|
||||
|
||||
domainFieldNames.forEach((name) => {
|
||||
const value = (<any>domain)[name];
|
||||
if (value == null) { return; }
|
||||
domainValues[name] = domainChecks[name](value);
|
||||
domainTypes.push({ name, type: domainFieldTypes[name] });
|
||||
});
|
||||
|
||||
const encoder = TypedDataEncoder.from(types);
|
||||
|
||||
// Get the normalized types
|
||||
types = encoder.types;
|
||||
|
||||
const typesWithDomain = Object.assign({ }, types);
|
||||
assertArgument(typesWithDomain.EIP712Domain == null, "types must not contain EIP712Domain type", "types.EIP712Domain", types);
|
||||
|
||||
typesWithDomain.EIP712Domain = domainTypes;
|
||||
|
||||
// Validate the data structures and types
|
||||
encoder.encode(value);
|
||||
|
||||
return {
|
||||
types: typesWithDomain,
|
||||
domain: domainValues,
|
||||
primaryType: encoder.primaryType,
|
||||
message: encoder.visit(value, (type: string, value: any) => {
|
||||
|
||||
// bytes
|
||||
if (type.match(/^bytes(\d*)/)) {
|
||||
return hexlify(getBytes(value));
|
||||
}
|
||||
|
||||
// uint or int
|
||||
if (type.match(/^u?int/)) {
|
||||
return getBigInt(value).toString();
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case "address":
|
||||
return value.toLowerCase();
|
||||
case "bool":
|
||||
return !!value;
|
||||
case "string":
|
||||
assertArgument(typeof(value) === "string", "invalid string", "value", value);
|
||||
return value;
|
||||
}
|
||||
|
||||
assertArgument(false, "unsupported type", "type", type);
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the address used to sign the typed data for the %%signature%%.
|
||||
*/
|
||||
export function verifyTypedData(domain: TypedDataDomain, types: Record<string, Array<TypedDataField>>, value: Record<string, any>, signature: SignatureLike): string {
|
||||
return recoverAddress(TypedDataEncoder.hash(domain, types, value), signature);
|
||||
}
|
||||
12
dev/env/node_modules/ethers/src.ts/index.ts
generated
vendored
Executable file
12
dev/env/node_modules/ethers/src.ts/index.ts
generated
vendored
Executable file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* The Application Programming Interface (API) is the collection of
|
||||
* functions, classes and types offered by the Ethers library.
|
||||
*
|
||||
* @_section: api:Application Programming Interface [about-api]
|
||||
* @_navTitle: API
|
||||
*/
|
||||
import * as ethers from "./ethers.js";
|
||||
|
||||
export { ethers };
|
||||
|
||||
export * from "./ethers.js";
|
||||
1761
dev/env/node_modules/ethers/src.ts/providers/abstract-provider.ts
generated
vendored
Executable file
1761
dev/env/node_modules/ethers/src.ts/providers/abstract-provider.ts
generated
vendored
Executable file
File diff suppressed because it is too large
Load Diff
314
dev/env/node_modules/ethers/src.ts/providers/abstract-signer.ts
generated
vendored
Executable file
314
dev/env/node_modules/ethers/src.ts/providers/abstract-signer.ts
generated
vendored
Executable file
@@ -0,0 +1,314 @@
|
||||
/**
|
||||
* Generally the [[Wallet]] and [[JsonRpcSigner]] and their sub-classes
|
||||
* are sufficient for most developers, but this is provided to
|
||||
* fascilitate more complex Signers.
|
||||
*
|
||||
* @_section: api/providers/abstract-signer: Subclassing Signer [abstract-signer]
|
||||
*/
|
||||
import { resolveAddress } from "../address/index.js";
|
||||
import { Transaction } from "../transaction/index.js";
|
||||
import {
|
||||
defineProperties, getBigInt, resolveProperties,
|
||||
assert, assertArgument
|
||||
} from "../utils/index.js";
|
||||
|
||||
import { copyRequest } from "./provider.js";
|
||||
|
||||
import type {
|
||||
AuthorizationRequest, TypedDataDomain, TypedDataField
|
||||
} from "../hash/index.js";
|
||||
import type { Authorization, TransactionLike } from "../transaction/index.js";
|
||||
|
||||
import type {
|
||||
BlockTag, Provider, TransactionRequest, TransactionResponse
|
||||
} from "./provider.js";
|
||||
import type { Signer } from "./signer.js";
|
||||
|
||||
function checkProvider(signer: AbstractSigner, operation: string): Provider {
|
||||
if (signer.provider) { return signer.provider; }
|
||||
assert(false, "missing provider", "UNSUPPORTED_OPERATION", { operation });
|
||||
}
|
||||
|
||||
async function populate(signer: AbstractSigner, tx: TransactionRequest): Promise<TransactionLike<string>> {
|
||||
let pop: any = copyRequest(tx);
|
||||
|
||||
if (pop.to != null) { pop.to = resolveAddress(pop.to, signer); }
|
||||
|
||||
if (pop.from != null) {
|
||||
const from = pop.from;
|
||||
pop.from = Promise.all([
|
||||
signer.getAddress(),
|
||||
resolveAddress(from, signer)
|
||||
]).then(([ address, from ]) => {
|
||||
assertArgument(address.toLowerCase() === from.toLowerCase(),
|
||||
"transaction from mismatch", "tx.from", from);
|
||||
return address;
|
||||
});
|
||||
} else {
|
||||
pop.from = signer.getAddress();
|
||||
}
|
||||
|
||||
return await resolveProperties(pop);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* An **AbstractSigner** includes most of teh functionality required
|
||||
* to get a [[Signer]] working as expected, but requires a few
|
||||
* Signer-specific methods be overridden.
|
||||
*
|
||||
*/
|
||||
export abstract class AbstractSigner<P extends null | Provider = null | Provider> implements Signer {
|
||||
/**
|
||||
* The provider this signer is connected to.
|
||||
*/
|
||||
readonly provider!: P;
|
||||
|
||||
/**
|
||||
* Creates a new Signer connected to %%provider%%.
|
||||
*/
|
||||
constructor(provider?: P) {
|
||||
defineProperties<AbstractSigner>(this, { provider: (provider || null) });
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to the Signer address.
|
||||
*/
|
||||
abstract getAddress(): Promise<string>;
|
||||
|
||||
/**
|
||||
* Returns the signer connected to %%provider%%.
|
||||
*
|
||||
* This may throw, for example, a Signer connected over a Socket or
|
||||
* to a specific instance of a node may not be transferrable.
|
||||
*/
|
||||
abstract connect(provider: null | Provider): Signer;
|
||||
|
||||
async getNonce(blockTag?: BlockTag): Promise<number> {
|
||||
return checkProvider(this, "getTransactionCount").getTransactionCount(await this.getAddress(), blockTag);
|
||||
}
|
||||
|
||||
async populateCall(tx: TransactionRequest): Promise<TransactionLike<string>> {
|
||||
const pop = await populate(this, tx);
|
||||
return pop;
|
||||
}
|
||||
|
||||
async populateTransaction(tx: TransactionRequest): Promise<TransactionLike<string>> {
|
||||
const provider = checkProvider(this, "populateTransaction");
|
||||
|
||||
const pop = await populate(this, tx);
|
||||
|
||||
if (pop.nonce == null) {
|
||||
pop.nonce = await this.getNonce("pending");
|
||||
}
|
||||
|
||||
if (pop.gasLimit == null) {
|
||||
pop.gasLimit = await this.estimateGas(pop);
|
||||
}
|
||||
|
||||
// Populate the chain ID
|
||||
const network = await (<Provider>(this.provider)).getNetwork();
|
||||
if (pop.chainId != null) {
|
||||
const chainId = getBigInt(pop.chainId);
|
||||
assertArgument(chainId === network.chainId, "transaction chainId mismatch", "tx.chainId", tx.chainId);
|
||||
} else {
|
||||
pop.chainId = network.chainId;
|
||||
}
|
||||
|
||||
// Do not allow mixing pre-eip-1559 and eip-1559 properties
|
||||
const hasEip1559 = (pop.maxFeePerGas != null || pop.maxPriorityFeePerGas != null);
|
||||
if (pop.gasPrice != null && (pop.type === 2 || hasEip1559)) {
|
||||
assertArgument(false, "eip-1559 transaction do not support gasPrice", "tx", tx);
|
||||
} else if ((pop.type === 0 || pop.type === 1) && hasEip1559) {
|
||||
assertArgument(false, "pre-eip-1559 transaction do not support maxFeePerGas/maxPriorityFeePerGas", "tx", tx);
|
||||
}
|
||||
|
||||
if ((pop.type === 2 || pop.type == null) && (pop.maxFeePerGas != null && pop.maxPriorityFeePerGas != null)) {
|
||||
// Fully-formed EIP-1559 transaction (skip getFeeData)
|
||||
pop.type = 2;
|
||||
|
||||
} else if (pop.type === 0 || pop.type === 1) {
|
||||
// Explicit Legacy or EIP-2930 transaction
|
||||
|
||||
// We need to get fee data to determine things
|
||||
const feeData = await provider.getFeeData();
|
||||
|
||||
assert(feeData.gasPrice != null, "network does not support gasPrice", "UNSUPPORTED_OPERATION", {
|
||||
operation: "getGasPrice" });
|
||||
|
||||
// Populate missing gasPrice
|
||||
if (pop.gasPrice == null) { pop.gasPrice = feeData.gasPrice; }
|
||||
|
||||
} else {
|
||||
|
||||
// We need to get fee data to determine things
|
||||
const feeData = await provider.getFeeData();
|
||||
|
||||
if (pop.type == null) {
|
||||
// We need to auto-detect the intended type of this transaction...
|
||||
|
||||
if (feeData.maxFeePerGas != null && feeData.maxPriorityFeePerGas != null) {
|
||||
// The network supports EIP-1559!
|
||||
|
||||
// Upgrade transaction from null to eip-1559
|
||||
if (pop.authorizationList && pop.authorizationList.length) {
|
||||
pop.type = 4;
|
||||
} else {
|
||||
pop.type = 2;
|
||||
}
|
||||
|
||||
if (pop.gasPrice != null) {
|
||||
// Using legacy gasPrice property on an eip-1559 network,
|
||||
// so use gasPrice as both fee properties
|
||||
const gasPrice = pop.gasPrice;
|
||||
delete pop.gasPrice;
|
||||
pop.maxFeePerGas = gasPrice;
|
||||
pop.maxPriorityFeePerGas = gasPrice;
|
||||
|
||||
} else {
|
||||
// Populate missing fee data
|
||||
|
||||
if (pop.maxFeePerGas == null) {
|
||||
pop.maxFeePerGas = feeData.maxFeePerGas;
|
||||
}
|
||||
|
||||
if (pop.maxPriorityFeePerGas == null) {
|
||||
pop.maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (feeData.gasPrice != null) {
|
||||
// Network doesn't support EIP-1559...
|
||||
|
||||
// ...but they are trying to use EIP-1559 properties
|
||||
assert(!hasEip1559, "network does not support EIP-1559", "UNSUPPORTED_OPERATION", {
|
||||
operation: "populateTransaction" });
|
||||
|
||||
// Populate missing fee data
|
||||
if (pop.gasPrice == null) {
|
||||
pop.gasPrice = feeData.gasPrice;
|
||||
}
|
||||
|
||||
// Explicitly set untyped transaction to legacy
|
||||
// @TODO: Maybe this shold allow type 1?
|
||||
pop.type = 0;
|
||||
|
||||
} else {
|
||||
// getFeeData has failed us.
|
||||
assert(false, "failed to get consistent fee data", "UNSUPPORTED_OPERATION", {
|
||||
operation: "signer.getFeeData" });
|
||||
}
|
||||
|
||||
} else if (pop.type === 2 || pop.type === 3 || pop.type === 4) {
|
||||
// Explicitly using EIP-1559 or EIP-4844
|
||||
|
||||
// Populate missing fee data
|
||||
if (pop.maxFeePerGas == null) {
|
||||
pop.maxFeePerGas = feeData.maxFeePerGas;
|
||||
}
|
||||
|
||||
if (pop.maxPriorityFeePerGas == null) {
|
||||
pop.maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//@TOOD: Don't await all over the place; save them up for
|
||||
// the end for better batching
|
||||
return await resolveProperties(pop);
|
||||
}
|
||||
|
||||
async populateAuthorization(_auth: AuthorizationRequest): Promise<AuthorizationRequest> {
|
||||
const auth = Object.assign({ }, _auth);
|
||||
|
||||
// Add a chain ID if not explicitly set to 0
|
||||
if (auth.chainId == null) {
|
||||
auth.chainId = (await checkProvider(this, "getNetwork").getNetwork()).chainId;
|
||||
}
|
||||
|
||||
// @TODO: Take chain ID into account when populating noce?
|
||||
|
||||
if (auth.nonce == null) { auth.nonce = await this.getNonce(); }
|
||||
|
||||
return auth;
|
||||
}
|
||||
|
||||
async estimateGas(tx: TransactionRequest): Promise<bigint> {
|
||||
return checkProvider(this, "estimateGas").estimateGas(await this.populateCall(tx));
|
||||
}
|
||||
|
||||
async call(tx: TransactionRequest): Promise<string> {
|
||||
return checkProvider(this, "call").call(await this.populateCall(tx));
|
||||
}
|
||||
|
||||
async resolveName(name: string): Promise<null | string> {
|
||||
const provider = checkProvider(this, "resolveName");
|
||||
return await provider.resolveName(name);
|
||||
}
|
||||
|
||||
async sendTransaction(tx: TransactionRequest): Promise<TransactionResponse> {
|
||||
const provider = checkProvider(this, "sendTransaction");
|
||||
|
||||
const pop = await this.populateTransaction(tx);
|
||||
delete pop.from;
|
||||
const txObj = Transaction.from(pop);
|
||||
return await provider.broadcastTransaction(await this.signTransaction(txObj));
|
||||
}
|
||||
|
||||
// @TODO: in v7 move this to be abstract
|
||||
authorize(authorization: AuthorizationRequest): Promise<Authorization> {
|
||||
assert(false, "authorization not implemented for this signer",
|
||||
"UNSUPPORTED_OPERATION", { operation: "authorize" });
|
||||
}
|
||||
|
||||
abstract signTransaction(tx: TransactionRequest): Promise<string>;
|
||||
abstract signMessage(message: string | Uint8Array): Promise<string>;
|
||||
abstract signTypedData(domain: TypedDataDomain, types: Record<string, Array<TypedDataField>>, value: Record<string, any>): Promise<string>;
|
||||
}
|
||||
|
||||
/**
|
||||
* A **VoidSigner** is a class designed to allow an address to be used
|
||||
* in any API which accepts a Signer, but for which there are no
|
||||
* credentials available to perform any actual signing.
|
||||
*
|
||||
* This for example allow impersonating an account for the purpose of
|
||||
* static calls or estimating gas, but does not allow sending transactions.
|
||||
*/
|
||||
export class VoidSigner extends AbstractSigner {
|
||||
/**
|
||||
* The signer address.
|
||||
*/
|
||||
readonly address!: string;
|
||||
|
||||
/**
|
||||
* Creates a new **VoidSigner** with %%address%% attached to
|
||||
* %%provider%%.
|
||||
*/
|
||||
constructor(address: string, provider?: null | Provider) {
|
||||
super(provider);
|
||||
defineProperties<VoidSigner>(this, { address });
|
||||
}
|
||||
|
||||
async getAddress(): Promise<string> { return this.address; }
|
||||
|
||||
connect(provider: null | Provider): VoidSigner {
|
||||
return new VoidSigner(this.address, provider);
|
||||
}
|
||||
|
||||
#throwUnsupported(suffix: string, operation: string): never {
|
||||
assert(false, `VoidSigner cannot sign ${ suffix }`, "UNSUPPORTED_OPERATION", { operation });
|
||||
}
|
||||
|
||||
async signTransaction(tx: TransactionRequest): Promise<string> {
|
||||
this.#throwUnsupported("transactions", "signTransaction");
|
||||
}
|
||||
|
||||
async signMessage(message: string | Uint8Array): Promise<string> {
|
||||
this.#throwUnsupported("messages", "signMessage");
|
||||
}
|
||||
|
||||
async signTypedData(domain: TypedDataDomain, types: Record<string, Array<TypedDataField>>, value: Record<string, any>): Promise<string> {
|
||||
this.#throwUnsupported("typed-data", "signTypedData");
|
||||
}
|
||||
}
|
||||
|
||||
49
dev/env/node_modules/ethers/src.ts/providers/community.ts
generated
vendored
Executable file
49
dev/env/node_modules/ethers/src.ts/providers/community.ts
generated
vendored
Executable file
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* There are many awesome community services that provide Ethereum
|
||||
* nodes both for developers just starting out and for large-scale
|
||||
* communities.
|
||||
*
|
||||
* @_section: api/providers/thirdparty: Community Providers [thirdparty]
|
||||
*/
|
||||
|
||||
/**
|
||||
* Providers which offer community credentials should extend this
|
||||
* to notify any interested consumers whether community credentials
|
||||
* are in-use.
|
||||
*/
|
||||
export interface CommunityResourcable {
|
||||
/**
|
||||
* Returns true if the instance is connected using the community
|
||||
* credentials.
|
||||
*/
|
||||
isCommunityResource(): boolean;
|
||||
}
|
||||
|
||||
// Show the throttle message only once per service
|
||||
const shown: Set<string> = new Set();
|
||||
|
||||
/**
|
||||
* Displays a warning in the console when the community resource is
|
||||
* being used too heavily by the app, recommending the developer
|
||||
* acquire their own credentials instead of using the community
|
||||
* credentials.
|
||||
*
|
||||
* The notification will only occur once per service.
|
||||
*/
|
||||
export function showThrottleMessage(service: string): void {
|
||||
if (shown.has(service)) { return; }
|
||||
shown.add(service);
|
||||
|
||||
console.log("========= NOTICE =========")
|
||||
console.log(`Request-Rate Exceeded for ${ service } (this message will not be repeated)`);
|
||||
console.log("");
|
||||
console.log("The default API keys for each service are provided as a highly-throttled,");
|
||||
console.log("community resource for low-traffic projects and early prototyping.");
|
||||
console.log("");
|
||||
console.log("While your application will continue to function, we highly recommended");
|
||||
console.log("signing up for your own API keys to improve performance, increase your");
|
||||
console.log("request rate/limit and enable other perks, such as metrics and advanced APIs.");
|
||||
console.log("");
|
||||
console.log("For more details: https:/\/docs.ethers.org/api-keys/");
|
||||
console.log("==========================");
|
||||
}
|
||||
42
dev/env/node_modules/ethers/src.ts/providers/contracts.ts
generated
vendored
Executable file
42
dev/env/node_modules/ethers/src.ts/providers/contracts.ts
generated
vendored
Executable file
@@ -0,0 +1,42 @@
|
||||
import type {
|
||||
Provider, TransactionRequest, TransactionResponse
|
||||
} from "./provider.js";
|
||||
|
||||
/**
|
||||
* A **ContractRunner** is a generic interface which defines an object
|
||||
* capable of interacting with a Contract on the network.
|
||||
*
|
||||
* The more operations supported, the more utility it is capable of.
|
||||
*
|
||||
* The most common ContractRunners are [Providers](Provider) which enable
|
||||
* read-only access and [Signers](Signer) which enable write-access.
|
||||
*/
|
||||
export interface ContractRunner {
|
||||
/**
|
||||
* The provider used for necessary state querying operations.
|
||||
*
|
||||
* This can also point to the **ContractRunner** itself, in the
|
||||
* case of an [[AbstractProvider]].
|
||||
*/
|
||||
provider: null | Provider;
|
||||
|
||||
/**
|
||||
* Required to estimate gas.
|
||||
*/
|
||||
estimateGas?: (tx: TransactionRequest) => Promise<bigint>;
|
||||
|
||||
/**
|
||||
* Required for pure, view or static calls to contracts.
|
||||
*/
|
||||
call?: (tx: TransactionRequest) => Promise<string>;
|
||||
|
||||
/**
|
||||
* Required to support ENS names
|
||||
*/
|
||||
resolveName?: (name: string) => Promise<null | string>;
|
||||
|
||||
/**
|
||||
* Required for state mutating calls
|
||||
*/
|
||||
sendTransaction?: (tx: TransactionRequest) => Promise<TransactionResponse>;
|
||||
}
|
||||
202
dev/env/node_modules/ethers/src.ts/providers/default-provider.ts
generated
vendored
Executable file
202
dev/env/node_modules/ethers/src.ts/providers/default-provider.ts
generated
vendored
Executable file
@@ -0,0 +1,202 @@
|
||||
|
||||
import { assert } from "../utils/index.js";
|
||||
|
||||
import { AnkrProvider } from "./provider-ankr.js";
|
||||
import { AlchemyProvider } from "./provider-alchemy.js";
|
||||
//import { BlockscoutProvider } from "./provider-blockscout.js";
|
||||
import { ChainstackProvider } from "./provider-chainstack.js";
|
||||
import { CloudflareProvider } from "./provider-cloudflare.js";
|
||||
import { EtherscanProvider } from "./provider-etherscan.js";
|
||||
import { InfuraProvider } from "./provider-infura.js";
|
||||
//import { PocketProvider } from "./provider-pocket.js";
|
||||
import { QuickNodeProvider } from "./provider-quicknode.js";
|
||||
|
||||
import { FallbackProvider } from "./provider-fallback.js";
|
||||
import { JsonRpcProvider } from "./provider-jsonrpc.js";
|
||||
import { Network } from "./network.js";
|
||||
import { WebSocketProvider } from "./provider-websocket.js";
|
||||
|
||||
import type { AbstractProvider } from "./abstract-provider.js";
|
||||
import type { Networkish } from "./network.js";
|
||||
import { WebSocketLike } from "./provider-websocket.js";
|
||||
|
||||
function isWebSocketLike(value: any): value is WebSocketLike {
|
||||
return (value && typeof(value.send) === "function" &&
|
||||
typeof(value.close) === "function");
|
||||
}
|
||||
|
||||
const Testnets = "goerli kovan sepolia classicKotti optimism-goerli arbitrum-goerli matic-mumbai bnbt".split(" ");
|
||||
|
||||
/**
|
||||
* Returns a default provider for %%network%%.
|
||||
*
|
||||
* If %%network%% is a [[WebSocketLike]] or string that begins with
|
||||
* ``"ws:"`` or ``"wss:"``, a [[WebSocketProvider]] is returned backed
|
||||
* by that WebSocket or URL.
|
||||
*
|
||||
* If %%network%% is a string that begins with ``"HTTP:"`` or ``"HTTPS:"``,
|
||||
* a [[JsonRpcProvider]] is returned connected to that URL.
|
||||
*
|
||||
* Otherwise, a default provider is created backed by well-known public
|
||||
* Web3 backends (such as [[link-infura]]) using community-provided API
|
||||
* keys.
|
||||
*
|
||||
* The %%options%% allows specifying custom API keys per backend (setting
|
||||
* an API key to ``"-"`` will omit that provider) and ``options.exclusive``
|
||||
* can be set to either a backend name or and array of backend names, which
|
||||
* will whitelist **only** those backends.
|
||||
*
|
||||
* Current backend strings supported are:
|
||||
* - ``"alchemy"``
|
||||
* - ``"ankr"``
|
||||
* - ``"cloudflare"``
|
||||
* - ``"chainstack"``
|
||||
* - ``"etherscan"``
|
||||
* - ``"infura"``
|
||||
* - ``"publicPolygon"``
|
||||
* - ``"quicknode"``
|
||||
*
|
||||
* @example:
|
||||
* // Connect to a local Geth node
|
||||
* provider = getDefaultProvider("http://localhost:8545/");
|
||||
*
|
||||
* // Connect to Ethereum mainnet with any current and future
|
||||
* // third-party services available
|
||||
* provider = getDefaultProvider("mainnet");
|
||||
*
|
||||
* // Connect to Polygon, but only allow Etherscan and
|
||||
* // INFURA and use "MY_API_KEY" in calls to Etherscan.
|
||||
* provider = getDefaultProvider("matic", {
|
||||
* etherscan: "MY_API_KEY",
|
||||
* exclusive: [ "etherscan", "infura" ]
|
||||
* });
|
||||
*/
|
||||
export function getDefaultProvider(network?: string | Networkish | WebSocketLike, options?: any): AbstractProvider {
|
||||
if (options == null) { options = { }; }
|
||||
|
||||
const allowService = (name: string) => {
|
||||
if (options[name] === "-") { return false; }
|
||||
if (typeof(options.exclusive) === "string") {
|
||||
return (name === options.exclusive);
|
||||
}
|
||||
if (Array.isArray(options.exclusive)) {
|
||||
return (options.exclusive.indexOf(name) !== -1);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
if (typeof(network) === "string" && network.match(/^https?:/)) {
|
||||
return new JsonRpcProvider(network);
|
||||
}
|
||||
|
||||
if (typeof(network) === "string" && network.match(/^wss?:/) || isWebSocketLike(network)) {
|
||||
return new WebSocketProvider(network);
|
||||
}
|
||||
|
||||
// Get the network and name, if possible
|
||||
let staticNetwork: null | Network = null;
|
||||
try {
|
||||
staticNetwork = Network.from(network);
|
||||
} catch (error) { }
|
||||
|
||||
|
||||
const providers: Array<AbstractProvider> = [ ];
|
||||
|
||||
if (allowService("publicPolygon") && staticNetwork) {
|
||||
if (staticNetwork.name === "matic") {
|
||||
providers.push(new JsonRpcProvider("https:/\/polygon-rpc.com/", staticNetwork, { staticNetwork }));
|
||||
} else if (staticNetwork.name === "matic-amoy") {
|
||||
providers.push(new JsonRpcProvider("https:/\/rpc-amoy.polygon.technology/", staticNetwork, { staticNetwork }));
|
||||
}
|
||||
}
|
||||
|
||||
if (allowService("alchemy")) {
|
||||
try {
|
||||
providers.push(new AlchemyProvider(network, options.alchemy));
|
||||
} catch (error) { }
|
||||
}
|
||||
|
||||
if (allowService("ankr") && options.ankr != null) {
|
||||
try {
|
||||
providers.push(new AnkrProvider(network, options.ankr));
|
||||
} catch (error) { }
|
||||
}
|
||||
/* Temporarily remove until custom error issue is fixed
|
||||
if (allowService("blockscout")) {
|
||||
try {
|
||||
providers.push(new BlockscoutProvider(network, options.blockscout));
|
||||
} catch (error) { }
|
||||
}
|
||||
*/
|
||||
if (allowService("chainstack")) {
|
||||
try {
|
||||
providers.push(new ChainstackProvider(network, options.chainstack));
|
||||
} catch (error) { }
|
||||
}
|
||||
|
||||
if (allowService("cloudflare")) {
|
||||
try {
|
||||
providers.push(new CloudflareProvider(network));
|
||||
} catch (error) { }
|
||||
}
|
||||
|
||||
if (allowService("etherscan")) {
|
||||
try {
|
||||
providers.push(new EtherscanProvider(network, options.etherscan));
|
||||
} catch (error) { }
|
||||
}
|
||||
|
||||
if (allowService("infura")) {
|
||||
try {
|
||||
let projectId = options.infura;
|
||||
let projectSecret: undefined | string = undefined;
|
||||
if (typeof(projectId) === "object") {
|
||||
projectSecret = projectId.projectSecret;
|
||||
projectId = projectId.projectId;
|
||||
}
|
||||
providers.push(new InfuraProvider(network, projectId, projectSecret));
|
||||
} catch (error) { }
|
||||
}
|
||||
/*
|
||||
if (options.pocket !== "-") {
|
||||
try {
|
||||
let appId = options.pocket;
|
||||
let secretKey: undefined | string = undefined;
|
||||
let loadBalancer: undefined | boolean = undefined;
|
||||
if (typeof(appId) === "object") {
|
||||
loadBalancer = !!appId.loadBalancer;
|
||||
secretKey = appId.secretKey;
|
||||
appId = appId.appId;
|
||||
}
|
||||
providers.push(new PocketProvider(network, appId, secretKey, loadBalancer));
|
||||
} catch (error) { console.log(error); }
|
||||
}
|
||||
*/
|
||||
if (allowService("quicknode")) {
|
||||
try {
|
||||
let token = options.quicknode;
|
||||
providers.push(new QuickNodeProvider(network, token));
|
||||
} catch (error) { }
|
||||
}
|
||||
|
||||
assert(providers.length, "unsupported default network", "UNSUPPORTED_OPERATION", {
|
||||
operation: "getDefaultProvider"
|
||||
});
|
||||
|
||||
// No need for a FallbackProvider
|
||||
if (providers.length === 1) { return providers[0]; }
|
||||
|
||||
// We use the floor because public third-party providers can be unreliable,
|
||||
// so a low number of providers with a large quorum will fail too often
|
||||
let quorum = Math.floor(providers.length / 2);
|
||||
if (quorum > 2) { quorum = 2; }
|
||||
|
||||
// Testnets don't need as strong a security gaurantee and speed is
|
||||
// more useful during testing
|
||||
if (staticNetwork && Testnets.indexOf(staticNetwork.name) !== -1) { quorum = 1; }
|
||||
|
||||
// Provided override qorum takes priority
|
||||
if (options && options.quorum) { quorum = options.quorum; }
|
||||
|
||||
return new FallbackProvider(providers, undefined, { quorum });
|
||||
}
|
||||
606
dev/env/node_modules/ethers/src.ts/providers/ens-resolver.ts
generated
vendored
Executable file
606
dev/env/node_modules/ethers/src.ts/providers/ens-resolver.ts
generated
vendored
Executable file
@@ -0,0 +1,606 @@
|
||||
/**
|
||||
* ENS is a service which allows easy-to-remember names to map to
|
||||
* network addresses.
|
||||
*
|
||||
* @_section: api/providers/ens-resolver:ENS Resolver [about-ens-rsolver]
|
||||
*/
|
||||
|
||||
import { getAddress } from "../address/index.js";
|
||||
import { ZeroAddress } from "../constants/index.js";
|
||||
import { Contract } from "../contract/index.js";
|
||||
import { dnsEncode, namehash } from "../hash/index.js";
|
||||
import {
|
||||
hexlify, isHexString, toBeHex,
|
||||
defineProperties, encodeBase58,
|
||||
assert, assertArgument, isError,
|
||||
FetchRequest
|
||||
} from "../utils/index.js";
|
||||
|
||||
import type { FunctionFragment } from "../abi/index.js";
|
||||
|
||||
import type { BytesLike } from "../utils/index.js";
|
||||
|
||||
import type { AbstractProvider, AbstractProviderPlugin } from "./abstract-provider.js";
|
||||
import type { EnsPlugin } from "./plugins-network.js";
|
||||
import type { Provider } from "./provider.js";
|
||||
|
||||
// @TODO: This should use the fetch-data:ipfs gateway
|
||||
// Trim off the ipfs:// prefix and return the default gateway URL
|
||||
function getIpfsLink(link: string): string {
|
||||
if (link.match(/^ipfs:\/\/ipfs\//i)) {
|
||||
link = link.substring(12);
|
||||
} else if (link.match(/^ipfs:\/\//i)) {
|
||||
link = link.substring(7);
|
||||
} else {
|
||||
assertArgument(false, "unsupported IPFS format", "link", link);
|
||||
}
|
||||
|
||||
return `https:/\/gateway.ipfs.io/ipfs/${ link }`;
|
||||
}
|
||||
|
||||
/**
|
||||
* The type of data found during a steip during avatar resolution.
|
||||
*/
|
||||
export type AvatarLinkageType = "name" | "avatar" | "!avatar" | "url" | "data" | "ipfs" |
|
||||
"erc721" | "erc1155" | "!erc721-caip" | "!erc1155-caip" |
|
||||
"!owner" | "owner" | "!balance" | "balance" |
|
||||
"metadata-url-base" | "metadata-url-expanded" | "metadata-url" | "!metadata-url" |
|
||||
"!metadata" | "metadata" |
|
||||
"!imageUrl" | "imageUrl-ipfs" | "imageUrl" | "!imageUrl-ipfs";
|
||||
|
||||
/**
|
||||
* An individual record for each step during avatar resolution.
|
||||
*/
|
||||
export interface AvatarLinkage {
|
||||
/**
|
||||
* The type of linkage.
|
||||
*/
|
||||
type: AvatarLinkageType;
|
||||
|
||||
/**
|
||||
* The linkage value.
|
||||
*/
|
||||
value: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* When resolving an avatar for an ENS name, there are many
|
||||
* steps involved, fetching metadata, validating results, et cetera.
|
||||
*
|
||||
* Some applications may wish to analyse this data, or use this data
|
||||
* to diagnose promblems, so an **AvatarResult** provides details of
|
||||
* each completed step during avatar resolution.
|
||||
*/
|
||||
export interface AvatarResult {
|
||||
/**
|
||||
* How the [[url]] was arrived at, resolving the many steps required
|
||||
* for an avatar URL.
|
||||
*/
|
||||
linkage: Array<AvatarLinkage>;
|
||||
|
||||
/**
|
||||
* The avatar URL or null if the avatar was not set, or there was
|
||||
* an issue during validation (such as the address not owning the
|
||||
* avatar or a metadata error).
|
||||
*/
|
||||
url: null | string;
|
||||
};
|
||||
|
||||
/**
|
||||
* A provider plugin super-class for processing multicoin address types.
|
||||
*/
|
||||
export abstract class MulticoinProviderPlugin implements AbstractProviderPlugin {
|
||||
/**
|
||||
* The name.
|
||||
*/
|
||||
readonly name!: string;
|
||||
|
||||
/**
|
||||
* Creates a new **MulticoinProviderPluing** for %%name%%.
|
||||
*/
|
||||
constructor(name: string) {
|
||||
defineProperties<MulticoinProviderPlugin>(this, { name });
|
||||
}
|
||||
|
||||
connect(proivder: Provider): MulticoinProviderPlugin {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ``true`` if %%coinType%% is supported by this plugin.
|
||||
*/
|
||||
supportsCoinType(coinType: number): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to the encoded %%address%% for %%coinType%%.
|
||||
*/
|
||||
async encodeAddress(coinType: number, address: string): Promise<string> {
|
||||
throw new Error("unsupported coin");
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to the decoded %%data%% for %%coinType%%.
|
||||
*/
|
||||
async decodeAddress(coinType: number, data: BytesLike): Promise<string> {
|
||||
throw new Error("unsupported coin");
|
||||
}
|
||||
}
|
||||
|
||||
const BasicMulticoinPluginId = "org.ethers.plugins.provider.BasicMulticoin";
|
||||
|
||||
/**
|
||||
* A **BasicMulticoinProviderPlugin** provides service for common
|
||||
* coin types, which do not require additional libraries to encode or
|
||||
* decode.
|
||||
*/
|
||||
export class BasicMulticoinProviderPlugin extends MulticoinProviderPlugin {
|
||||
/**
|
||||
* Creates a new **BasicMulticoinProviderPlugin**.
|
||||
*/
|
||||
constructor() {
|
||||
super(BasicMulticoinPluginId);
|
||||
}
|
||||
}
|
||||
|
||||
const matcherIpfs = new RegExp("^(ipfs):/\/(.*)$", "i");
|
||||
const matchers = [
|
||||
new RegExp("^(https):/\/(.*)$", "i"),
|
||||
new RegExp("^(data):(.*)$", "i"),
|
||||
matcherIpfs,
|
||||
new RegExp("^eip155:[0-9]+/(erc[0-9]+):(.*)$", "i"),
|
||||
];
|
||||
|
||||
/**
|
||||
* A connected object to a resolved ENS name resolver, which can be
|
||||
* used to query additional details.
|
||||
*/
|
||||
export class EnsResolver {
|
||||
/**
|
||||
* The connected provider.
|
||||
*/
|
||||
provider!: AbstractProvider;
|
||||
|
||||
/**
|
||||
* The address of the resolver.
|
||||
*/
|
||||
address!: string;
|
||||
|
||||
/**
|
||||
* The name this resolver was resolved against.
|
||||
*/
|
||||
name!: string;
|
||||
|
||||
// For EIP-2544 names, the ancestor that provided the resolver
|
||||
#supports2544: null | Promise<boolean>;
|
||||
|
||||
#resolver: Contract;
|
||||
|
||||
constructor(provider: AbstractProvider, address: string, name: string) {
|
||||
defineProperties<EnsResolver>(this, { provider, address, name });
|
||||
this.#supports2544 = null;
|
||||
|
||||
this.#resolver = new Contract(address, [
|
||||
"function supportsInterface(bytes4) view returns (bool)",
|
||||
"function resolve(bytes, bytes) view returns (bytes)",
|
||||
"function addr(bytes32) view returns (address)",
|
||||
"function addr(bytes32, uint) view returns (bytes)",
|
||||
"function text(bytes32, string) view returns (string)",
|
||||
"function contenthash(bytes32) view returns (bytes)",
|
||||
], provider);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to true if the resolver supports wildcard resolution.
|
||||
*/
|
||||
async supportsWildcard(): Promise<boolean> {
|
||||
if (this.#supports2544 == null) {
|
||||
this.#supports2544 = (async () => {
|
||||
try {
|
||||
return await this.#resolver.supportsInterface("0x9061b923");
|
||||
} catch (error) {
|
||||
// Wildcard resolvers must understand supportsInterface
|
||||
// and return true.
|
||||
if (isError(error, "CALL_EXCEPTION")) { return false; }
|
||||
|
||||
// Let future attempts try again...
|
||||
this.#supports2544 = null;
|
||||
|
||||
throw error;
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
return await this.#supports2544;
|
||||
}
|
||||
|
||||
async #fetch(funcName: string, params?: Array<any>): Promise<null | any> {
|
||||
params = (params || []).slice();
|
||||
const iface = this.#resolver.interface;
|
||||
|
||||
// The first parameters is always the nodehash
|
||||
params.unshift(namehash(this.name))
|
||||
|
||||
let fragment: null | FunctionFragment = null;
|
||||
if (await this.supportsWildcard()) {
|
||||
fragment = iface.getFunction(funcName);
|
||||
assert(fragment, "missing fragment", "UNKNOWN_ERROR", {
|
||||
info: { funcName }
|
||||
});
|
||||
|
||||
params = [
|
||||
dnsEncode(this.name, 255),
|
||||
iface.encodeFunctionData(fragment, params)
|
||||
];
|
||||
|
||||
funcName = "resolve(bytes,bytes)";
|
||||
}
|
||||
|
||||
params.push({
|
||||
enableCcipRead: true
|
||||
});
|
||||
|
||||
try {
|
||||
const result = await this.#resolver[funcName](...params);
|
||||
|
||||
if (fragment) {
|
||||
return iface.decodeFunctionResult(fragment, result)[0];
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (error: any) {
|
||||
if (!isError(error, "CALL_EXCEPTION")) { throw error; }
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to the address for %%coinType%% or null if the
|
||||
* provided %%coinType%% has not been configured.
|
||||
*/
|
||||
async getAddress(coinType?: number): Promise<null | string> {
|
||||
if (coinType == null) { coinType = 60; }
|
||||
if (coinType === 60) {
|
||||
try {
|
||||
const result = await this.#fetch("addr(bytes32)");
|
||||
|
||||
// No address
|
||||
if (result == null || result === ZeroAddress) { return null; }
|
||||
|
||||
return result;
|
||||
} catch (error: any) {
|
||||
if (isError(error, "CALL_EXCEPTION")) { return null; }
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Try decoding its EVM canonical chain as an EVM chain address first
|
||||
if (coinType >= 0 && coinType < 0x80000000) {
|
||||
let ethCoinType = coinType + 0x80000000;
|
||||
|
||||
const data = await this.#fetch("addr(bytes32,uint)", [ ethCoinType ]);
|
||||
if (isHexString(data, 20)) { return getAddress(data); }
|
||||
}
|
||||
|
||||
let coinPlugin: null | MulticoinProviderPlugin = null;
|
||||
for (const plugin of this.provider.plugins) {
|
||||
if (!(plugin instanceof MulticoinProviderPlugin)) { continue; }
|
||||
if (plugin.supportsCoinType(coinType)) {
|
||||
coinPlugin = plugin;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (coinPlugin == null) { return null; }
|
||||
|
||||
// keccak256("addr(bytes32,uint256")
|
||||
const data = await this.#fetch("addr(bytes32,uint)", [ coinType ]);
|
||||
|
||||
// No address
|
||||
if (data == null || data === "0x") { return null; }
|
||||
|
||||
// Compute the address
|
||||
const address = await coinPlugin.decodeAddress(coinType, data);
|
||||
|
||||
if (address != null) { return address; }
|
||||
|
||||
assert(false, `invalid coin data`, "UNSUPPORTED_OPERATION", {
|
||||
operation: `getAddress(${ coinType })`,
|
||||
info: { coinType, data }
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to the EIP-634 text record for %%key%%, or ``null``
|
||||
* if unconfigured.
|
||||
*/
|
||||
async getText(key: string): Promise<null | string> {
|
||||
const data = await this.#fetch("text(bytes32,string)", [ key ]);
|
||||
if (data == null || data === "0x") { return null; }
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rsolves to the content-hash or ``null`` if unconfigured.
|
||||
*/
|
||||
async getContentHash(): Promise<null | string> {
|
||||
// keccak256("contenthash()")
|
||||
const data = await this.#fetch("contenthash(bytes32)");
|
||||
|
||||
// No contenthash
|
||||
if (data == null || data === "0x") { return null; }
|
||||
|
||||
// IPFS (CID: 1, Type: 70=DAG-PB, 72=libp2p-key)
|
||||
const ipfs = data.match(/^0x(e3010170|e5010172)(([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f]*))$/);
|
||||
if (ipfs) {
|
||||
const scheme = (ipfs[1] === "e3010170") ? "ipfs": "ipns";
|
||||
const length = parseInt(ipfs[4], 16);
|
||||
if (ipfs[5].length === length * 2) {
|
||||
return `${ scheme }:/\/${ encodeBase58("0x" + ipfs[2])}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Swarm (CID: 1, Type: swarm-manifest; hash/length hard-coded to keccak256/32)
|
||||
const swarm = data.match(/^0xe40101fa011b20([0-9a-f]*)$/)
|
||||
if (swarm && swarm[1].length === 64) {
|
||||
return `bzz:/\/${ swarm[1] }`;
|
||||
}
|
||||
|
||||
assert(false, `invalid or unsupported content hash data`, "UNSUPPORTED_OPERATION", {
|
||||
operation: "getContentHash()",
|
||||
info: { data }
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to the avatar url or ``null`` if the avatar is either
|
||||
* unconfigured or incorrectly configured (e.g. references an NFT
|
||||
* not owned by the address).
|
||||
*
|
||||
* If diagnosing issues with configurations, the [[_getAvatar]]
|
||||
* method may be useful.
|
||||
*/
|
||||
async getAvatar(): Promise<null | string> {
|
||||
const avatar = await this._getAvatar();
|
||||
return avatar.url;
|
||||
}
|
||||
|
||||
/**
|
||||
* When resolving an avatar, there are many steps involved, such
|
||||
* fetching metadata and possibly validating ownership of an
|
||||
* NFT.
|
||||
*
|
||||
* This method can be used to examine each step and the value it
|
||||
* was working from.
|
||||
*/
|
||||
async _getAvatar(): Promise<AvatarResult> {
|
||||
const linkage: Array<AvatarLinkage> = [ { type: "name", value: this.name } ];
|
||||
try {
|
||||
// test data for ricmoo.eth
|
||||
//const avatar = "eip155:1/erc721:0x265385c7f4132228A0d54EB1A9e7460b91c0cC68/29233";
|
||||
const avatar = await this.getText("avatar");
|
||||
if (avatar == null) {
|
||||
linkage.push({ type: "!avatar", value: "" });
|
||||
return { url: null, linkage };
|
||||
}
|
||||
linkage.push({ type: "avatar", value: avatar });
|
||||
|
||||
for (let i = 0; i < matchers.length; i++) {
|
||||
const match = avatar.match(matchers[i]);
|
||||
if (match == null) { continue; }
|
||||
|
||||
const scheme = match[1].toLowerCase();
|
||||
|
||||
switch (scheme) {
|
||||
case "https":
|
||||
case "data":
|
||||
linkage.push({ type: "url", value: avatar });
|
||||
return { linkage, url: avatar };
|
||||
case "ipfs": {
|
||||
const url = getIpfsLink(avatar);
|
||||
linkage.push({ type: "ipfs", value: avatar });
|
||||
linkage.push({ type: "url", value: url });
|
||||
return { linkage, url };
|
||||
}
|
||||
|
||||
case "erc721":
|
||||
case "erc1155": {
|
||||
// Depending on the ERC type, use tokenURI(uint256) or url(uint256)
|
||||
const selector = (scheme === "erc721") ? "tokenURI(uint256)": "uri(uint256)";
|
||||
linkage.push({ type: scheme, value: avatar });
|
||||
|
||||
// The owner of this name
|
||||
const owner = await this.getAddress();
|
||||
if (owner == null) {
|
||||
linkage.push({ type: "!owner", value: "" });
|
||||
return { url: null, linkage };
|
||||
}
|
||||
|
||||
const comps = (match[2] || "").split("/");
|
||||
if (comps.length !== 2) {
|
||||
linkage.push({ type: <any>`!${ scheme }caip`, value: (match[2] || "") });
|
||||
return { url: null, linkage };
|
||||
}
|
||||
|
||||
const tokenId = comps[1];
|
||||
|
||||
const contract = new Contract(comps[0], [
|
||||
// ERC-721
|
||||
"function tokenURI(uint) view returns (string)",
|
||||
"function ownerOf(uint) view returns (address)",
|
||||
|
||||
// ERC-1155
|
||||
"function uri(uint) view returns (string)",
|
||||
"function balanceOf(address, uint256) view returns (uint)"
|
||||
], this.provider);
|
||||
|
||||
// Check that this account owns the token
|
||||
if (scheme === "erc721") {
|
||||
const tokenOwner = await contract.ownerOf(tokenId);
|
||||
|
||||
if (owner !== tokenOwner) {
|
||||
linkage.push({ type: "!owner", value: tokenOwner });
|
||||
return { url: null, linkage };
|
||||
}
|
||||
linkage.push({ type: "owner", value: tokenOwner });
|
||||
|
||||
} else if (scheme === "erc1155") {
|
||||
const balance = await contract.balanceOf(owner, tokenId);
|
||||
if (!balance) {
|
||||
linkage.push({ type: "!balance", value: "0" });
|
||||
return { url: null, linkage };
|
||||
}
|
||||
linkage.push({ type: "balance", value: balance.toString() });
|
||||
}
|
||||
|
||||
// Call the token contract for the metadata URL
|
||||
let metadataUrl = await contract[selector](tokenId);
|
||||
if (metadataUrl == null || metadataUrl === "0x") {
|
||||
linkage.push({ type: "!metadata-url", value: "" });
|
||||
return { url: null, linkage };
|
||||
}
|
||||
|
||||
linkage.push({ type: "metadata-url-base", value: metadataUrl });
|
||||
|
||||
// ERC-1155 allows a generic {id} in the URL
|
||||
if (scheme === "erc1155") {
|
||||
metadataUrl = metadataUrl.replace("{id}", toBeHex(tokenId, 32).substring(2));
|
||||
linkage.push({ type: "metadata-url-expanded", value: metadataUrl });
|
||||
}
|
||||
|
||||
// Transform IPFS metadata links
|
||||
if (metadataUrl.match(/^ipfs:/i)) {
|
||||
metadataUrl = getIpfsLink(metadataUrl);
|
||||
}
|
||||
linkage.push({ type: "metadata-url", value: metadataUrl });
|
||||
|
||||
// Get the token metadata
|
||||
let metadata: any = { };
|
||||
const response = await (new FetchRequest(metadataUrl)).send();
|
||||
response.assertOk();
|
||||
|
||||
try {
|
||||
metadata = response.bodyJson;
|
||||
} catch (error) {
|
||||
try {
|
||||
linkage.push({ type: "!metadata", value: response.bodyText });
|
||||
} catch (error) {
|
||||
const bytes = response.body;
|
||||
if (bytes) {
|
||||
linkage.push({ type: "!metadata", value: hexlify(bytes) });
|
||||
}
|
||||
return { url: null, linkage };
|
||||
}
|
||||
return { url: null, linkage };
|
||||
}
|
||||
|
||||
if (!metadata) {
|
||||
linkage.push({ type: "!metadata", value: "" });
|
||||
return { url: null, linkage };
|
||||
}
|
||||
|
||||
linkage.push({ type: "metadata", value: JSON.stringify(metadata) });
|
||||
|
||||
// Pull the image URL out
|
||||
let imageUrl = metadata.image;
|
||||
if (typeof(imageUrl) !== "string") {
|
||||
linkage.push({ type: "!imageUrl", value: "" });
|
||||
return { url: null, linkage };
|
||||
}
|
||||
|
||||
if (imageUrl.match(/^(https:\/\/|data:)/i)) {
|
||||
// Allow
|
||||
} else {
|
||||
// Transform IPFS link to gateway
|
||||
const ipfs = imageUrl.match(matcherIpfs);
|
||||
if (ipfs == null) {
|
||||
linkage.push({ type: "!imageUrl-ipfs", value: imageUrl });
|
||||
return { url: null, linkage };
|
||||
}
|
||||
|
||||
linkage.push({ type: "imageUrl-ipfs", value: imageUrl });
|
||||
imageUrl = getIpfsLink(imageUrl);
|
||||
}
|
||||
|
||||
linkage.push({ type: "url", value: imageUrl });
|
||||
|
||||
return { linkage, url: imageUrl };
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) { }
|
||||
|
||||
return { linkage, url: null };
|
||||
}
|
||||
|
||||
static async getEnsAddress(provider: Provider): Promise<string> {
|
||||
const network = await provider.getNetwork();
|
||||
|
||||
const ensPlugin = network.getPlugin<EnsPlugin>("org.ethers.plugins.network.Ens");
|
||||
|
||||
// No ENS...
|
||||
assert(ensPlugin, "network does not support ENS", "UNSUPPORTED_OPERATION", {
|
||||
operation: "getEnsAddress", info: { network } });
|
||||
|
||||
return ensPlugin.address;
|
||||
}
|
||||
|
||||
static async #getResolver(provider: Provider, name: string): Promise<null | string> {
|
||||
const ensAddr = await EnsResolver.getEnsAddress(provider);
|
||||
|
||||
try {
|
||||
const contract = new Contract(ensAddr, [
|
||||
"function resolver(bytes32) view returns (address)"
|
||||
], provider);
|
||||
|
||||
const addr = await contract.resolver(namehash(name), {
|
||||
enableCcipRead: true
|
||||
});
|
||||
|
||||
if (addr === ZeroAddress) { return null; }
|
||||
return addr;
|
||||
|
||||
} catch (error) {
|
||||
// ENS registry cannot throw errors on resolver(bytes32),
|
||||
// so probably a link error
|
||||
throw error;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve to the ENS resolver for %%name%% using %%provider%% or
|
||||
* ``null`` if unconfigured.
|
||||
*/
|
||||
static async fromName(provider: AbstractProvider, name: string): Promise<null | EnsResolver> {
|
||||
|
||||
let currentName = name;
|
||||
while (true) {
|
||||
if (currentName === "" || currentName === ".") { return null; }
|
||||
|
||||
// Optimization since the eth node cannot change and does
|
||||
// not have a wildcard resolver
|
||||
if (name !== "eth" && currentName === "eth") { return null; }
|
||||
|
||||
// Check the current node for a resolver
|
||||
const addr = await EnsResolver.#getResolver(provider, currentName);
|
||||
|
||||
// Found a resolver!
|
||||
if (addr != null) {
|
||||
const resolver = new EnsResolver(provider, addr, name);
|
||||
|
||||
// Legacy resolver found, using EIP-2544 so it isn't safe to use
|
||||
if (currentName !== name && !(await resolver.supportsWildcard())) { return null; }
|
||||
|
||||
return resolver;
|
||||
}
|
||||
|
||||
// Get the parent node
|
||||
currentName = currentName.split(".").slice(1).join(".");
|
||||
}
|
||||
}
|
||||
}
|
||||
335
dev/env/node_modules/ethers/src.ts/providers/format.ts
generated
vendored
Executable file
335
dev/env/node_modules/ethers/src.ts/providers/format.ts
generated
vendored
Executable file
@@ -0,0 +1,335 @@
|
||||
/**
|
||||
* @_ignore
|
||||
*/
|
||||
import { getAddress, getCreateAddress } from "../address/index.js";
|
||||
import { Signature } from "../crypto/index.js"
|
||||
import { accessListify } from "../transaction/index.js";
|
||||
import {
|
||||
getBigInt, getNumber, hexlify, isHexString, zeroPadValue,
|
||||
assert, assertArgument
|
||||
} from "../utils/index.js";
|
||||
|
||||
import type { SignatureLike } from "../crypto/index.js"
|
||||
import type {
|
||||
BlockParams, LogParams,
|
||||
TransactionReceiptParams, TransactionResponseParams,
|
||||
} from "./formatting.js";
|
||||
|
||||
|
||||
const BN_0 = BigInt(0);
|
||||
|
||||
export type FormatFunc = (value: any) => any;
|
||||
|
||||
export function allowNull(format: FormatFunc, nullValue?: any): FormatFunc {
|
||||
return (function(value: any) {
|
||||
if (value == null) { return nullValue; }
|
||||
return format(value);
|
||||
});
|
||||
}
|
||||
|
||||
export function arrayOf(format: FormatFunc, allowNull?: boolean): FormatFunc {
|
||||
return ((array: any) => {
|
||||
if (allowNull && array == null) { return null; }
|
||||
if (!Array.isArray(array)) { throw new Error("not an array"); }
|
||||
return array.map((i) => format(i));
|
||||
});
|
||||
}
|
||||
|
||||
// Requires an object which matches a fleet of other formatters
|
||||
// Any FormatFunc may return `undefined` to have the value omitted
|
||||
// from the result object. Calls preserve `this`.
|
||||
export function object(format: Record<string, FormatFunc>, altNames?: Record<string, Array<string>>): FormatFunc {
|
||||
return ((value: any) => {
|
||||
const result: any = { };
|
||||
for (const key in format) {
|
||||
let srcKey = key;
|
||||
if (altNames && key in altNames && !(srcKey in value)) {
|
||||
for (const altKey of altNames[key]) {
|
||||
if (altKey in value) {
|
||||
srcKey = altKey;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const nv = format[key](value[srcKey]);
|
||||
if (nv !== undefined) { result[key] = nv; }
|
||||
} catch (error) {
|
||||
const message = (error instanceof Error) ? error.message: "not-an-error";
|
||||
assert(false, `invalid value for value.${ key } (${ message })`, "BAD_DATA", { value })
|
||||
}
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
export function formatBoolean(value: any): boolean {
|
||||
switch (value) {
|
||||
case true: case "true":
|
||||
return true;
|
||||
case false: case "false":
|
||||
return false;
|
||||
}
|
||||
assertArgument(false, `invalid boolean; ${ JSON.stringify(value) }`, "value", value);
|
||||
}
|
||||
|
||||
export function formatData(value: string): string {
|
||||
assertArgument(isHexString(value, true), "invalid data", "value", value);
|
||||
return value;
|
||||
}
|
||||
|
||||
export function formatHash(value: any): string {
|
||||
assertArgument(isHexString(value, 32), "invalid hash", "value", value);
|
||||
return value;
|
||||
}
|
||||
|
||||
export function formatUint256(value: any): string {
|
||||
if (!isHexString(value)) {
|
||||
throw new Error("invalid uint256");
|
||||
}
|
||||
return zeroPadValue(value, 32);
|
||||
}
|
||||
|
||||
const _formatLog = object({
|
||||
address: getAddress,
|
||||
blockHash: formatHash,
|
||||
blockNumber: getNumber,
|
||||
data: formatData,
|
||||
index: getNumber,
|
||||
removed: allowNull(formatBoolean, false),
|
||||
topics: arrayOf(formatHash),
|
||||
transactionHash: formatHash,
|
||||
transactionIndex: getNumber,
|
||||
}, {
|
||||
index: [ "logIndex" ]
|
||||
});
|
||||
|
||||
export function formatLog(value: any): LogParams {
|
||||
return _formatLog(value);
|
||||
}
|
||||
|
||||
const _formatBlock = object({
|
||||
hash: allowNull(formatHash),
|
||||
parentHash: formatHash,
|
||||
parentBeaconBlockRoot: allowNull(formatHash, null),
|
||||
|
||||
number: getNumber,
|
||||
|
||||
timestamp: getNumber,
|
||||
nonce: allowNull(formatData),
|
||||
difficulty: getBigInt,
|
||||
|
||||
gasLimit: getBigInt,
|
||||
gasUsed: getBigInt,
|
||||
|
||||
stateRoot: allowNull(formatHash, null),
|
||||
receiptsRoot: allowNull(formatHash, null),
|
||||
|
||||
blobGasUsed: allowNull(getBigInt, null),
|
||||
excessBlobGas: allowNull(getBigInt, null),
|
||||
|
||||
miner: allowNull(getAddress),
|
||||
prevRandao: allowNull(formatHash, null),
|
||||
extraData: formatData,
|
||||
|
||||
baseFeePerGas: allowNull(getBigInt)
|
||||
}, {
|
||||
prevRandao: [ "mixHash" ]
|
||||
});
|
||||
|
||||
export function formatBlock(value: any): BlockParams {
|
||||
const result = _formatBlock(value);
|
||||
result.transactions = value.transactions.map((tx: string | TransactionResponseParams) => {
|
||||
if (typeof(tx) === "string") { return tx; }
|
||||
return formatTransactionResponse(tx);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
const _formatReceiptLog = object({
|
||||
transactionIndex: getNumber,
|
||||
blockNumber: getNumber,
|
||||
transactionHash: formatHash,
|
||||
address: getAddress,
|
||||
topics: arrayOf(formatHash),
|
||||
data: formatData,
|
||||
index: getNumber,
|
||||
blockHash: formatHash,
|
||||
}, {
|
||||
index: [ "logIndex" ]
|
||||
});
|
||||
|
||||
export function formatReceiptLog(value: any): LogParams {
|
||||
return _formatReceiptLog(value);
|
||||
}
|
||||
|
||||
const _formatTransactionReceipt = object({
|
||||
to: allowNull(getAddress, null),
|
||||
from: allowNull(getAddress, null),
|
||||
contractAddress: allowNull(getAddress, null),
|
||||
// should be allowNull(hash), but broken-EIP-658 support is handled in receipt
|
||||
index: getNumber,
|
||||
root: allowNull(hexlify),
|
||||
gasUsed: getBigInt,
|
||||
blobGasUsed: allowNull(getBigInt, null),
|
||||
logsBloom: allowNull(formatData),
|
||||
blockHash: formatHash,
|
||||
hash: formatHash,
|
||||
logs: arrayOf(formatReceiptLog),
|
||||
blockNumber: getNumber,
|
||||
//confirmations: allowNull(getNumber, null),
|
||||
cumulativeGasUsed: getBigInt,
|
||||
effectiveGasPrice: allowNull(getBigInt),
|
||||
blobGasPrice: allowNull(getBigInt, null),
|
||||
status: allowNull(getNumber),
|
||||
type: allowNull(getNumber, 0)
|
||||
}, {
|
||||
effectiveGasPrice: [ "gasPrice" ],
|
||||
hash: [ "transactionHash" ],
|
||||
index: [ "transactionIndex" ],
|
||||
});
|
||||
|
||||
export function formatTransactionReceipt(value: any): TransactionReceiptParams {
|
||||
return _formatTransactionReceipt(value);
|
||||
}
|
||||
|
||||
export function formatTransactionResponse(value: any): TransactionResponseParams {
|
||||
|
||||
// Some clients (TestRPC) do strange things like return 0x0 for the
|
||||
// 0 address; correct this to be a real address
|
||||
if (value.to && getBigInt(value.to) === BN_0) {
|
||||
value.to = "0x0000000000000000000000000000000000000000";
|
||||
}
|
||||
|
||||
const result = object({
|
||||
hash: formatHash,
|
||||
|
||||
// Some nodes do not return this, usually test nodes (like Ganache)
|
||||
index: allowNull(getNumber, undefined),
|
||||
|
||||
type: (value: any) => {
|
||||
if (value === "0x" || value == null) { return 0; }
|
||||
return getNumber(value);
|
||||
},
|
||||
accessList: allowNull(accessListify, null),
|
||||
blobVersionedHashes: allowNull(arrayOf(formatHash, true), null),
|
||||
|
||||
authorizationList: allowNull(arrayOf((v: any) => {
|
||||
let sig: SignatureLike;
|
||||
if (v.signature) {
|
||||
sig = v.signature;
|
||||
|
||||
} else {
|
||||
let yParity = v.yParity;
|
||||
if (yParity === "0x1b") {
|
||||
yParity = 0;
|
||||
} else if (yParity === "0x1c") {
|
||||
yParity = 1;
|
||||
}
|
||||
sig = Object.assign({ }, v, { yParity });
|
||||
}
|
||||
|
||||
return {
|
||||
address: getAddress(v.address),
|
||||
chainId: getBigInt(v.chainId),
|
||||
nonce: getBigInt(v.nonce),
|
||||
signature: Signature.from(sig)
|
||||
};
|
||||
}, false), null),
|
||||
|
||||
blockHash: allowNull(formatHash, null),
|
||||
blockNumber: allowNull(getNumber, null),
|
||||
transactionIndex: allowNull(getNumber, null),
|
||||
|
||||
from: getAddress,
|
||||
|
||||
// either (gasPrice) or (maxPriorityFeePerGas + maxFeePerGas) must be set
|
||||
gasPrice: allowNull(getBigInt),
|
||||
maxPriorityFeePerGas: allowNull(getBigInt),
|
||||
maxFeePerGas: allowNull(getBigInt),
|
||||
maxFeePerBlobGas: allowNull(getBigInt, null),
|
||||
|
||||
gasLimit: getBigInt,
|
||||
to: allowNull(getAddress, null),
|
||||
value: getBigInt,
|
||||
nonce: getNumber,
|
||||
data: formatData,
|
||||
|
||||
creates: allowNull(getAddress, null),
|
||||
|
||||
chainId: allowNull(getBigInt, null)
|
||||
}, {
|
||||
data: [ "input" ],
|
||||
gasLimit: [ "gas" ],
|
||||
index: [ "transactionIndex" ]
|
||||
})(value);
|
||||
|
||||
// If to and creates are empty, populate the creates from the value
|
||||
if (result.to == null && result.creates == null) {
|
||||
result.creates = getCreateAddress(result);
|
||||
}
|
||||
|
||||
// @TODO: Check fee data
|
||||
|
||||
// Add an access list to supported transaction types
|
||||
if ((value.type === 1 || value.type === 2) && value.accessList == null) {
|
||||
result.accessList = [ ];
|
||||
}
|
||||
|
||||
// Compute the signature
|
||||
if (value.signature) {
|
||||
result.signature = Signature.from(value.signature);
|
||||
} else {
|
||||
result.signature = Signature.from(value);
|
||||
}
|
||||
|
||||
// Some backends omit ChainId on legacy transactions, but we can compute it
|
||||
if (result.chainId == null) {
|
||||
const chainId = result.signature.legacyChainId;
|
||||
if (chainId != null) { result.chainId = chainId; }
|
||||
}
|
||||
|
||||
|
||||
// @TODO: check chainID
|
||||
/*
|
||||
if (value.chainId != null) {
|
||||
let chainId = value.chainId;
|
||||
|
||||
if (isHexString(chainId)) {
|
||||
chainId = BigNumber.from(chainId).toNumber();
|
||||
}
|
||||
|
||||
result.chainId = chainId;
|
||||
|
||||
} else {
|
||||
let chainId = value.networkId;
|
||||
|
||||
// geth-etc returns chainId
|
||||
if (chainId == null && result.v == null) {
|
||||
chainId = value.chainId;
|
||||
}
|
||||
|
||||
if (isHexString(chainId)) {
|
||||
chainId = BigNumber.from(chainId).toNumber();
|
||||
}
|
||||
|
||||
if (typeof(chainId) !== "number" && result.v != null) {
|
||||
chainId = (result.v - 35) / 2;
|
||||
if (chainId < 0) { chainId = 0; }
|
||||
chainId = parseInt(chainId);
|
||||
}
|
||||
|
||||
if (typeof(chainId) !== "number") { chainId = 0; }
|
||||
|
||||
result.chainId = chainId;
|
||||
}
|
||||
*/
|
||||
|
||||
// 0x0000... should actually be null
|
||||
if (result.blockHash && getBigInt(result.blockHash) === BN_0) {
|
||||
result.blockHash = null;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
418
dev/env/node_modules/ethers/src.ts/providers/formatting.ts
generated
vendored
Executable file
418
dev/env/node_modules/ethers/src.ts/providers/formatting.ts
generated
vendored
Executable file
@@ -0,0 +1,418 @@
|
||||
/**
|
||||
* About provider formatting?
|
||||
*
|
||||
* @_section: api/providers/formatting:Formatting [provider-formatting]
|
||||
*/
|
||||
|
||||
import type { Signature } from "../crypto/index.js";
|
||||
import type { Authorization, AccessList } from "../transaction/index.js";
|
||||
|
||||
|
||||
//////////////////////
|
||||
// Block
|
||||
|
||||
/**
|
||||
* a **BlockParams** encodes the minimal required properties for a
|
||||
* formatted block.
|
||||
*/
|
||||
export interface BlockParams {
|
||||
/**
|
||||
* The block hash.
|
||||
*/
|
||||
hash?: null | string;
|
||||
|
||||
/**
|
||||
* The block number.
|
||||
*/
|
||||
number: number;
|
||||
|
||||
/**
|
||||
* The timestamp for this block, which is the number of seconds
|
||||
* since epoch that this block was included.
|
||||
*/
|
||||
timestamp: number;
|
||||
|
||||
/**
|
||||
* The hash of the previous block in the blockchain. The genesis block
|
||||
* has the parentHash of the [[ZeroHash]].
|
||||
*/
|
||||
parentHash: string;
|
||||
|
||||
/**
|
||||
* The hash tree root of the parent beacon block for the given
|
||||
* execution block. See [[link-eip-4788]].
|
||||
*/
|
||||
parentBeaconBlockRoot?: null | string;
|
||||
|
||||
/**
|
||||
* A random sequence provided during the mining process for
|
||||
* proof-of-work networks.
|
||||
*/
|
||||
nonce: string;
|
||||
|
||||
/**
|
||||
* For proof-of-work networks, the difficulty target is used to
|
||||
* adjust the difficulty in mining to ensure an expected block rate.
|
||||
*/
|
||||
difficulty: bigint;
|
||||
|
||||
/**
|
||||
* The maximum amount of gas a block can consume.
|
||||
*/
|
||||
gasLimit: bigint;
|
||||
|
||||
/**
|
||||
* The amount of gas a block consumed.
|
||||
*/
|
||||
gasUsed: bigint;
|
||||
|
||||
/**
|
||||
* The total amount of BLOb gas consumed by transactions within
|
||||
* the block. See [[link-eip4844].
|
||||
*/
|
||||
blobGasUsed?: null | bigint;
|
||||
|
||||
/**
|
||||
* The running total of BLOb gas consumed in excess of the target
|
||||
* prior to the block. See [[link-eip-4844]].
|
||||
*/
|
||||
excessBlobGas?: null | bigint;
|
||||
|
||||
/**
|
||||
* The miner (or author) of a block.
|
||||
*/
|
||||
miner: string;
|
||||
|
||||
/**
|
||||
* The latest RANDAO mix of the post beacon state of
|
||||
* the previous block.
|
||||
*/
|
||||
prevRandao?: null | string;
|
||||
|
||||
/**
|
||||
* Additional data the miner choose to include.
|
||||
*/
|
||||
extraData: string;
|
||||
|
||||
/**
|
||||
* The protocol-defined base fee per gas in an [[link-eip-1559]]
|
||||
* block.
|
||||
*/
|
||||
baseFeePerGas: null | bigint;
|
||||
|
||||
/**
|
||||
* The root hash for the global state after applying changes
|
||||
* in this block.
|
||||
*/
|
||||
stateRoot?: null | string;
|
||||
|
||||
/**
|
||||
* The hash of the transaction receipts trie.
|
||||
*/
|
||||
receiptsRoot?: null | string;
|
||||
|
||||
/**
|
||||
* The list of transactions in the block.
|
||||
*/
|
||||
transactions: ReadonlyArray<string | TransactionResponseParams>;
|
||||
};
|
||||
|
||||
|
||||
//////////////////////
|
||||
// Log
|
||||
|
||||
/**
|
||||
* a **LogParams** encodes the minimal required properties for a
|
||||
* formatted log.
|
||||
*/
|
||||
export interface LogParams {
|
||||
/**
|
||||
* The transaction hash for the transaxction the log occurred in.
|
||||
*/
|
||||
transactionHash: string;
|
||||
|
||||
/**
|
||||
* The block hash of the block that included the transaction for this
|
||||
* log.
|
||||
*/
|
||||
blockHash: string;
|
||||
|
||||
/**
|
||||
* The block number of the block that included the transaction for this
|
||||
* log.
|
||||
*/
|
||||
blockNumber: number;
|
||||
|
||||
/**
|
||||
* Whether this log was removed due to the transaction it was included
|
||||
* in being removed dur to an orphaned block.
|
||||
*/
|
||||
removed: boolean;
|
||||
|
||||
/**
|
||||
* The address of the contract that emitted this log.
|
||||
*/
|
||||
address: string;
|
||||
|
||||
/**
|
||||
* The data emitted with this log.
|
||||
*/
|
||||
data: string;
|
||||
|
||||
/**
|
||||
* The topics emitted with this log.
|
||||
*/
|
||||
topics: ReadonlyArray<string>;
|
||||
|
||||
/**
|
||||
* The index of this log.
|
||||
*/
|
||||
index: number;
|
||||
|
||||
/**
|
||||
* The transaction index of this log.
|
||||
*/
|
||||
transactionIndex: number;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////
|
||||
// Transaction Receipt
|
||||
|
||||
/**
|
||||
* a **TransactionReceiptParams** encodes the minimal required properties
|
||||
* for a formatted transaction receipt.
|
||||
*/
|
||||
export interface TransactionReceiptParams {
|
||||
/**
|
||||
* The target of the transaction. If null, the transaction was trying
|
||||
* to deploy a transaction with the ``data`` as the initi=code.
|
||||
*/
|
||||
to: null | string;
|
||||
|
||||
/**
|
||||
* The sender of the transaction.
|
||||
*/
|
||||
from: string;
|
||||
|
||||
/**
|
||||
* If the transaction was directly deploying a contract, the [[to]]
|
||||
* will be null, the ``data`` will be initcode and if successful, this
|
||||
* will be the address of the contract deployed.
|
||||
*/
|
||||
contractAddress: null | string;
|
||||
|
||||
/**
|
||||
* The transaction hash.
|
||||
*/
|
||||
hash: string;
|
||||
|
||||
/**
|
||||
* The transaction index.
|
||||
*/
|
||||
index: number;
|
||||
|
||||
/**
|
||||
* The block hash of the block that included this transaction.
|
||||
*/
|
||||
blockHash: string;
|
||||
|
||||
/**
|
||||
* The block number of the block that included this transaction.
|
||||
*/
|
||||
blockNumber: number;
|
||||
|
||||
/**
|
||||
* The bloom filter for the logs emitted during execution of this
|
||||
* transaction.
|
||||
*/
|
||||
logsBloom: string;
|
||||
|
||||
/**
|
||||
* The logs emitted during the execution of this transaction.
|
||||
*/
|
||||
logs: ReadonlyArray<LogParams>;
|
||||
|
||||
/**
|
||||
* The amount of gas consumed executing this transaction.
|
||||
*/
|
||||
gasUsed: bigint;
|
||||
|
||||
/**
|
||||
* The amount of BLOb gas used. See [[link-eip-4844]].
|
||||
*/
|
||||
blobGasUsed?: null | bigint;
|
||||
|
||||
/**
|
||||
* The total amount of gas consumed during the entire block up to
|
||||
* and including this transaction.
|
||||
*/
|
||||
cumulativeGasUsed: bigint;
|
||||
|
||||
/**
|
||||
* The actual gas price per gas charged for this transaction.
|
||||
*/
|
||||
gasPrice?: null | bigint;
|
||||
|
||||
/**
|
||||
* The actual BLOb gas price that was charged. See [[link-eip-4844]].
|
||||
*/
|
||||
blobGasPrice?: null | bigint;
|
||||
|
||||
/**
|
||||
* The actual gas price per gas charged for this transaction.
|
||||
*/
|
||||
effectiveGasPrice?: null | bigint;
|
||||
|
||||
/**
|
||||
* The [[link-eip-2718]] envelope type.
|
||||
*/
|
||||
type: number;
|
||||
//byzantium: boolean;
|
||||
|
||||
/**
|
||||
* The status of the transaction execution. If ``1`` then the
|
||||
* the transaction returned success, if ``0`` then the transaction
|
||||
* was reverted. For pre-byzantium blocks, this is usually null, but
|
||||
* some nodes may have backfilled this data.
|
||||
*/
|
||||
status: null | number;
|
||||
|
||||
/**
|
||||
* The root of this transaction in a pre-bazatium block. In
|
||||
* post-byzantium blocks this is null.
|
||||
*/
|
||||
root: null | string;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
export interface LegacyTransactionReceipt {
|
||||
byzantium: false;
|
||||
status: null;
|
||||
root: string;
|
||||
}
|
||||
|
||||
export interface ByzantiumTransactionReceipt {
|
||||
byzantium: true;
|
||||
status: number;
|
||||
root: null;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
//////////////////////
|
||||
// Transaction Response
|
||||
|
||||
/**
|
||||
* a **TransactionResponseParams** encodes the minimal required properties
|
||||
* for a formatted transaction response.
|
||||
*/
|
||||
export interface TransactionResponseParams {
|
||||
/**
|
||||
* The block number of the block that included this transaction.
|
||||
*/
|
||||
blockNumber: null | number;
|
||||
|
||||
/**
|
||||
* The block hash of the block that included this transaction.
|
||||
*/
|
||||
blockHash: null | string;
|
||||
|
||||
/**
|
||||
* The transaction hash.
|
||||
*/
|
||||
hash: string;
|
||||
|
||||
/**
|
||||
* The transaction index.
|
||||
*/
|
||||
index: number;
|
||||
|
||||
/**
|
||||
* The [[link-eip-2718]] transaction type.
|
||||
*/
|
||||
type: number;
|
||||
|
||||
/**
|
||||
* The target of the transaction. If ``null``, the ``data`` is initcode
|
||||
* and this transaction is a deployment transaction.
|
||||
*/
|
||||
to: null | string;
|
||||
|
||||
/**
|
||||
* The sender of the transaction.
|
||||
*/
|
||||
from: string;
|
||||
|
||||
/**
|
||||
* The nonce of the transaction, used for replay protection.
|
||||
*/
|
||||
nonce: number;
|
||||
|
||||
/**
|
||||
* The maximum amount of gas this transaction is authorized to consume.
|
||||
*/
|
||||
gasLimit: bigint;
|
||||
|
||||
/**
|
||||
* For legacy transactions, this is the gas price per gas to pay.
|
||||
*/
|
||||
gasPrice: bigint;
|
||||
|
||||
/**
|
||||
* For [[link-eip-1559]] transactions, this is the maximum priority
|
||||
* fee to allow a producer to claim.
|
||||
*/
|
||||
maxPriorityFeePerGas: null | bigint;
|
||||
|
||||
/**
|
||||
* For [[link-eip-1559]] transactions, this is the maximum fee that
|
||||
* will be paid.
|
||||
*/
|
||||
maxFeePerGas: null | bigint;
|
||||
|
||||
/**
|
||||
* For [[link-eip-4844]] transactions, this is the maximum fee that
|
||||
* will be paid per BLOb.
|
||||
*/
|
||||
maxFeePerBlobGas?: null | bigint;
|
||||
|
||||
/**
|
||||
* The transaction data.
|
||||
*/
|
||||
data: string;
|
||||
|
||||
/**
|
||||
* The transaction value (in wei).
|
||||
*/
|
||||
value: bigint;
|
||||
|
||||
/**
|
||||
* The chain ID this transaction is valid on.
|
||||
*/
|
||||
chainId: bigint;
|
||||
|
||||
/**
|
||||
* The signature of the transaction.
|
||||
*/
|
||||
signature: Signature;
|
||||
|
||||
/**
|
||||
* The transaction access list.
|
||||
*/
|
||||
accessList: null | AccessList;
|
||||
|
||||
/**
|
||||
* The [[link-eip-4844]] BLOb versioned hashes.
|
||||
*/
|
||||
blobVersionedHashes?: null | Array<string>; // @TODO: drop the "?"? (v7)
|
||||
|
||||
/**
|
||||
* The [[link-eip-7702]] authorizations (if any).
|
||||
*/
|
||||
authorizationList: null | Array<Authorization>;
|
||||
};
|
||||
|
||||
|
||||
135
dev/env/node_modules/ethers/src.ts/providers/index.ts
generated
vendored
Executable file
135
dev/env/node_modules/ethers/src.ts/providers/index.ts
generated
vendored
Executable file
@@ -0,0 +1,135 @@
|
||||
/**
|
||||
* A **Provider** provides a connection to the blockchain, whch can be
|
||||
* used to query its current state, simulate execution and send transactions
|
||||
* to update the state.
|
||||
*
|
||||
* It is one of the most fundamental components of interacting with a
|
||||
* blockchain application, and there are many ways to connect, such as over
|
||||
* HTTP, WebSockets or injected providers such as [MetaMask](link-metamask).
|
||||
*
|
||||
* @_section: api/providers:Providers [about-providers]
|
||||
*/
|
||||
|
||||
|
||||
export {
|
||||
AbstractProvider, UnmanagedSubscriber
|
||||
} from "./abstract-provider.js";
|
||||
|
||||
export {
|
||||
AbstractSigner,
|
||||
VoidSigner,
|
||||
} from "./abstract-signer.js";
|
||||
|
||||
export {
|
||||
showThrottleMessage
|
||||
} from "./community.js";
|
||||
|
||||
export { getDefaultProvider } from "./default-provider.js";
|
||||
|
||||
export {
|
||||
EnsResolver,
|
||||
MulticoinProviderPlugin
|
||||
} from "./ens-resolver.js";
|
||||
|
||||
export { Network } from "./network.js";
|
||||
|
||||
export { NonceManager } from "./signer-noncemanager.js";
|
||||
|
||||
export {
|
||||
NetworkPlugin,
|
||||
GasCostPlugin,
|
||||
EnsPlugin,
|
||||
FeeDataNetworkPlugin,
|
||||
FetchUrlFeeDataNetworkPlugin,
|
||||
} from "./plugins-network.js";
|
||||
|
||||
export {
|
||||
Block,
|
||||
FeeData,
|
||||
Log,
|
||||
TransactionReceipt,
|
||||
TransactionResponse,
|
||||
|
||||
copyRequest,
|
||||
//resolveTransactionRequest,
|
||||
} from "./provider.js";
|
||||
|
||||
export { FallbackProvider } from "./provider-fallback.js";
|
||||
export { JsonRpcApiProvider, JsonRpcProvider, JsonRpcSigner } from "./provider-jsonrpc.js"
|
||||
|
||||
export { BrowserProvider } from "./provider-browser.js";
|
||||
|
||||
export { AlchemyProvider } from "./provider-alchemy.js";
|
||||
export { BlockscoutProvider } from "./provider-blockscout.js";
|
||||
export { AnkrProvider } from "./provider-ankr.js";
|
||||
export { CloudflareProvider } from "./provider-cloudflare.js";
|
||||
export { ChainstackProvider } from "./provider-chainstack.js";
|
||||
export { EtherscanProvider, EtherscanPlugin } from "./provider-etherscan.js";
|
||||
export { InfuraProvider, InfuraWebSocketProvider } from "./provider-infura.js";
|
||||
export { PocketProvider } from "./provider-pocket.js";
|
||||
export { QuickNodeProvider } from "./provider-quicknode.js";
|
||||
|
||||
import { IpcSocketProvider } from "./provider-ipcsocket.js"; /*-browser*/
|
||||
export { IpcSocketProvider };
|
||||
export { SocketProvider } from "./provider-socket.js";
|
||||
export { WebSocketProvider } from "./provider-websocket.js";
|
||||
|
||||
export {
|
||||
SocketSubscriber, SocketBlockSubscriber, SocketPendingSubscriber,
|
||||
SocketEventSubscriber
|
||||
} from "./provider-socket.js";
|
||||
|
||||
export type {
|
||||
AbstractProviderOptions, Subscription, Subscriber,
|
||||
AbstractProviderPlugin,
|
||||
PerformActionFilter, PerformActionTransaction, PerformActionRequest,
|
||||
} from "./abstract-provider.js"
|
||||
|
||||
export type { ContractRunner } from "./contracts.js";
|
||||
|
||||
export type {
|
||||
BlockParams, LogParams, TransactionReceiptParams,
|
||||
TransactionResponseParams,
|
||||
} from "./formatting.js";
|
||||
|
||||
export type {
|
||||
CommunityResourcable
|
||||
} from "./community.js";
|
||||
|
||||
/*
|
||||
export type {
|
||||
AvatarLinkageType, AvatarLinkage, AvatarResult
|
||||
} from "./ens-resolver.js";
|
||||
*/
|
||||
export type { Networkish } from "./network.js";
|
||||
|
||||
export type { GasCostParameters } from "./plugins-network.js";
|
||||
|
||||
export type {
|
||||
BlockTag,
|
||||
TransactionRequest, PreparedTransactionRequest,
|
||||
EventFilter, Filter, FilterByBlockHash, OrphanFilter, ProviderEvent,
|
||||
TopicFilter,
|
||||
Provider,
|
||||
MinedBlock, MinedTransactionResponse
|
||||
} from "./provider.js";
|
||||
|
||||
export type {
|
||||
BrowserDiscoverOptions, BrowserProviderOptions, DebugEventBrowserProvider,
|
||||
Eip1193Provider, Eip6963ProviderInfo
|
||||
} from "./provider-browser.js";
|
||||
|
||||
export type { FallbackProviderOptions } from "./provider-fallback.js";
|
||||
|
||||
export type {
|
||||
JsonRpcPayload, JsonRpcResult, JsonRpcError,
|
||||
JsonRpcApiProviderOptions,
|
||||
JsonRpcTransactionRequest,
|
||||
} from "./provider-jsonrpc.js";
|
||||
|
||||
export type {
|
||||
WebSocketCreator, WebSocketLike
|
||||
} from "./provider-websocket.js";
|
||||
|
||||
export type { Signer } from "./signer.js";
|
||||
|
||||
438
dev/env/node_modules/ethers/src.ts/providers/network.ts
generated
vendored
Executable file
438
dev/env/node_modules/ethers/src.ts/providers/network.ts
generated
vendored
Executable file
@@ -0,0 +1,438 @@
|
||||
/**
|
||||
* A **Network** encapsulates the various properties required to
|
||||
* interact with a specific chain.
|
||||
*
|
||||
* @_subsection: api/providers:Networks [networks]
|
||||
*/
|
||||
|
||||
import { accessListify } from "../transaction/index.js";
|
||||
import { getBigInt, assert, assertArgument } from "../utils/index.js";
|
||||
|
||||
import {
|
||||
EnsPlugin, FetchUrlFeeDataNetworkPlugin, GasCostPlugin
|
||||
} from "./plugins-network.js";
|
||||
|
||||
import type { BigNumberish } from "../utils/index.js";
|
||||
import type { TransactionLike } from "../transaction/index.js";
|
||||
|
||||
import type { NetworkPlugin } from "./plugins-network.js";
|
||||
|
||||
|
||||
/**
|
||||
* A Networkish can be used to allude to a Network, by specifing:
|
||||
* - a [[Network]] object
|
||||
* - a well-known (or registered) network name
|
||||
* - a well-known (or registered) chain ID
|
||||
* - an object with sufficient details to describe a network
|
||||
*/
|
||||
export type Networkish = Network | number | bigint | string | {
|
||||
name?: string,
|
||||
chainId?: number,
|
||||
//layerOneConnection?: Provider,
|
||||
ensAddress?: string,
|
||||
ensNetwork?: number
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/* * * *
|
||||
// Networks which operation against an L2 can use this plugin to
|
||||
// specify how to access L1, for the purpose of resolving ENS,
|
||||
// for example.
|
||||
export class LayerOneConnectionPlugin extends NetworkPlugin {
|
||||
readonly provider!: Provider;
|
||||
// @TODO: Rename to ChainAccess and allow for connecting to any chain
|
||||
constructor(provider: Provider) {
|
||||
super("org.ethers.plugins.layer-one-connection");
|
||||
defineProperties<LayerOneConnectionPlugin>(this, { provider });
|
||||
}
|
||||
|
||||
clone(): LayerOneConnectionPlugin {
|
||||
return new LayerOneConnectionPlugin(this.provider);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
const Networks: Map<string | bigint, () => Network> = new Map();
|
||||
|
||||
|
||||
/**
|
||||
* A **Network** provides access to a chain's properties and allows
|
||||
* for plug-ins to extend functionality.
|
||||
*/
|
||||
export class Network {
|
||||
#name: string;
|
||||
#chainId: bigint;
|
||||
|
||||
#plugins: Map<string, NetworkPlugin>;
|
||||
|
||||
/**
|
||||
* Creates a new **Network** for %%name%% and %%chainId%%.
|
||||
*/
|
||||
constructor(name: string, chainId: BigNumberish) {
|
||||
this.#name = name;
|
||||
this.#chainId = getBigInt(chainId);
|
||||
this.#plugins = new Map();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JSON-compatible representation of a Network.
|
||||
*/
|
||||
toJSON(): any {
|
||||
return { name: this.name, chainId: String(this.chainId) };
|
||||
}
|
||||
|
||||
/**
|
||||
* The network common name.
|
||||
*
|
||||
* This is the canonical name, as networks migh have multiple
|
||||
* names.
|
||||
*/
|
||||
get name(): string { return this.#name; }
|
||||
set name(value: string) { this.#name = value; }
|
||||
|
||||
/**
|
||||
* The network chain ID.
|
||||
*/
|
||||
get chainId(): bigint { return this.#chainId; }
|
||||
set chainId(value: BigNumberish) { this.#chainId = getBigInt(value, "chainId"); }
|
||||
|
||||
/**
|
||||
* Returns true if %%other%% matches this network. Any chain ID
|
||||
* must match, and if no chain ID is present, the name must match.
|
||||
*
|
||||
* This method does not currently check for additional properties,
|
||||
* such as ENS address or plug-in compatibility.
|
||||
*/
|
||||
matches(other: Networkish): boolean {
|
||||
if (other == null) { return false; }
|
||||
|
||||
if (typeof(other) === "string") {
|
||||
try {
|
||||
return (this.chainId === getBigInt(other));
|
||||
} catch (error) { }
|
||||
return (this.name === other);
|
||||
}
|
||||
|
||||
if (typeof(other) === "number" || typeof(other) === "bigint") {
|
||||
try {
|
||||
return (this.chainId === getBigInt(other));
|
||||
} catch (error) { }
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof(other) === "object") {
|
||||
if (other.chainId != null) {
|
||||
try {
|
||||
return (this.chainId === getBigInt(other.chainId));
|
||||
} catch (error) { }
|
||||
return false;
|
||||
}
|
||||
if (other.name != null) {
|
||||
return (this.name === other.name);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of plugins currently attached to this Network.
|
||||
*/
|
||||
get plugins(): Array<NetworkPlugin> {
|
||||
return Array.from(this.#plugins.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach a new %%plugin%% to this Network. The network name
|
||||
* must be unique, excluding any fragment.
|
||||
*/
|
||||
attachPlugin(plugin: NetworkPlugin): this {
|
||||
if (this.#plugins.get(plugin.name)) {
|
||||
throw new Error(`cannot replace existing plugin: ${ plugin.name } `);
|
||||
}
|
||||
this.#plugins.set(plugin.name, plugin.clone());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the plugin, if any, matching %%name%% exactly. Plugins
|
||||
* with fragments will not be returned unless %%name%% includes
|
||||
* a fragment.
|
||||
*/
|
||||
getPlugin<T extends NetworkPlugin = NetworkPlugin>(name: string): null | T {
|
||||
return <T>(this.#plugins.get(name)) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of all plugins that match %%name%%, with otr without
|
||||
* a fragment.
|
||||
*/
|
||||
getPlugins<T extends NetworkPlugin = NetworkPlugin>(basename: string): Array<T> {
|
||||
return <Array<T>>(this.plugins.filter((p) => (p.name.split("#")[0] === basename)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of this Network.
|
||||
*/
|
||||
clone(): Network {
|
||||
const clone = new Network(this.name, this.chainId);
|
||||
this.plugins.forEach((plugin) => {
|
||||
clone.attachPlugin(plugin.clone());
|
||||
});
|
||||
return clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the intrinsic gas required for a transaction.
|
||||
*
|
||||
* A GasCostPlugin can be attached to override the default
|
||||
* values.
|
||||
*/
|
||||
computeIntrinsicGas(tx: TransactionLike): number {
|
||||
const costs = this.getPlugin<GasCostPlugin>("org.ethers.plugins.network.GasCost") || (new GasCostPlugin());
|
||||
|
||||
let gas = costs.txBase;
|
||||
if (tx.to == null) { gas += costs.txCreate; }
|
||||
if (tx.data) {
|
||||
for (let i = 2; i < tx.data.length; i += 2) {
|
||||
if (tx.data.substring(i, i + 2) === "00") {
|
||||
gas += costs.txDataZero;
|
||||
} else {
|
||||
gas += costs.txDataNonzero;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tx.accessList) {
|
||||
const accessList = accessListify(tx.accessList);
|
||||
for (const addr in accessList) {
|
||||
gas += costs.txAccessListAddress + costs.txAccessListStorageKey * accessList[addr].storageKeys.length;
|
||||
}
|
||||
}
|
||||
|
||||
return gas;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new Network for the %%network%% name or chainId.
|
||||
*/
|
||||
static from(network?: Networkish): Network {
|
||||
injectCommonNetworks();
|
||||
|
||||
// Default network
|
||||
if (network == null) { return Network.from("mainnet"); }
|
||||
|
||||
// Canonical name or chain ID
|
||||
if (typeof(network) === "number") { network = BigInt(network); }
|
||||
if (typeof(network) === "string" || typeof(network) === "bigint") {
|
||||
const networkFunc = Networks.get(network);
|
||||
if (networkFunc) { return networkFunc(); }
|
||||
if (typeof(network) === "bigint") {
|
||||
return new Network("unknown", network);
|
||||
}
|
||||
|
||||
assertArgument(false, "unknown network", "network", network);
|
||||
}
|
||||
|
||||
// Clonable with network-like abilities
|
||||
if (typeof((<Network>network).clone) === "function") {
|
||||
const clone = (<Network>network).clone();
|
||||
//if (typeof(network.name) !== "string" || typeof(network.chainId) !== "number") {
|
||||
//}
|
||||
return clone;
|
||||
}
|
||||
|
||||
// Networkish
|
||||
if (typeof(network) === "object") {
|
||||
assertArgument(typeof(network.name) === "string" && typeof(network.chainId) === "number",
|
||||
"invalid network object name or chainId", "network", network);
|
||||
|
||||
const custom = new Network(<string>(network.name), <number>(network.chainId));
|
||||
|
||||
if ((<any>network).ensAddress || (<any>network).ensNetwork != null) {
|
||||
custom.attachPlugin(new EnsPlugin((<any>network).ensAddress, (<any>network).ensNetwork));
|
||||
}
|
||||
|
||||
//if ((<any>network).layerOneConnection) {
|
||||
// custom.attachPlugin(new LayerOneConnectionPlugin((<any>network).layerOneConnection));
|
||||
//}
|
||||
|
||||
return custom;
|
||||
}
|
||||
|
||||
assertArgument(false, "invalid network", "network", network);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register %%nameOrChainId%% with a function which returns
|
||||
* an instance of a Network representing that chain.
|
||||
*/
|
||||
static register(nameOrChainId: string | number | bigint, networkFunc: () => Network): void {
|
||||
if (typeof(nameOrChainId) === "number") { nameOrChainId = BigInt(nameOrChainId); }
|
||||
const existing = Networks.get(nameOrChainId);
|
||||
if (existing) {
|
||||
assertArgument(false, `conflicting network for ${ JSON.stringify(existing.name) }`, "nameOrChainId", nameOrChainId);
|
||||
}
|
||||
Networks.set(nameOrChainId, networkFunc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
type Options = {
|
||||
ensNetwork?: number;
|
||||
altNames?: Array<string>;
|
||||
plugins?: Array<NetworkPlugin>;
|
||||
};
|
||||
|
||||
// We don't want to bring in formatUnits because it is backed by
|
||||
// FixedNumber and we want to keep Networks tiny. The values
|
||||
// included by the Gas Stations are also IEEE 754 with lots of
|
||||
// rounding issues and exceed the strict checks formatUnits has.
|
||||
function parseUnits(_value: number | string, decimals: number): bigint {
|
||||
const value = String(_value);
|
||||
if (!value.match(/^[0-9.]+$/)) {
|
||||
throw new Error(`invalid gwei value: ${ _value }`);
|
||||
}
|
||||
|
||||
// Break into [ whole, fraction ]
|
||||
const comps = value.split(".");
|
||||
if (comps.length === 1) { comps.push(""); }
|
||||
|
||||
// More than 1 decimal point or too many fractional positions
|
||||
if (comps.length !== 2) {
|
||||
throw new Error(`invalid gwei value: ${ _value }`);
|
||||
}
|
||||
|
||||
// Pad the fraction to 9 decimalplaces
|
||||
while (comps[1].length < decimals) { comps[1] += "0"; }
|
||||
|
||||
// Too many decimals and some non-zero ending, take the ceiling
|
||||
if (comps[1].length > 9) {
|
||||
let frac = BigInt(comps[1].substring(0, 9));
|
||||
if (!comps[1].substring(9).match(/^0+$/)) { frac++; }
|
||||
comps[1] = frac.toString();
|
||||
}
|
||||
|
||||
return BigInt(comps[0] + comps[1]);
|
||||
}
|
||||
|
||||
// Used by Polygon to use a gas station for fee data
|
||||
function getGasStationPlugin(url: string) {
|
||||
return new FetchUrlFeeDataNetworkPlugin(url, async (fetchFeeData, provider, request) => {
|
||||
|
||||
// Prevent Cloudflare from blocking our request in node.js
|
||||
request.setHeader("User-Agent", "ethers");
|
||||
|
||||
let response;
|
||||
try {
|
||||
const [ _response, _feeData ] = await Promise.all([
|
||||
request.send(), fetchFeeData()
|
||||
]);
|
||||
response = _response;
|
||||
const payload = response.bodyJson.standard;
|
||||
const feeData = {
|
||||
gasPrice: _feeData.gasPrice,
|
||||
maxFeePerGas: parseUnits(payload.maxFee, 9),
|
||||
maxPriorityFeePerGas: parseUnits(payload.maxPriorityFee, 9),
|
||||
};
|
||||
return feeData;
|
||||
} catch (error: any) {
|
||||
assert(false, `error encountered with polygon gas station (${ JSON.stringify(request.url) })`, "SERVER_ERROR", { request, response, error });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// See: https://chainlist.org
|
||||
let injected = false;
|
||||
function injectCommonNetworks(): void {
|
||||
if (injected) { return; }
|
||||
injected = true;
|
||||
|
||||
/// Register popular Ethereum networks
|
||||
function registerEth(name: string, chainId: number, options: Options): void {
|
||||
const func = function() {
|
||||
const network = new Network(name, chainId);
|
||||
|
||||
// We use 0 to disable ENS
|
||||
if (options.ensNetwork != null) {
|
||||
network.attachPlugin(new EnsPlugin(null, options.ensNetwork));
|
||||
}
|
||||
|
||||
network.attachPlugin(new GasCostPlugin());
|
||||
|
||||
(options.plugins || []).forEach((plugin) => {
|
||||
network.attachPlugin(plugin);
|
||||
});
|
||||
|
||||
return network;
|
||||
};
|
||||
|
||||
// Register the network by name and chain ID
|
||||
Network.register(name, func);
|
||||
Network.register(chainId, func);
|
||||
|
||||
if (options.altNames) {
|
||||
options.altNames.forEach((name) => {
|
||||
Network.register(name, func);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
registerEth("mainnet", 1, { ensNetwork: 1, altNames: [ "homestead" ] });
|
||||
registerEth("ropsten", 3, { ensNetwork: 3 });
|
||||
registerEth("rinkeby", 4, { ensNetwork: 4 });
|
||||
registerEth("goerli", 5, { ensNetwork: 5 });
|
||||
registerEth("kovan", 42, { ensNetwork: 42 });
|
||||
registerEth("sepolia", 11155111, { ensNetwork: 11155111 });
|
||||
registerEth("holesky", 17000, { ensNetwork: 17000 });
|
||||
|
||||
registerEth("classic", 61, { });
|
||||
registerEth("classicKotti", 6, { });
|
||||
|
||||
registerEth("arbitrum", 42161, {
|
||||
ensNetwork: 1,
|
||||
});
|
||||
registerEth("arbitrum-goerli", 421613, { });
|
||||
registerEth("arbitrum-sepolia", 421614, { });
|
||||
|
||||
registerEth("base", 8453, { ensNetwork: 1 });
|
||||
registerEth("base-goerli", 84531, { });
|
||||
registerEth("base-sepolia", 84532, { });
|
||||
|
||||
registerEth("bnb", 56, { ensNetwork: 1 });
|
||||
registerEth("bnbt", 97, { });
|
||||
|
||||
registerEth("filecoin", 314, { });
|
||||
registerEth("filecoin-calibration", 314159, { });
|
||||
|
||||
registerEth("linea", 59144, { ensNetwork: 1 });
|
||||
registerEth("linea-goerli", 59140, { });
|
||||
registerEth("linea-sepolia", 59141, { });
|
||||
|
||||
registerEth("matic", 137, {
|
||||
ensNetwork: 1,
|
||||
plugins: [
|
||||
getGasStationPlugin("https:/\/gasstation.polygon.technology/v2")
|
||||
]
|
||||
});
|
||||
registerEth("matic-amoy", 80002, { });
|
||||
registerEth("matic-mumbai", 80001, {
|
||||
altNames: [ "maticMumbai", "maticmum" ], // @TODO: Future remove these alts
|
||||
plugins: [
|
||||
getGasStationPlugin("https:/\/gasstation-testnet.polygon.technology/v2")
|
||||
]
|
||||
});
|
||||
|
||||
registerEth("optimism", 10, {
|
||||
ensNetwork: 1,
|
||||
plugins: [ ]
|
||||
});
|
||||
registerEth("optimism-goerli", 420, { });
|
||||
registerEth("optimism-sepolia", 11155420, { });
|
||||
|
||||
registerEth("xdai", 100, { ensNetwork: 1 });
|
||||
}
|
||||
8
dev/env/node_modules/ethers/src.ts/providers/pagination.ts
generated
vendored
Executable file
8
dev/env/node_modules/ethers/src.ts/providers/pagination.ts
generated
vendored
Executable file
@@ -0,0 +1,8 @@
|
||||
export interface PaginationResult<R> extends Array<R> {
|
||||
next(): Promise<PaginationResult<R>>;
|
||||
|
||||
// The total number of results available or null if unknown
|
||||
totalResults: null | number;
|
||||
|
||||
done: boolean;
|
||||
}
|
||||
35
dev/env/node_modules/ethers/src.ts/providers/plugin-fallback.ts
generated
vendored
Executable file
35
dev/env/node_modules/ethers/src.ts/providers/plugin-fallback.ts
generated
vendored
Executable file
@@ -0,0 +1,35 @@
|
||||
|
||||
import { AbstractProviderPlugin } from "./abstract-provider.js";
|
||||
import { defineProperties } from "../utils/index.js";
|
||||
|
||||
import type { AbstractProvider, PerformActionRequest } from "./abstract-provider.js";
|
||||
|
||||
|
||||
export const PluginIdFallbackProvider = "org.ethers.plugins.provider.QualifiedPlugin";
|
||||
|
||||
export class CheckQualifiedPlugin implements AbstractProviderPlugin {
|
||||
declare name: string;
|
||||
|
||||
constructor() {
|
||||
defineProperties<CheckQualifiedPlugin>(this, { name: PluginIdFallbackProvider });
|
||||
}
|
||||
|
||||
connect(provider: AbstractProvider): CheckQualifiedPlugin {
|
||||
return this;
|
||||
}
|
||||
|
||||
// Retruns true if this value should be considered qualified for
|
||||
// inclusion in the quorum.
|
||||
isQualified(action: PerformActionRequest, result: any): boolean {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export class PossiblyPrunedTransactionPlugin extends CheckQualifiedPlugin {
|
||||
isQualified(action: PerformActionRequest, result: any): boolean {
|
||||
if (action.method === "getTransaction" || action.method === "getTransactionReceipt") {
|
||||
if (result == null) { return false; }
|
||||
}
|
||||
return super.isQualified(action, result);
|
||||
}
|
||||
}
|
||||
281
dev/env/node_modules/ethers/src.ts/providers/plugins-network.ts
generated
vendored
Executable file
281
dev/env/node_modules/ethers/src.ts/providers/plugins-network.ts
generated
vendored
Executable file
@@ -0,0 +1,281 @@
|
||||
import { defineProperties } from "../utils/properties.js";
|
||||
|
||||
import { assertArgument } from "../utils/index.js";
|
||||
|
||||
import type { FeeData, Provider } from "./provider.js";
|
||||
import type { FetchRequest } from "../utils/fetch.js";
|
||||
|
||||
|
||||
const EnsAddress = "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e";
|
||||
|
||||
/**
|
||||
* A **NetworkPlugin** provides additional functionality on a [[Network]].
|
||||
*/
|
||||
export class NetworkPlugin {
|
||||
/**
|
||||
* The name of the plugin.
|
||||
*
|
||||
* It is recommended to use reverse-domain-notation, which permits
|
||||
* unique names with a known authority as well as hierarchal entries.
|
||||
*/
|
||||
readonly name!: string;
|
||||
|
||||
/**
|
||||
* Creates a new **NetworkPlugin**.
|
||||
*/
|
||||
constructor(name: string) {
|
||||
defineProperties<NetworkPlugin>(this, { name });
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a copy of this plugin.
|
||||
*/
|
||||
clone(): NetworkPlugin {
|
||||
return new NetworkPlugin(this.name);
|
||||
}
|
||||
|
||||
// validate(network: Network): NetworkPlugin {
|
||||
// return this;
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The gas cost parameters for a [[GasCostPlugin]].
|
||||
*/
|
||||
export type GasCostParameters = {
|
||||
/**
|
||||
* The transactions base fee.
|
||||
*/
|
||||
txBase?: number;
|
||||
|
||||
/**
|
||||
* The fee for creating a new account.
|
||||
*/
|
||||
txCreate?: number;
|
||||
|
||||
/**
|
||||
* The fee per zero-byte in the data.
|
||||
*/
|
||||
txDataZero?: number;
|
||||
|
||||
/**
|
||||
* The fee per non-zero-byte in the data.
|
||||
*/
|
||||
txDataNonzero?: number;
|
||||
|
||||
/**
|
||||
* The fee per storage key in the [[link-eip-2930]] access list.
|
||||
*/
|
||||
txAccessListStorageKey?: number;
|
||||
|
||||
/**
|
||||
* The fee per address in the [[link-eip-2930]] access list.
|
||||
*/
|
||||
txAccessListAddress?: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* A **GasCostPlugin** allows a network to provide alternative values when
|
||||
* computing the intrinsic gas required for a transaction.
|
||||
*/
|
||||
export class GasCostPlugin extends NetworkPlugin implements GasCostParameters {
|
||||
/**
|
||||
* The block number to treat these values as valid from.
|
||||
*
|
||||
* This allows a hardfork to have updated values included as well as
|
||||
* mulutiple hardforks to be supported.
|
||||
*/
|
||||
readonly effectiveBlock!: number;
|
||||
|
||||
/**
|
||||
* The transactions base fee.
|
||||
*/
|
||||
readonly txBase!: number;
|
||||
|
||||
/**
|
||||
* The fee for creating a new account.
|
||||
*/
|
||||
readonly txCreate!: number;
|
||||
|
||||
/**
|
||||
* The fee per zero-byte in the data.
|
||||
*/
|
||||
readonly txDataZero!: number;
|
||||
|
||||
/**
|
||||
* The fee per non-zero-byte in the data.
|
||||
*/
|
||||
readonly txDataNonzero!: number;
|
||||
|
||||
/**
|
||||
* The fee per storage key in the [[link-eip-2930]] access list.
|
||||
*/
|
||||
readonly txAccessListStorageKey!: number;
|
||||
|
||||
/**
|
||||
* The fee per address in the [[link-eip-2930]] access list.
|
||||
*/
|
||||
readonly txAccessListAddress!: number;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new GasCostPlugin from %%effectiveBlock%% until the
|
||||
* latest block or another GasCostPlugin supercedes that block number,
|
||||
* with the associated %%costs%%.
|
||||
*/
|
||||
constructor(effectiveBlock?: number, costs?: GasCostParameters) {
|
||||
if (effectiveBlock == null) { effectiveBlock = 0; }
|
||||
super(`org.ethers.network.plugins.GasCost#${ (effectiveBlock || 0) }`);
|
||||
|
||||
const props: Record<string, number> = { effectiveBlock };
|
||||
function set(name: keyof GasCostParameters, nullish: number): void {
|
||||
let value = (costs || { })[name];
|
||||
if (value == null) { value = nullish; }
|
||||
assertArgument(typeof(value) === "number", `invalud value for ${ name }`, "costs", costs);
|
||||
props[name] = value;
|
||||
}
|
||||
|
||||
set("txBase", 21000);
|
||||
set("txCreate", 32000);
|
||||
set("txDataZero", 4);
|
||||
set("txDataNonzero", 16);
|
||||
set("txAccessListStorageKey", 1900);
|
||||
set("txAccessListAddress", 2400);
|
||||
|
||||
defineProperties<GasCostPlugin>(this, props);
|
||||
}
|
||||
|
||||
clone(): GasCostPlugin {
|
||||
return new GasCostPlugin(this.effectiveBlock, this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An **EnsPlugin** allows a [[Network]] to specify the ENS Registry
|
||||
* Contract address and the target network to use when using that
|
||||
* contract.
|
||||
*
|
||||
* Various testnets have their own instance of the contract to use, but
|
||||
* in general, the mainnet instance supports multi-chain addresses and
|
||||
* should be used.
|
||||
*/
|
||||
export class EnsPlugin extends NetworkPlugin {
|
||||
|
||||
/**
|
||||
* The ENS Registrty Contract address.
|
||||
*/
|
||||
readonly address!: string;
|
||||
|
||||
/**
|
||||
* The chain ID that the ENS contract lives on.
|
||||
*/
|
||||
readonly targetNetwork!: number;
|
||||
|
||||
/**
|
||||
* Creates a new **EnsPlugin** connected to %%address%% on the
|
||||
* %%targetNetwork%%. The default ENS address and mainnet is used
|
||||
* if unspecified.
|
||||
*/
|
||||
constructor(address?: null | string, targetNetwork?: null | number) {
|
||||
super("org.ethers.plugins.network.Ens");
|
||||
defineProperties<EnsPlugin>(this, {
|
||||
address: (address || EnsAddress),
|
||||
targetNetwork: ((targetNetwork == null) ? 1: targetNetwork)
|
||||
});
|
||||
}
|
||||
|
||||
clone(): EnsPlugin {
|
||||
return new EnsPlugin(this.address, this.targetNetwork);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A **FeeDataNetworkPlugin** allows a network to provide and alternate
|
||||
* means to specify its fee data.
|
||||
*
|
||||
* For example, a network which does not support [[link-eip-1559]] may
|
||||
* choose to use a Gas Station site to approximate the gas price.
|
||||
*/
|
||||
export class FeeDataNetworkPlugin extends NetworkPlugin {
|
||||
readonly #feeDataFunc: (provider: Provider) => Promise<FeeData>;
|
||||
|
||||
/**
|
||||
* The fee data function provided to the constructor.
|
||||
*/
|
||||
get feeDataFunc(): (provider: Provider) => Promise<FeeData> {
|
||||
return this.#feeDataFunc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new **FeeDataNetworkPlugin**.
|
||||
*/
|
||||
constructor(feeDataFunc: (provider: Provider) => Promise<FeeData>) {
|
||||
super("org.ethers.plugins.network.FeeData");
|
||||
this.#feeDataFunc = feeDataFunc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to the fee data.
|
||||
*/
|
||||
async getFeeData(provider: Provider): Promise<FeeData> {
|
||||
return await this.#feeDataFunc(provider);
|
||||
}
|
||||
|
||||
clone(): FeeDataNetworkPlugin {
|
||||
return new FeeDataNetworkPlugin(this.#feeDataFunc);
|
||||
}
|
||||
}
|
||||
|
||||
export class FetchUrlFeeDataNetworkPlugin extends NetworkPlugin {
|
||||
readonly #url: string;
|
||||
readonly #processFunc: (f: () => Promise<FeeData>, p: Provider, r: FetchRequest) => Promise<{ gasPrice?: null | bigint, maxFeePerGas?: null | bigint, maxPriorityFeePerGas?: null | bigint }>;
|
||||
|
||||
/**
|
||||
* The URL to initialize the FetchRequest with in %%processFunc%%.
|
||||
*/
|
||||
get url(): string { return this.#url; }
|
||||
|
||||
/**
|
||||
* The callback to use when computing the FeeData.
|
||||
*/
|
||||
get processFunc(): (f: () => Promise<FeeData>, p: Provider, r: FetchRequest) => Promise<{ gasPrice?: null | bigint, maxFeePerGas?: null | bigint, maxPriorityFeePerGas?: null | bigint }> { return this.#processFunc; }
|
||||
|
||||
/**
|
||||
* Creates a new **FetchUrlFeeDataNetworkPlugin** which will
|
||||
* be used when computing the fee data for the network.
|
||||
*/
|
||||
constructor(url: string, processFunc: (f: () => Promise<FeeData>, p: Provider, r: FetchRequest) => Promise<{ gasPrice?: null | bigint, maxFeePerGas?: null | bigint, maxPriorityFeePerGas?: null | bigint }>) {
|
||||
super("org.ethers.plugins.network.FetchUrlFeeDataPlugin");
|
||||
this.#url = url;
|
||||
this.#processFunc = processFunc;
|
||||
}
|
||||
|
||||
// We are immutable, so we can serve as our own clone
|
||||
clone(): FetchUrlFeeDataNetworkPlugin { return this; }
|
||||
}
|
||||
|
||||
/*
|
||||
export class CustomBlockNetworkPlugin extends NetworkPlugin {
|
||||
readonly #blockFunc: (provider: Provider, block: BlockParams<string>) => Block<string>;
|
||||
readonly #blockWithTxsFunc: (provider: Provider, block: BlockParams<TransactionResponseParams>) => Block<TransactionResponse>;
|
||||
|
||||
constructor(blockFunc: (provider: Provider, block: BlockParams<string>) => Block<string>, blockWithTxsFunc: (provider: Provider, block: BlockParams<TransactionResponseParams>) => Block<TransactionResponse>) {
|
||||
super("org.ethers.network-plugins.custom-block");
|
||||
this.#blockFunc = blockFunc;
|
||||
this.#blockWithTxsFunc = blockWithTxsFunc;
|
||||
}
|
||||
|
||||
async getBlock(provider: Provider, block: BlockParams<string>): Promise<Block<string>> {
|
||||
return await this.#blockFunc(provider, block);
|
||||
}
|
||||
|
||||
async getBlockions(provider: Provider, block: BlockParams<TransactionResponseParams>): Promise<Block<TransactionResponse>> {
|
||||
return await this.#blockWithTxsFunc(provider, block);
|
||||
}
|
||||
|
||||
clone(): CustomBlockNetworkPlugin {
|
||||
return new CustomBlockNetworkPlugin(this.#blockFunc, this.#blockWithTxsFunc);
|
||||
}
|
||||
}
|
||||
*/
|
||||
166
dev/env/node_modules/ethers/src.ts/providers/provider-alchemy.ts
generated
vendored
Executable file
166
dev/env/node_modules/ethers/src.ts/providers/provider-alchemy.ts
generated
vendored
Executable file
@@ -0,0 +1,166 @@
|
||||
/**
|
||||
* [[link-alchemy]] provides a third-party service for connecting to
|
||||
* various blockchains over JSON-RPC.
|
||||
*
|
||||
* **Supported Networks**
|
||||
*
|
||||
* - Ethereum Mainnet (``mainnet``)
|
||||
* - Goerli Testnet (``goerli``)
|
||||
* - Sepolia Testnet (``sepolia``)
|
||||
* - Arbitrum (``arbitrum``)
|
||||
* - Arbitrum Goerli Testnet (``arbitrum-goerli``)
|
||||
* - Arbitrum Sepolia Testnet (``arbitrum-sepolia``)
|
||||
* - Base (``base``)
|
||||
* - Base Goerlia Testnet (``base-goerli``)
|
||||
* - Base Sepolia Testnet (``base-sepolia``)
|
||||
* - Optimism (``optimism``)
|
||||
* - Optimism Goerli Testnet (``optimism-goerli``)
|
||||
* - Optimism Sepolia Testnet (``optimism-sepolia``)
|
||||
* - Polygon (``matic``)
|
||||
* - Polygon Amoy Testnet (``matic-amoy``)
|
||||
* - Polygon Mumbai Testnet (``matic-mumbai``)
|
||||
*
|
||||
* @_subsection: api/providers/thirdparty:Alchemy [providers-alchemy]
|
||||
*/
|
||||
|
||||
import {
|
||||
defineProperties, resolveProperties, assert, assertArgument,
|
||||
FetchRequest
|
||||
} from "../utils/index.js";
|
||||
|
||||
import { showThrottleMessage } from "./community.js";
|
||||
import { Network } from "./network.js";
|
||||
import { JsonRpcProvider } from "./provider-jsonrpc.js";
|
||||
|
||||
import type { AbstractProvider, PerformActionRequest } from "./abstract-provider.js";
|
||||
import type { CommunityResourcable } from "./community.js";
|
||||
import type { Networkish } from "./network.js";
|
||||
|
||||
|
||||
const defaultApiKey = "_gg7wSSi0KMBsdKnGVfHDueq6xMB9EkC"
|
||||
|
||||
function getHost(name: string): string {
|
||||
switch(name) {
|
||||
case "mainnet":
|
||||
return "eth-mainnet.g.alchemy.com";
|
||||
case "goerli":
|
||||
return "eth-goerli.g.alchemy.com";
|
||||
case "sepolia":
|
||||
return "eth-sepolia.g.alchemy.com";
|
||||
|
||||
case "arbitrum":
|
||||
return "arb-mainnet.g.alchemy.com";
|
||||
case "arbitrum-goerli":
|
||||
return "arb-goerli.g.alchemy.com";
|
||||
case "arbitrum-sepolia":
|
||||
return "arb-sepolia.g.alchemy.com";
|
||||
case "base":
|
||||
return "base-mainnet.g.alchemy.com";
|
||||
case "base-goerli":
|
||||
return "base-goerli.g.alchemy.com";
|
||||
case "base-sepolia":
|
||||
return "base-sepolia.g.alchemy.com";
|
||||
case "matic":
|
||||
return "polygon-mainnet.g.alchemy.com";
|
||||
case "matic-amoy":
|
||||
return "polygon-amoy.g.alchemy.com";
|
||||
case "matic-mumbai":
|
||||
return "polygon-mumbai.g.alchemy.com";
|
||||
case "optimism":
|
||||
return "opt-mainnet.g.alchemy.com";
|
||||
case "optimism-goerli":
|
||||
return "opt-goerli.g.alchemy.com";
|
||||
case "optimism-sepolia":
|
||||
return "opt-sepolia.g.alchemy.com";
|
||||
}
|
||||
|
||||
assertArgument(false, "unsupported network", "network", name);
|
||||
}
|
||||
|
||||
/**
|
||||
* The **AlchemyProvider** connects to the [[link-alchemy]]
|
||||
* JSON-RPC end-points.
|
||||
*
|
||||
* By default, a highly-throttled API key is used, which is
|
||||
* appropriate for quick prototypes and simple scripts. To
|
||||
* gain access to an increased rate-limit, it is highly
|
||||
* recommended to [sign up here](link-alchemy-signup).
|
||||
*
|
||||
* @_docloc: api/providers/thirdparty
|
||||
*/
|
||||
export class AlchemyProvider extends JsonRpcProvider implements CommunityResourcable {
|
||||
readonly apiKey!: string;
|
||||
|
||||
constructor(_network?: Networkish, apiKey?: null | string) {
|
||||
if (_network == null) { _network = "mainnet"; }
|
||||
const network = Network.from(_network);
|
||||
if (apiKey == null) { apiKey = defaultApiKey; }
|
||||
|
||||
const request = AlchemyProvider.getRequest(network, apiKey);
|
||||
super(request, network, { staticNetwork: network });
|
||||
|
||||
defineProperties<AlchemyProvider>(this, { apiKey });
|
||||
}
|
||||
|
||||
_getProvider(chainId: number): AbstractProvider {
|
||||
try {
|
||||
return new AlchemyProvider(chainId, this.apiKey);
|
||||
} catch (error) { }
|
||||
return super._getProvider(chainId);
|
||||
}
|
||||
|
||||
async _perform(req: PerformActionRequest): Promise<any> {
|
||||
|
||||
// https://docs.alchemy.com/reference/trace-transaction
|
||||
if (req.method === "getTransactionResult") {
|
||||
const { trace, tx } = await resolveProperties({
|
||||
trace: this.send("trace_transaction", [ req.hash ]),
|
||||
tx: this.getTransaction(req.hash)
|
||||
});
|
||||
if (trace == null || tx == null) { return null; }
|
||||
|
||||
let data: undefined | string;
|
||||
let error = false;
|
||||
try {
|
||||
data = trace[0].result.output;
|
||||
error = (trace[0].error === "Reverted");
|
||||
} catch (error) { }
|
||||
|
||||
if (data) {
|
||||
assert(!error, "an error occurred during transaction executions", "CALL_EXCEPTION", {
|
||||
action: "getTransactionResult",
|
||||
data,
|
||||
reason: null,
|
||||
transaction: tx,
|
||||
invocation: null,
|
||||
revert: null // @TODO
|
||||
});
|
||||
return data;
|
||||
}
|
||||
|
||||
assert(false, "could not parse trace result", "BAD_DATA", { value: trace });
|
||||
}
|
||||
|
||||
return await super._perform(req);
|
||||
}
|
||||
|
||||
isCommunityResource(): boolean {
|
||||
return (this.apiKey === defaultApiKey);
|
||||
}
|
||||
|
||||
static getRequest(network: Network, apiKey?: string): FetchRequest {
|
||||
if (apiKey == null) { apiKey = defaultApiKey; }
|
||||
|
||||
const request = new FetchRequest(`https:/\/${ getHost(network.name) }/v2/${ apiKey }`);
|
||||
request.allowGzip = true;
|
||||
|
||||
if (apiKey === defaultApiKey) {
|
||||
request.retryFunc = async (request, response, attempt) => {
|
||||
showThrottleMessage("alchemy");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
}
|
||||
159
dev/env/node_modules/ethers/src.ts/providers/provider-ankr.ts
generated
vendored
Executable file
159
dev/env/node_modules/ethers/src.ts/providers/provider-ankr.ts
generated
vendored
Executable file
@@ -0,0 +1,159 @@
|
||||
/**
|
||||
* [[link-ankr]] provides a third-party service for connecting to
|
||||
* various blockchains over JSON-RPC.
|
||||
*
|
||||
* **Supported Networks**
|
||||
*
|
||||
* - Ethereum Mainnet (``mainnet``)
|
||||
* - Goerli Testnet (``goerli``)
|
||||
* - Sepolia Testnet (``sepolia``)
|
||||
* - Arbitrum (``arbitrum``)
|
||||
* - Base (``base``)
|
||||
* - Base Goerlia Testnet (``base-goerli``)
|
||||
* - Base Sepolia Testnet (``base-sepolia``)
|
||||
* - BNB (``bnb``)
|
||||
* - BNB Testnet (``bnbt``)
|
||||
* - Filecoin (``filecoin``)
|
||||
* - Filecoin Calibration Testnet (``filecoin-calibration``)
|
||||
* - Optimism (``optimism``)
|
||||
* - Optimism Goerli Testnet (``optimism-goerli``)
|
||||
* - Optimism Sepolia Testnet (``optimism-sepolia``)
|
||||
* - Polygon (``matic``)
|
||||
* - Polygon Mumbai Testnet (``matic-mumbai``)
|
||||
*
|
||||
* @_subsection: api/providers/thirdparty:Ankr [providers-ankr]
|
||||
*/
|
||||
import {
|
||||
defineProperties, FetchRequest, assertArgument
|
||||
} from "../utils/index.js";
|
||||
|
||||
import { AbstractProvider } from "./abstract-provider.js";
|
||||
import { showThrottleMessage } from "./community.js";
|
||||
import { Network } from "./network.js";
|
||||
import { JsonRpcProvider } from "./provider-jsonrpc.js";
|
||||
|
||||
import type { CommunityResourcable } from "./community.js";
|
||||
import type { Networkish } from "./network.js";
|
||||
import type { JsonRpcError, JsonRpcPayload } from "./provider-jsonrpc.js";
|
||||
|
||||
|
||||
const defaultApiKey = "9f7d929b018cdffb338517efa06f58359e86ff1ffd350bc889738523659e7972";
|
||||
|
||||
function getHost(name: string): string {
|
||||
switch (name) {
|
||||
case "mainnet":
|
||||
return "rpc.ankr.com/eth";
|
||||
case "goerli":
|
||||
return "rpc.ankr.com/eth_goerli";
|
||||
case "sepolia":
|
||||
return "rpc.ankr.com/eth_sepolia";
|
||||
|
||||
case "arbitrum":
|
||||
return "rpc.ankr.com/arbitrum";
|
||||
case "base":
|
||||
return "rpc.ankr.com/base";
|
||||
case "base-goerli":
|
||||
return "rpc.ankr.com/base_goerli";
|
||||
case "base-sepolia":
|
||||
return "rpc.ankr.com/base_sepolia";
|
||||
case "bnb":
|
||||
return "rpc.ankr.com/bsc";
|
||||
case "bnbt":
|
||||
return "rpc.ankr.com/bsc_testnet_chapel";
|
||||
case "filecoin":
|
||||
return "rpc.ankr.com/filecoin";
|
||||
case "filecoin-calibration":
|
||||
return "rpc.ankr.com/filecoin_testnet";
|
||||
case "matic":
|
||||
return "rpc.ankr.com/polygon";
|
||||
case "matic-mumbai":
|
||||
return "rpc.ankr.com/polygon_mumbai";
|
||||
case "optimism":
|
||||
return "rpc.ankr.com/optimism";
|
||||
case "optimism-goerli":
|
||||
return "rpc.ankr.com/optimism_testnet";
|
||||
case "optimism-sepolia":
|
||||
return "rpc.ankr.com/optimism_sepolia";
|
||||
}
|
||||
|
||||
assertArgument(false, "unsupported network", "network", name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The **AnkrProvider** connects to the [[link-ankr]]
|
||||
* JSON-RPC end-points.
|
||||
*
|
||||
* By default, a highly-throttled API key is used, which is
|
||||
* appropriate for quick prototypes and simple scripts. To
|
||||
* gain access to an increased rate-limit, it is highly
|
||||
* recommended to [sign up here](link-ankr-signup).
|
||||
*/
|
||||
export class AnkrProvider extends JsonRpcProvider implements CommunityResourcable {
|
||||
|
||||
/**
|
||||
* The API key for the Ankr connection.
|
||||
*/
|
||||
readonly apiKey!: string;
|
||||
|
||||
/**
|
||||
* Create a new **AnkrProvider**.
|
||||
*
|
||||
* By default connecting to ``mainnet`` with a highly throttled
|
||||
* API key.
|
||||
*/
|
||||
constructor(_network?: Networkish, apiKey?: null | string) {
|
||||
if (_network == null) { _network = "mainnet"; }
|
||||
const network = Network.from(_network);
|
||||
if (apiKey == null) { apiKey = defaultApiKey; }
|
||||
|
||||
// Ankr does not support filterId, so we force polling
|
||||
const options = { polling: true, staticNetwork: network };
|
||||
|
||||
const request = AnkrProvider.getRequest(network, apiKey);
|
||||
super(request, network, options);
|
||||
|
||||
defineProperties<AnkrProvider>(this, { apiKey });
|
||||
}
|
||||
|
||||
_getProvider(chainId: number): AbstractProvider {
|
||||
try {
|
||||
return new AnkrProvider(chainId, this.apiKey);
|
||||
} catch (error) { }
|
||||
return super._getProvider(chainId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a prepared request for connecting to %%network%% with
|
||||
* %%apiKey%%.
|
||||
*/
|
||||
static getRequest(network: Network, apiKey?: null | string): FetchRequest {
|
||||
if (apiKey == null) { apiKey = defaultApiKey; }
|
||||
|
||||
const request = new FetchRequest(`https:/\/${ getHost(network.name) }/${ apiKey }`);
|
||||
request.allowGzip = true;
|
||||
|
||||
if (apiKey === defaultApiKey) {
|
||||
request.retryFunc = async (request, response, attempt) => {
|
||||
showThrottleMessage("AnkrProvider");
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
getRpcError(payload: JsonRpcPayload, error: JsonRpcError): Error {
|
||||
if (payload.method === "eth_sendRawTransaction") {
|
||||
if (error && error.error && error.error.message === "INTERNAL_ERROR: could not replace existing tx") {
|
||||
error.error.message = "replacement transaction underpriced";
|
||||
}
|
||||
}
|
||||
|
||||
return super.getRpcError(payload, error);
|
||||
}
|
||||
|
||||
isCommunityResource(): boolean {
|
||||
return (this.apiKey === defaultApiKey);
|
||||
}
|
||||
}
|
||||
167
dev/env/node_modules/ethers/src.ts/providers/provider-blockscout.ts
generated
vendored
Executable file
167
dev/env/node_modules/ethers/src.ts/providers/provider-blockscout.ts
generated
vendored
Executable file
@@ -0,0 +1,167 @@
|
||||
|
||||
/**
|
||||
* [[link-blockscout]] provides a third-party service for connecting to
|
||||
* various blockchains over JSON-RPC.
|
||||
*
|
||||
* **Supported Networks**
|
||||
*
|
||||
* - Ethereum Mainnet (``mainnet``)
|
||||
* - Sepolia Testnet (``sepolia``)
|
||||
* - Holesky Testnet (``holesky``)
|
||||
* - Ethereum Classic (``classic``)
|
||||
* - Arbitrum (``arbitrum``)
|
||||
* - Base (``base``)
|
||||
* - Base Sepolia Testnet (``base-sepolia``)
|
||||
* - Gnosis (``xdai``)
|
||||
* - Optimism (``optimism``)
|
||||
* - Optimism Sepolia Testnet (``optimism-sepolia``)
|
||||
* - Polygon (``matic``)
|
||||
*
|
||||
* @_subsection: api/providers/thirdparty:Blockscout [providers-blockscout]
|
||||
*/
|
||||
import {
|
||||
assertArgument, defineProperties, FetchRequest, isHexString
|
||||
} from "../utils/index.js";
|
||||
|
||||
import { Network } from "./network.js";
|
||||
import { JsonRpcProvider } from "./provider-jsonrpc.js";
|
||||
|
||||
import type { AbstractProvider, PerformActionRequest } from "./abstract-provider.js";
|
||||
import type { CommunityResourcable } from "./community.js";
|
||||
import type { Networkish } from "./network.js";
|
||||
import type { JsonRpcPayload, JsonRpcError } from "./provider-jsonrpc.js";
|
||||
|
||||
|
||||
function getUrl(name: string): string {
|
||||
switch(name) {
|
||||
case "mainnet":
|
||||
return "https:/\/eth.blockscout.com/api/eth-rpc";
|
||||
case "sepolia":
|
||||
return "https:/\/eth-sepolia.blockscout.com/api/eth-rpc";
|
||||
case "holesky":
|
||||
return "https:/\/eth-holesky.blockscout.com/api/eth-rpc";
|
||||
|
||||
case "classic":
|
||||
return "https:/\/etc.blockscout.com/api/eth-rpc";
|
||||
|
||||
case "arbitrum":
|
||||
return "https:/\/arbitrum.blockscout.com/api/eth-rpc";
|
||||
|
||||
case "base":
|
||||
return "https:/\/base.blockscout.com/api/eth-rpc";
|
||||
case "base-sepolia":
|
||||
return "https:/\/base-sepolia.blockscout.com/api/eth-rpc";
|
||||
|
||||
case "matic":
|
||||
return "https:/\/polygon.blockscout.com/api/eth-rpc";
|
||||
|
||||
case "optimism":
|
||||
return "https:/\/optimism.blockscout.com/api/eth-rpc";
|
||||
case "optimism-sepolia":
|
||||
return "https:/\/optimism-sepolia.blockscout.com/api/eth-rpc";
|
||||
|
||||
case "xdai":
|
||||
return "https:/\/gnosis.blockscout.com/api/eth-rpc";
|
||||
}
|
||||
|
||||
assertArgument(false, "unsupported network", "network", name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The **BlockscoutProvider** connects to the [[link-blockscout]]
|
||||
* JSON-RPC end-points.
|
||||
*
|
||||
* By default, a highly-throttled API key is used, which is
|
||||
* appropriate for quick prototypes and simple scripts. To
|
||||
* gain access to an increased rate-limit, it is highly
|
||||
* recommended to [sign up here](link-blockscout).
|
||||
*/
|
||||
export class BlockscoutProvider extends JsonRpcProvider implements CommunityResourcable {
|
||||
/**
|
||||
* The API key.
|
||||
*/
|
||||
readonly apiKey!: null | string;
|
||||
|
||||
/**
|
||||
* Creates a new **BlockscoutProvider**.
|
||||
*/
|
||||
constructor(_network?: Networkish, apiKey?: null | string) {
|
||||
if (_network == null) { _network = "mainnet"; }
|
||||
const network = Network.from(_network);
|
||||
|
||||
if (apiKey == null) { apiKey = null; }
|
||||
|
||||
const request = BlockscoutProvider.getRequest(network);
|
||||
super(request, network, { staticNetwork: network });
|
||||
|
||||
defineProperties<BlockscoutProvider>(this, { apiKey });
|
||||
}
|
||||
|
||||
_getProvider(chainId: number): AbstractProvider {
|
||||
try {
|
||||
return new BlockscoutProvider(chainId, this.apiKey);
|
||||
} catch (error) { }
|
||||
return super._getProvider(chainId);
|
||||
}
|
||||
|
||||
isCommunityResource(): boolean {
|
||||
return (this.apiKey === null);
|
||||
}
|
||||
|
||||
getRpcRequest(req: PerformActionRequest): null | { method: string, args: Array<any> } {
|
||||
// Blockscout enforces the TAG argument for estimateGas
|
||||
const resp = super.getRpcRequest(req);
|
||||
if (resp && resp.method === "eth_estimateGas" && resp.args.length == 1) {
|
||||
resp.args = resp.args.slice();
|
||||
resp.args.push("latest");
|
||||
}
|
||||
return resp;
|
||||
}
|
||||
|
||||
getRpcError(payload: JsonRpcPayload, _error: JsonRpcError): Error {
|
||||
const error = _error ? _error.error: null;
|
||||
|
||||
// Blockscout currently drops the VM result and replaces it with a
|
||||
// human-readable string, so we need to make it machine-readable.
|
||||
if (error && error.code === -32015 && !isHexString(error.data || "", true)) {
|
||||
const panicCodes = <Record<string, string>>{
|
||||
"assert(false)": "01",
|
||||
"arithmetic underflow or overflow": "11",
|
||||
"division or modulo by zero": "12",
|
||||
"out-of-bounds array access; popping on an empty array": "31",
|
||||
"out-of-bounds access of an array or bytesN": "32"
|
||||
};
|
||||
|
||||
let panicCode = "";
|
||||
if (error.message === "VM execution error.") {
|
||||
// eth_call passes this message
|
||||
panicCode = panicCodes[error.data] || "";
|
||||
} else if (panicCodes[error.message || ""]) {
|
||||
panicCode = panicCodes[error.message || ""];
|
||||
}
|
||||
|
||||
if (panicCode) {
|
||||
error.message += ` (reverted: ${ error.data })`;
|
||||
error.data = "0x4e487b7100000000000000000000000000000000000000000000000000000000000000" + panicCode;
|
||||
}
|
||||
|
||||
} else if (error && error.code === -32000) {
|
||||
if (error.message === "wrong transaction nonce") {
|
||||
error.message += " (nonce too low)";
|
||||
}
|
||||
}
|
||||
|
||||
return super.getRpcError(payload, _error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a prepared request for connecting to %%network%%
|
||||
* with %%apiKey%%.
|
||||
*/
|
||||
static getRequest(network: Network): FetchRequest {
|
||||
const request = new FetchRequest(getUrl(network.name));
|
||||
request.allowGzip = true;
|
||||
return request;
|
||||
}
|
||||
}
|
||||
334
dev/env/node_modules/ethers/src.ts/providers/provider-browser.ts
generated
vendored
Executable file
334
dev/env/node_modules/ethers/src.ts/providers/provider-browser.ts
generated
vendored
Executable file
@@ -0,0 +1,334 @@
|
||||
|
||||
import { assertArgument, makeError } from "../utils/index.js";
|
||||
|
||||
import { JsonRpcApiPollingProvider } from "./provider-jsonrpc.js";
|
||||
|
||||
import type {
|
||||
JsonRpcApiProviderOptions,
|
||||
JsonRpcError, JsonRpcPayload, JsonRpcResult,
|
||||
JsonRpcSigner
|
||||
} from "./provider-jsonrpc.js";
|
||||
import type { Network, Networkish } from "./network.js";
|
||||
|
||||
/**
|
||||
* The interface to an [[link-eip-1193]] provider, which is a standard
|
||||
* used by most injected providers, which the [[BrowserProvider]] accepts
|
||||
* and exposes the API of.
|
||||
*/
|
||||
export interface Eip1193Provider {
|
||||
/**
|
||||
* See [[link-eip-1193]] for details on this method.
|
||||
*/
|
||||
request(request: { method: string, params?: Array<any> | Record<string, any> }): Promise<any>;
|
||||
};
|
||||
|
||||
/**
|
||||
* The possible additional events dispatched when using the ``"debug"``
|
||||
* event on a [[BrowserProvider]].
|
||||
*/
|
||||
export type DebugEventBrowserProvider = {
|
||||
action: "sendEip1193Payload",
|
||||
payload: { method: string, params: Array<any> }
|
||||
} | {
|
||||
action: "receiveEip1193Result",
|
||||
result: any
|
||||
} | {
|
||||
action: "receiveEip1193Error",
|
||||
error: Error
|
||||
};
|
||||
|
||||
/**
|
||||
* Provider info provided by the [[link-eip-6963]] discovery mechanism.
|
||||
*/
|
||||
export interface Eip6963ProviderInfo {
|
||||
uuid: string;
|
||||
name: string;
|
||||
icon: string;
|
||||
rdns: string;
|
||||
}
|
||||
|
||||
interface Eip6963ProviderDetail {
|
||||
info: Eip6963ProviderInfo;
|
||||
provider: Eip1193Provider;
|
||||
}
|
||||
|
||||
interface Eip6963Announcement {
|
||||
type: "eip6963:announceProvider";
|
||||
detail: Eip6963ProviderDetail
|
||||
}
|
||||
|
||||
export type BrowserProviderOptions = {
|
||||
polling?: boolean;
|
||||
staticNetwork?: null | boolean | Network;
|
||||
|
||||
cacheTimeout?: number;
|
||||
pollingInterval?: number;
|
||||
|
||||
providerInfo?: Eip6963ProviderInfo;
|
||||
};
|
||||
|
||||
/**
|
||||
* Specifies how [[link-eip-6963]] discovery should proceed.
|
||||
*
|
||||
* See: [[BrowserProvider-discover]]
|
||||
*/
|
||||
export interface BrowserDiscoverOptions {
|
||||
/**
|
||||
* Override provider detection with this provider.
|
||||
*/
|
||||
provider?: Eip1193Provider;
|
||||
|
||||
/**
|
||||
* Duration to wait to detect providers. (default: 300ms)
|
||||
*/
|
||||
timeout?: number;
|
||||
|
||||
/**
|
||||
* Return the first detected provider. Otherwise wait for %%timeout%%
|
||||
* and allowing filtering before selecting the desired provider.
|
||||
*/
|
||||
anyProvider?: boolean;
|
||||
|
||||
/**
|
||||
* Use the provided window context. Useful in non-standard
|
||||
* environments or to hijack where a provider comes from.
|
||||
*/
|
||||
window?: any;
|
||||
|
||||
/**
|
||||
* Explicitly choose which provider to used once scanning is complete.
|
||||
*/
|
||||
filter?: (found: Array<Eip6963ProviderInfo>) => null | BrowserProvider |
|
||||
Eip6963ProviderInfo;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A **BrowserProvider** is intended to wrap an injected provider which
|
||||
* adheres to the [[link-eip-1193]] standard, which most (if not all)
|
||||
* currently do.
|
||||
*/
|
||||
export class BrowserProvider extends JsonRpcApiPollingProvider {
|
||||
#request: (method: string, params: Array<any> | Record<string, any>) => Promise<any>;
|
||||
|
||||
#providerInfo: null | Eip6963ProviderInfo;
|
||||
|
||||
/**
|
||||
* Connect to the %%ethereum%% provider, optionally forcing the
|
||||
* %%network%%.
|
||||
*/
|
||||
constructor(ethereum: Eip1193Provider, network?: Networkish, _options?: BrowserProviderOptions) {
|
||||
|
||||
// Copy the options
|
||||
const options: JsonRpcApiProviderOptions = Object.assign({ },
|
||||
((_options != null) ? _options: { }),
|
||||
{ batchMaxCount: 1 });
|
||||
|
||||
assertArgument(ethereum && ethereum.request, "invalid EIP-1193 provider", "ethereum", ethereum);
|
||||
|
||||
super(network, options);
|
||||
|
||||
this.#providerInfo = null;
|
||||
if (_options && _options.providerInfo) {
|
||||
this.#providerInfo = _options.providerInfo;
|
||||
}
|
||||
|
||||
this.#request = async (method: string, params: Array<any> | Record<string, any>) => {
|
||||
const payload = { method, params };
|
||||
this.emit("debug", { action: "sendEip1193Request", payload });
|
||||
try {
|
||||
const result = await ethereum.request(payload);
|
||||
this.emit("debug", { action: "receiveEip1193Result", result });
|
||||
return result;
|
||||
} catch (e: any) {
|
||||
const error = new Error(e.message);
|
||||
(<any>error).code = e.code;
|
||||
(<any>error).data = e.data;
|
||||
(<any>error).payload = payload;
|
||||
this.emit("debug", { action: "receiveEip1193Error", error });
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
get providerInfo(): null | Eip6963ProviderInfo {
|
||||
return this.#providerInfo;
|
||||
}
|
||||
|
||||
async send(method: string, params: Array<any> | Record<string, any>): Promise<any> {
|
||||
await this._start();
|
||||
|
||||
return await super.send(method, params);
|
||||
}
|
||||
|
||||
async _send(payload: JsonRpcPayload | Array<JsonRpcPayload>): Promise<Array<JsonRpcResult | JsonRpcError>> {
|
||||
assertArgument(!Array.isArray(payload), "EIP-1193 does not support batch request", "payload", payload);
|
||||
|
||||
try {
|
||||
const result = await this.#request(payload.method, payload.params || [ ]);
|
||||
return [ { id: payload.id, result } ];
|
||||
} catch (e: any) {
|
||||
return [ {
|
||||
id: payload.id,
|
||||
error: { code: e.code, data: e.data, message: e.message }
|
||||
} ];
|
||||
}
|
||||
}
|
||||
|
||||
getRpcError(payload: JsonRpcPayload, error: JsonRpcError): Error {
|
||||
|
||||
error = JSON.parse(JSON.stringify(error));
|
||||
|
||||
// EIP-1193 gives us some machine-readable error codes, so rewrite
|
||||
// them into Ethers standard errors.
|
||||
switch (error.error.code || -1) {
|
||||
case 4001:
|
||||
error.error.message = `ethers-user-denied: ${ error.error.message }`;
|
||||
break;
|
||||
case 4200:
|
||||
error.error.message = `ethers-unsupported: ${ error.error.message }`;
|
||||
break;
|
||||
}
|
||||
|
||||
return super.getRpcError(payload, error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to ``true`` if the provider manages the %%address%%.
|
||||
*/
|
||||
async hasSigner(address: number | string): Promise<boolean> {
|
||||
if (address == null) { address = 0; }
|
||||
|
||||
const accounts = await this.send("eth_accounts", [ ]);
|
||||
if (typeof(address) === "number") {
|
||||
return (accounts.length > address);
|
||||
}
|
||||
|
||||
address = address.toLowerCase();
|
||||
return accounts.filter((a: string) => (a.toLowerCase() === address)).length !== 0;
|
||||
}
|
||||
|
||||
async getSigner(address?: number | string): Promise<JsonRpcSigner> {
|
||||
if (address == null) { address = 0; }
|
||||
|
||||
if (!(await this.hasSigner(address))) {
|
||||
try {
|
||||
await this.#request("eth_requestAccounts", [ ]);
|
||||
|
||||
} catch (error: any) {
|
||||
const payload = error.payload;
|
||||
throw this.getRpcError(payload, { id: payload.id, error });
|
||||
}
|
||||
}
|
||||
|
||||
return await super.getSigner(address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Discover and connect to a Provider in the Browser using the
|
||||
* [[link-eip-6963]] discovery mechanism. If no providers are
|
||||
* present, ``null`` is resolved.
|
||||
*/
|
||||
static async discover(options?: BrowserDiscoverOptions): Promise<null | BrowserProvider> {
|
||||
if (options == null) { options = { }; }
|
||||
|
||||
if (options.provider) {
|
||||
return new BrowserProvider(options.provider);
|
||||
}
|
||||
|
||||
const context = options.window ? options.window:
|
||||
(typeof(window) !== "undefined") ? window: null;
|
||||
|
||||
if (context == null) { return null; }
|
||||
|
||||
const anyProvider = options.anyProvider;
|
||||
if (anyProvider && context.ethereum) {
|
||||
return new BrowserProvider(context.ethereum);
|
||||
}
|
||||
|
||||
if (!("addEventListener" in context && "dispatchEvent" in context
|
||||
&& "removeEventListener" in context)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const timeout = options.timeout ? options.timeout: 300;
|
||||
if (timeout === 0) { return null; }
|
||||
|
||||
return await (new Promise((resolve, reject) => {
|
||||
let found: Array<Eip6963ProviderDetail> = [ ];
|
||||
|
||||
const addProvider = (event: Eip6963Announcement) => {
|
||||
found.push(event.detail);
|
||||
if (anyProvider) { finalize(); }
|
||||
};
|
||||
|
||||
const finalize = () => {
|
||||
clearTimeout(timer);
|
||||
|
||||
if (found.length) {
|
||||
|
||||
// If filtering is provided:
|
||||
if (options && options.filter) {
|
||||
|
||||
// Call filter, with a copies of found provider infos
|
||||
const filtered = options.filter(found.map(i =>
|
||||
Object.assign({ }, (i.info))));
|
||||
|
||||
if (filtered == null) {
|
||||
// No provider selected
|
||||
resolve(null);
|
||||
|
||||
} else if (filtered instanceof BrowserProvider) {
|
||||
// Custom provider created
|
||||
resolve(filtered);
|
||||
|
||||
} else {
|
||||
// Find the matching provider
|
||||
let match: null | Eip6963ProviderDetail = null;
|
||||
if (filtered.uuid) {
|
||||
const matches = found.filter(f =>
|
||||
(filtered.uuid === f.info.uuid));
|
||||
// @TODO: What should happen if multiple values
|
||||
// for the same UUID?
|
||||
match = matches[0];
|
||||
}
|
||||
|
||||
if (match) {
|
||||
const { provider, info } = match;
|
||||
resolve(new BrowserProvider(provider, undefined, {
|
||||
providerInfo: info
|
||||
}));
|
||||
} else {
|
||||
reject(makeError("filter returned unknown info", "UNSUPPORTED_OPERATION", {
|
||||
value: filtered
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Pick the first found provider
|
||||
const { provider, info } = found[0];
|
||||
resolve(new BrowserProvider(provider, undefined, {
|
||||
providerInfo: info
|
||||
}));
|
||||
}
|
||||
|
||||
} else {
|
||||
// Nothing found
|
||||
resolve(null);
|
||||
}
|
||||
|
||||
context.removeEventListener(<any>"eip6963:announceProvider",
|
||||
addProvider);
|
||||
};
|
||||
|
||||
const timer = setTimeout(() => { finalize(); }, timeout);
|
||||
|
||||
context.addEventListener(<any>"eip6963:announceProvider",
|
||||
addProvider);
|
||||
|
||||
context.dispatchEvent(new Event("eip6963:requestProvider"));
|
||||
}));
|
||||
}
|
||||
}
|
||||
113
dev/env/node_modules/ethers/src.ts/providers/provider-chainstack.ts
generated
vendored
Executable file
113
dev/env/node_modules/ethers/src.ts/providers/provider-chainstack.ts
generated
vendored
Executable file
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* [[link-chainstack]] provides a third-party service for connecting to
|
||||
* various blockchains over JSON-RPC.
|
||||
*
|
||||
* **Supported Networks**
|
||||
*
|
||||
* - Ethereum Mainnet (``mainnet``)
|
||||
* - Arbitrum (``arbitrum``)
|
||||
* - BNB Smart Chain Mainnet (``bnb``)
|
||||
* - Polygon (``matic``)
|
||||
*
|
||||
* @_subsection: api/providers/thirdparty:Chainstack [providers-chainstack]
|
||||
*/
|
||||
import {
|
||||
defineProperties, FetchRequest, assertArgument
|
||||
} from "../utils/index.js";
|
||||
|
||||
import { showThrottleMessage } from "./community.js";
|
||||
import { Network } from "./network.js";
|
||||
import { JsonRpcProvider } from "./provider-jsonrpc.js";
|
||||
|
||||
import type { AbstractProvider } from "./abstract-provider.js";
|
||||
import type { CommunityResourcable } from "./community.js";
|
||||
import type { Networkish } from "./network.js";
|
||||
|
||||
|
||||
function getApiKey(name: string): string {
|
||||
switch (name) {
|
||||
case "mainnet": return "39f1d67cedf8b7831010a665328c9197";
|
||||
case "arbitrum": return "0550c209db33c3abf4cc927e1e18cea1"
|
||||
case "bnb": return "98b5a77e531614387366f6fc5da097f8";
|
||||
case "matic": return "cd9d4d70377471aa7c142ec4a4205249";
|
||||
}
|
||||
|
||||
assertArgument(false, "unsupported network", "network", name);
|
||||
}
|
||||
|
||||
function getHost(name: string): string {
|
||||
switch(name) {
|
||||
case "mainnet":
|
||||
return "ethereum-mainnet.core.chainstack.com";
|
||||
case "arbitrum":
|
||||
return "arbitrum-mainnet.core.chainstack.com";
|
||||
case "bnb":
|
||||
return "bsc-mainnet.core.chainstack.com";
|
||||
case "matic":
|
||||
return "polygon-mainnet.core.chainstack.com";
|
||||
}
|
||||
|
||||
assertArgument(false, "unsupported network", "network", name);
|
||||
}
|
||||
|
||||
/**
|
||||
* The **ChainstackProvider** connects to the [[link-chainstack]]
|
||||
* JSON-RPC end-points.
|
||||
*
|
||||
* By default, a highly-throttled API key is used, which is
|
||||
* appropriate for quick prototypes and simple scripts. To
|
||||
* gain access to an increased rate-limit, it is highly
|
||||
* recommended to [sign up here](link-chainstack).
|
||||
*/
|
||||
export class ChainstackProvider extends JsonRpcProvider implements CommunityResourcable {
|
||||
/**
|
||||
* The API key for the Chainstack connection.
|
||||
*/
|
||||
readonly apiKey!: string;
|
||||
|
||||
/**
|
||||
* Creates a new **ChainstackProvider**.
|
||||
*/
|
||||
constructor(_network?: Networkish, apiKey?: null | string) {
|
||||
if (_network == null) { _network = "mainnet"; }
|
||||
const network = Network.from(_network);
|
||||
|
||||
if (apiKey == null) { apiKey = getApiKey(network.name); }
|
||||
|
||||
const request = ChainstackProvider.getRequest(network, apiKey);
|
||||
super(request, network, { staticNetwork: network });
|
||||
|
||||
defineProperties<ChainstackProvider>(this, { apiKey });
|
||||
}
|
||||
|
||||
_getProvider(chainId: number): AbstractProvider {
|
||||
try {
|
||||
return new ChainstackProvider(chainId, this.apiKey);
|
||||
} catch (error) { }
|
||||
return super._getProvider(chainId);
|
||||
}
|
||||
|
||||
isCommunityResource(): boolean {
|
||||
return (this.apiKey === getApiKey(this._network.name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a prepared request for connecting to %%network%%
|
||||
* with %%apiKey%% and %%projectSecret%%.
|
||||
*/
|
||||
static getRequest(network: Network, apiKey?: null | string): FetchRequest {
|
||||
if (apiKey == null) { apiKey = getApiKey(network.name); }
|
||||
|
||||
const request = new FetchRequest(`https:/\/${ getHost(network.name) }/${ apiKey }`);
|
||||
request.allowGzip = true;
|
||||
|
||||
if (apiKey === getApiKey(network.name)) {
|
||||
request.retryFunc = async (request, response, attempt) => {
|
||||
showThrottleMessage("ChainstackProvider");
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
}
|
||||
24
dev/env/node_modules/ethers/src.ts/providers/provider-cloudflare.ts
generated
vendored
Executable file
24
dev/env/node_modules/ethers/src.ts/providers/provider-cloudflare.ts
generated
vendored
Executable file
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* About Cloudflare
|
||||
*
|
||||
* @_subsection: api/providers/thirdparty:Cloudflare [providers-cloudflare]
|
||||
*/
|
||||
|
||||
import { assertArgument } from "../utils/index.js";
|
||||
|
||||
import { Network } from "./network.js";
|
||||
import { JsonRpcProvider } from "./provider-jsonrpc.js";
|
||||
|
||||
import type { Networkish } from "./network.js";
|
||||
|
||||
/**
|
||||
* About Cloudflare...
|
||||
*/
|
||||
export class CloudflareProvider extends JsonRpcProvider {
|
||||
constructor(_network?: Networkish) {
|
||||
if (_network == null) { _network = "mainnet"; }
|
||||
const network = Network.from(_network);
|
||||
assertArgument(network.name === "mainnet", "unsupported network", "network", _network);
|
||||
super("https:/\/cloudflare-eth.com/", network, { staticNetwork: network });
|
||||
}
|
||||
}
|
||||
687
dev/env/node_modules/ethers/src.ts/providers/provider-etherscan.ts
generated
vendored
Executable file
687
dev/env/node_modules/ethers/src.ts/providers/provider-etherscan.ts
generated
vendored
Executable file
@@ -0,0 +1,687 @@
|
||||
/**
|
||||
* [[link-etherscan]] provides a third-party service for connecting to
|
||||
* various blockchains over a combination of JSON-RPC and custom API
|
||||
* endpoints.
|
||||
*
|
||||
* **Supported Networks**
|
||||
*
|
||||
* - Ethereum Mainnet (``mainnet``)
|
||||
* - Goerli Testnet (``goerli``)
|
||||
* - Sepolia Testnet (``sepolia``)
|
||||
* - Holesky Testnet (``holesky``)
|
||||
* - Arbitrum (``arbitrum``)
|
||||
* - Arbitrum Goerli Testnet (``arbitrum-goerli``)
|
||||
* - Base (``base``)
|
||||
* - Base Sepolia Testnet (``base-sepolia``)
|
||||
* - BNB Smart Chain Mainnet (``bnb``)
|
||||
* - BNB Smart Chain Testnet (``bnbt``)
|
||||
* - Optimism (``optimism``)
|
||||
* - Optimism Goerli Testnet (``optimism-goerli``)
|
||||
* - Polygon (``matic``)
|
||||
* - Polygon Mumbai Testnet (``matic-mumbai``)
|
||||
* - Polygon Amoy Testnet (``matic-amoy``)
|
||||
*
|
||||
* @_subsection api/providers/thirdparty:Etherscan [providers-etherscan]
|
||||
*/
|
||||
|
||||
import { AbiCoder } from "../abi/index.js";
|
||||
import { Contract } from "../contract/index.js";
|
||||
import { accessListify, Transaction } from "../transaction/index.js";
|
||||
import {
|
||||
defineProperties,
|
||||
hexlify, toQuantity,
|
||||
FetchRequest,
|
||||
assert, assertArgument, isError,
|
||||
// parseUnits,
|
||||
toUtf8String
|
||||
} from "../utils/index.js";
|
||||
|
||||
import { AbstractProvider } from "./abstract-provider.js";
|
||||
import { Network } from "./network.js";
|
||||
import { NetworkPlugin } from "./plugins-network.js";
|
||||
import { showThrottleMessage } from "./community.js";
|
||||
|
||||
import { PerformActionRequest } from "./abstract-provider.js";
|
||||
import type { Networkish } from "./network.js";
|
||||
//import type { } from "./pagination";
|
||||
import type { TransactionRequest } from "./provider.js";
|
||||
|
||||
// See: https://docs.etherscan.io/supported-chains
|
||||
const Supported = (
|
||||
"1 11155111 17000 560048 2741 11124 33111 33139 42170 " +
|
||||
"42161 421614 43114 43113 8453 84532 80069 80094 199 1029 81457 " +
|
||||
"168587773 56 97 42220 11142220 252 2523 100 999 737373 747474 " +
|
||||
"59144 59141 5000 5003 43521 143 10143 1287 1284 1285 10 " +
|
||||
"11155420 204 5611 80002 137 534352 534351 1329 1328 146 14601 " +
|
||||
"988 2201 1923 1924 167013 167000 130 1301 480 4801 51 50 324 300"
|
||||
).split(/ /g);
|
||||
|
||||
const THROTTLE = 2000;
|
||||
|
||||
function isPromise<T = any>(value: any): value is Promise<T> {
|
||||
return (value && typeof(value.then) === "function");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* When subscribing to the ``"debug"`` event on an Etherscan-based
|
||||
* provider, the events receive a **DebugEventEtherscanProvider**
|
||||
* payload.
|
||||
*
|
||||
* @_docloc: api/providers/thirdparty:Etherscan
|
||||
*/
|
||||
export type DebugEventEtherscanProvider = {
|
||||
action: "sendRequest",
|
||||
id: number,
|
||||
url: string,
|
||||
payload: Record<string, any>
|
||||
} | {
|
||||
action: "receiveRequest",
|
||||
id: number,
|
||||
result: any
|
||||
} | {
|
||||
action: "receiveError",
|
||||
id: number,
|
||||
error: any
|
||||
};
|
||||
|
||||
const EtherscanPluginId = "org.ethers.plugins.provider.Etherscan";
|
||||
|
||||
/**
|
||||
* A Network can include an **EtherscanPlugin** to provide
|
||||
* a custom base URL.
|
||||
*
|
||||
* @_docloc: api/providers/thirdparty:Etherscan
|
||||
*/
|
||||
export class EtherscanPlugin extends NetworkPlugin {
|
||||
/**
|
||||
* The Etherscan API base URL.
|
||||
*/
|
||||
readonly baseUrl!: string;
|
||||
|
||||
/**
|
||||
* Creates a new **EtherscanProvider** which will use
|
||||
* %%baseUrl%%.
|
||||
*/
|
||||
constructor(baseUrl: string) {
|
||||
super(EtherscanPluginId);
|
||||
defineProperties<EtherscanPlugin>(this, { baseUrl });
|
||||
}
|
||||
|
||||
clone(): EtherscanPlugin {
|
||||
return new EtherscanPlugin(this.baseUrl);
|
||||
}
|
||||
}
|
||||
|
||||
const skipKeys = [ "enableCcipRead" ];
|
||||
|
||||
let nextId = 1;
|
||||
|
||||
/**
|
||||
* The **EtherscanBaseProvider** is the super-class of
|
||||
* [[EtherscanProvider]], which should generally be used instead.
|
||||
*
|
||||
* Since the **EtherscanProvider** includes additional code for
|
||||
* [[Contract]] access, in //rare cases// that contracts are not
|
||||
* used, this class can reduce code size.
|
||||
*
|
||||
* @_docloc: api/providers/thirdparty:Etherscan
|
||||
*/
|
||||
export class EtherscanProvider extends AbstractProvider {
|
||||
|
||||
/**
|
||||
* The connected network.
|
||||
*/
|
||||
readonly network!: Network;
|
||||
|
||||
/**
|
||||
* The API key or null if using the community provided bandwidth.
|
||||
*/
|
||||
readonly apiKey!: null | string;
|
||||
|
||||
readonly #plugin: null | EtherscanPlugin;
|
||||
|
||||
/**
|
||||
* Creates a new **EtherscanBaseProvider**.
|
||||
*/
|
||||
constructor(_network?: Networkish, _apiKey?: string) {
|
||||
|
||||
const apiKey = (_apiKey != null) ? _apiKey: null;
|
||||
|
||||
super();
|
||||
|
||||
const network = Network.from(_network);
|
||||
|
||||
assertArgument(Supported.indexOf(`${ network.chainId }`) >= 0,
|
||||
"unsupported network", "network", network);
|
||||
|
||||
this.#plugin = network.getPlugin<EtherscanPlugin>(EtherscanPluginId);
|
||||
|
||||
defineProperties<EtherscanProvider>(this, { apiKey, network });
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the base URL.
|
||||
*
|
||||
* If an [[EtherscanPlugin]] is configured on the
|
||||
* [[EtherscanBaseProvider_network]], returns the plugin's
|
||||
* baseUrl.
|
||||
*
|
||||
* Deprecated; for Etherscan v2 the base is no longer a simply
|
||||
* host, but instead a URL including a chainId parameter. Changing
|
||||
* this to return a URL prefix could break some libraries, so it
|
||||
* is left intact but will be removed in the future as it is unused.
|
||||
*/
|
||||
getBaseUrl(): string {
|
||||
if (this.#plugin) { return this.#plugin.baseUrl; }
|
||||
|
||||
switch(this.network.name) {
|
||||
case "mainnet":
|
||||
return "https:/\/api.etherscan.io";
|
||||
case "goerli":
|
||||
return "https:/\/api-goerli.etherscan.io";
|
||||
case "sepolia":
|
||||
return "https:/\/api-sepolia.etherscan.io";
|
||||
case "holesky":
|
||||
return "https:/\/api-holesky.etherscan.io";
|
||||
|
||||
case "arbitrum":
|
||||
return "https:/\/api.arbiscan.io";
|
||||
case "arbitrum-goerli":
|
||||
return "https:/\/api-goerli.arbiscan.io";
|
||||
case "base":
|
||||
return "https:/\/api.basescan.org";
|
||||
case "base-sepolia":
|
||||
return "https:/\/api-sepolia.basescan.org";
|
||||
case "bnb":
|
||||
return "https:/\/api.bscscan.com";
|
||||
case "bnbt":
|
||||
return "https:/\/api-testnet.bscscan.com";
|
||||
case "matic":
|
||||
return "https:/\/api.polygonscan.com";
|
||||
case "matic-amoy":
|
||||
return "https:/\/api-amoy.polygonscan.com";
|
||||
case "matic-mumbai":
|
||||
return "https:/\/api-testnet.polygonscan.com";
|
||||
case "optimism":
|
||||
return "https:/\/api-optimistic.etherscan.io";
|
||||
case "optimism-goerli":
|
||||
return "https:/\/api-goerli-optimistic.etherscan.io";
|
||||
|
||||
default:
|
||||
}
|
||||
|
||||
assertArgument(false, "unsupported network", "network", this.network);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL for the %%module%% and %%params%%.
|
||||
*/
|
||||
getUrl(module: string, params: Record<string, string>): string {
|
||||
let query = Object.keys(params).reduce((accum, key) => {
|
||||
const value = params[key];
|
||||
if (value != null) {
|
||||
accum += `&${ key }=${ value }`
|
||||
}
|
||||
return accum
|
||||
}, "");
|
||||
if (this.apiKey) { query += `&apikey=${ this.apiKey }`; }
|
||||
return `https:/\/api.etherscan.io/v2/api?chainid=${ this.network.chainId }&module=${ module }${ query }`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL for using POST requests.
|
||||
*/
|
||||
getPostUrl(): string {
|
||||
return `https:/\/api.etherscan.io/v2/api?chainid=${ this.network.chainId }`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parameters for using POST requests.
|
||||
*/
|
||||
getPostData(module: string, params: Record<string, any>): Record<string, any> {
|
||||
params.module = module;
|
||||
params.apikey = this.apiKey;
|
||||
params.chainid = this.network.chainId;
|
||||
return params;
|
||||
}
|
||||
|
||||
async detectNetwork(): Promise<Network> {
|
||||
return this.network;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to the result of calling %%module%% with %%params%%.
|
||||
*
|
||||
* If %%post%%, the request is made as a POST request.
|
||||
*/
|
||||
async fetch(module: string, params: Record<string, any>, post?: boolean): Promise<any> {
|
||||
const id = nextId++;
|
||||
|
||||
const url = (post ? this.getPostUrl(): this.getUrl(module, params));
|
||||
const payload = (post ? this.getPostData(module, params): null);
|
||||
|
||||
this.emit("debug", { action: "sendRequest", id, url, payload: payload });
|
||||
|
||||
const request = new FetchRequest(url);
|
||||
request.setThrottleParams({ slotInterval: 1000 });
|
||||
request.retryFunc = (req, resp, attempt: number) => {
|
||||
if (this.isCommunityResource()) {
|
||||
showThrottleMessage("Etherscan");
|
||||
}
|
||||
return Promise.resolve(true);
|
||||
};
|
||||
request.processFunc = async (request, response) => {
|
||||
const result = response.hasBody() ? JSON.parse(toUtf8String(response.body)): { };
|
||||
const throttle = ((typeof(result.result) === "string") ? result.result: "").toLowerCase().indexOf("rate limit") >= 0;
|
||||
if (module === "proxy") {
|
||||
// This JSON response indicates we are being throttled
|
||||
if (result && result.status == 0 && result.message == "NOTOK" && throttle) {
|
||||
this.emit("debug", { action: "receiveError", id, reason: "proxy-NOTOK", error: result });
|
||||
response.throwThrottleError(result.result, THROTTLE);
|
||||
}
|
||||
} else {
|
||||
if (throttle) {
|
||||
this.emit("debug", { action: "receiveError", id, reason: "null result", error: result.result });
|
||||
response.throwThrottleError(result.result, THROTTLE);
|
||||
}
|
||||
}
|
||||
return response;
|
||||
};
|
||||
|
||||
if (payload) {
|
||||
request.setHeader("content-type", "application/x-www-form-urlencoded; charset=UTF-8");
|
||||
request.body = Object.keys(payload).map((k) => `${ k }=${ payload[k] }`).join("&");
|
||||
}
|
||||
|
||||
const response = await request.send();
|
||||
try {
|
||||
response.assertOk();
|
||||
} catch (error) {
|
||||
this.emit("debug", { action: "receiveError", id, error, reason: "assertOk" });
|
||||
assert(false, "response error", "SERVER_ERROR", { request, response });
|
||||
}
|
||||
|
||||
if (!response.hasBody()) {
|
||||
this.emit("debug", { action: "receiveError", id, error: "missing body", reason: "null body" });
|
||||
assert(false, "missing response", "SERVER_ERROR", { request, response });
|
||||
}
|
||||
|
||||
const result = JSON.parse(toUtf8String(response.body));
|
||||
if (module === "proxy") {
|
||||
if (result.jsonrpc != "2.0") {
|
||||
this.emit("debug", { action: "receiveError", id, result, reason: "invalid JSON-RPC" });
|
||||
assert(false, "invalid JSON-RPC response (missing jsonrpc='2.0')", "SERVER_ERROR", { request, response, info: { result } });
|
||||
}
|
||||
|
||||
if (result.error) {
|
||||
this.emit("debug", { action: "receiveError", id, result, reason: "JSON-RPC error" });
|
||||
assert(false, "error response", "SERVER_ERROR", { request, response, info: { result } });
|
||||
}
|
||||
|
||||
this.emit("debug", { action: "receiveRequest", id, result });
|
||||
|
||||
return result.result;
|
||||
|
||||
} else {
|
||||
// getLogs, getHistory have weird success responses
|
||||
if (result.status == 0 && (result.message === "No records found" || result.message === "No transactions found")) {
|
||||
this.emit("debug", { action: "receiveRequest", id, result });
|
||||
return result.result;
|
||||
}
|
||||
|
||||
if (result.status != 1 || (typeof(result.message) === "string" && !result.message.match(/^OK/))) {
|
||||
this.emit("debug", { action: "receiveError", id, result });
|
||||
assert(false, "error response", "SERVER_ERROR", { request, response, info: { result } });
|
||||
}
|
||||
|
||||
this.emit("debug", { action: "receiveRequest", id, result });
|
||||
|
||||
return result.result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns %%transaction%% normalized for the Etherscan API.
|
||||
*/
|
||||
_getTransactionPostData(transaction: TransactionRequest): Record<string, string> {
|
||||
const result: Record<string, string> = { };
|
||||
for (let key in transaction) {
|
||||
if (skipKeys.indexOf(key) >= 0) { continue; }
|
||||
|
||||
if ((<any>transaction)[key] == null) { continue; }
|
||||
let value = (<any>transaction)[key];
|
||||
if (key === "type" && value === 0) { continue; }
|
||||
if (key === "blockTag" && value === "latest") { continue; }
|
||||
|
||||
// Quantity-types require no leading zero, unless 0
|
||||
if ((<any>{ type: true, gasLimit: true, gasPrice: true, maxFeePerGs: true, maxPriorityFeePerGas: true, nonce: true, value: true })[key]) {
|
||||
value = toQuantity(value);
|
||||
|
||||
} else if (key === "accessList") {
|
||||
value = "[" + accessListify(value).map((set) => {
|
||||
return `{address:"${ set.address }",storageKeys:["${ set.storageKeys.join('","') }"]}`;
|
||||
}).join(",") + "]";
|
||||
|
||||
} else if (key === "blobVersionedHashes") {
|
||||
if (value.length === 0) { continue; }
|
||||
|
||||
// @TODO: update this once the API supports blobs
|
||||
assert(false, "Etherscan API does not support blobVersionedHashes", "UNSUPPORTED_OPERATION", {
|
||||
operation: "_getTransactionPostData",
|
||||
info: { transaction }
|
||||
});
|
||||
|
||||
} else {
|
||||
value = hexlify(value);
|
||||
}
|
||||
result[key] = value;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws the normalized Etherscan error.
|
||||
*/
|
||||
_checkError(req: PerformActionRequest, error: Error, transaction: any): never {
|
||||
// Pull any message out if, possible
|
||||
let message = "";
|
||||
if (isError(error, "SERVER_ERROR")) {
|
||||
// Check for an error emitted by a proxy call
|
||||
try {
|
||||
message = (<any>error).info.result.error.message;
|
||||
} catch (e) { }
|
||||
|
||||
if (!message) {
|
||||
try {
|
||||
message = (<any>error).info.message;
|
||||
} catch (e) { }
|
||||
}
|
||||
}
|
||||
|
||||
if (req.method === "estimateGas") {
|
||||
if (!message.match(/revert/i) && message.match(/insufficient funds/i)) {
|
||||
assert(false, "insufficient funds", "INSUFFICIENT_FUNDS", {
|
||||
transaction: req.transaction
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (req.method === "call" || req.method === "estimateGas") {
|
||||
if (message.match(/execution reverted/i)) {
|
||||
let data = "";
|
||||
try {
|
||||
data = (<any>error).info.result.error.data;
|
||||
} catch (error) { }
|
||||
|
||||
const e = AbiCoder.getBuiltinCallException(req.method, <any>req.transaction, data);
|
||||
e.info = { request: req, error }
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
if (message) {
|
||||
if (req.method === "broadcastTransaction") {
|
||||
const transaction = Transaction.from(req.signedTransaction);
|
||||
if (message.match(/replacement/i) && message.match(/underpriced/i)) {
|
||||
assert(false, "replacement fee too low", "REPLACEMENT_UNDERPRICED", {
|
||||
transaction
|
||||
});
|
||||
}
|
||||
|
||||
if (message.match(/insufficient funds/)) {
|
||||
assert(false, "insufficient funds for intrinsic transaction cost", "INSUFFICIENT_FUNDS", {
|
||||
transaction
|
||||
});
|
||||
}
|
||||
|
||||
if (message.match(/same hash was already imported|transaction nonce is too low|nonce too low/)) {
|
||||
assert(false, "nonce has already been used", "NONCE_EXPIRED", {
|
||||
transaction
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Something we could not process
|
||||
throw error;
|
||||
}
|
||||
|
||||
async _detectNetwork(): Promise<Network> {
|
||||
return this.network;
|
||||
}
|
||||
|
||||
async _perform(req: PerformActionRequest): Promise<any> {
|
||||
switch (req.method) {
|
||||
case "chainId":
|
||||
return this.network.chainId;
|
||||
|
||||
case "getBlockNumber":
|
||||
return this.fetch("proxy", { action: "eth_blockNumber" });
|
||||
|
||||
case "getGasPrice":
|
||||
return this.fetch("proxy", { action: "eth_gasPrice" });
|
||||
|
||||
case "getPriorityFee":
|
||||
// This is temporary until Etherscan completes support
|
||||
if (this.network.name === "mainnet") {
|
||||
return "1000000000";
|
||||
} else if (this.network.name === "optimism") {
|
||||
return "1000000";
|
||||
} else {
|
||||
throw new Error("fallback onto the AbstractProvider default");
|
||||
}
|
||||
/* Working with Etherscan to get this added:
|
||||
try {
|
||||
const test = await this.fetch("proxy", {
|
||||
action: "eth_maxPriorityFeePerGas"
|
||||
});
|
||||
console.log(test);
|
||||
return test;
|
||||
} catch (e) {
|
||||
console.log("DEBUG", e);
|
||||
throw e;
|
||||
}
|
||||
*/
|
||||
/* This might be safe; but due to rounding neither myself
|
||||
or Etherscan are necessarily comfortable with this. :)
|
||||
try {
|
||||
const result = await this.fetch("gastracker", { action: "gasoracle" });
|
||||
console.log(result);
|
||||
const gasPrice = parseUnits(result.SafeGasPrice, "gwei");
|
||||
const baseFee = parseUnits(result.suggestBaseFee, "gwei");
|
||||
const priorityFee = gasPrice - baseFee;
|
||||
if (priorityFee < 0) { throw new Error("negative priority fee; defer to abstract provider default"); }
|
||||
return priorityFee;
|
||||
} catch (error) {
|
||||
console.log("DEBUG", error);
|
||||
throw error;
|
||||
}
|
||||
*/
|
||||
|
||||
case "getBalance":
|
||||
// Returns base-10 result
|
||||
return this.fetch("account", {
|
||||
action: "balance",
|
||||
address: req.address,
|
||||
tag: req.blockTag
|
||||
});
|
||||
|
||||
case "getTransactionCount":
|
||||
return this.fetch("proxy", {
|
||||
action: "eth_getTransactionCount",
|
||||
address: req.address,
|
||||
tag: req.blockTag
|
||||
});
|
||||
|
||||
case "getCode":
|
||||
return this.fetch("proxy", {
|
||||
action: "eth_getCode",
|
||||
address: req.address,
|
||||
tag: req.blockTag
|
||||
});
|
||||
|
||||
case "getStorage":
|
||||
return this.fetch("proxy", {
|
||||
action: "eth_getStorageAt",
|
||||
address: req.address,
|
||||
position: req.position,
|
||||
tag: req.blockTag
|
||||
});
|
||||
|
||||
case "broadcastTransaction":
|
||||
return this.fetch("proxy", {
|
||||
action: "eth_sendRawTransaction",
|
||||
hex: req.signedTransaction
|
||||
}, true).catch((error) => {
|
||||
return this._checkError(req, <Error>error, req.signedTransaction);
|
||||
});
|
||||
|
||||
case "getBlock":
|
||||
if ("blockTag" in req) {
|
||||
return this.fetch("proxy", {
|
||||
action: "eth_getBlockByNumber",
|
||||
tag: req.blockTag,
|
||||
boolean: (req.includeTransactions ? "true": "false")
|
||||
});
|
||||
}
|
||||
|
||||
assert(false, "getBlock by blockHash not supported by Etherscan", "UNSUPPORTED_OPERATION", {
|
||||
operation: "getBlock(blockHash)"
|
||||
});
|
||||
|
||||
case "getTransaction":
|
||||
return this.fetch("proxy", {
|
||||
action: "eth_getTransactionByHash",
|
||||
txhash: req.hash
|
||||
});
|
||||
|
||||
case "getTransactionReceipt":
|
||||
return this.fetch("proxy", {
|
||||
action: "eth_getTransactionReceipt",
|
||||
txhash: req.hash
|
||||
});
|
||||
|
||||
case "call": {
|
||||
if (req.blockTag !== "latest") {
|
||||
throw new Error("EtherscanProvider does not support blockTag for call");
|
||||
}
|
||||
|
||||
const postData = this._getTransactionPostData(req.transaction);
|
||||
postData.module = "proxy";
|
||||
postData.action = "eth_call";
|
||||
|
||||
try {
|
||||
return await this.fetch("proxy", postData, true);
|
||||
} catch (error) {
|
||||
return this._checkError(req, <Error>error, req.transaction);
|
||||
}
|
||||
}
|
||||
|
||||
case "estimateGas": {
|
||||
const postData = this._getTransactionPostData(req.transaction);
|
||||
postData.module = "proxy";
|
||||
postData.action = "eth_estimateGas";
|
||||
|
||||
try {
|
||||
return await this.fetch("proxy", postData, true);
|
||||
} catch (error) {
|
||||
return this._checkError(req, <Error>error, req.transaction);
|
||||
}
|
||||
}
|
||||
/*
|
||||
case "getLogs": {
|
||||
// Needs to complain if more than one address is passed in
|
||||
const args: Record<string, any> = { action: "getLogs" }
|
||||
|
||||
if (params.filter.fromBlock) {
|
||||
args.fromBlock = checkLogTag(params.filter.fromBlock);
|
||||
}
|
||||
|
||||
if (params.filter.toBlock) {
|
||||
args.toBlock = checkLogTag(params.filter.toBlock);
|
||||
}
|
||||
|
||||
if (params.filter.address) {
|
||||
args.address = params.filter.address;
|
||||
}
|
||||
|
||||
// @TODO: We can handle slightly more complicated logs using the logs API
|
||||
if (params.filter.topics && params.filter.topics.length > 0) {
|
||||
if (params.filter.topics.length > 1) {
|
||||
logger.throwError("unsupported topic count", Logger.Errors.UNSUPPORTED_OPERATION, { topics: params.filter.topics });
|
||||
}
|
||||
if (params.filter.topics.length === 1) {
|
||||
const topic0 = params.filter.topics[0];
|
||||
if (typeof(topic0) !== "string" || topic0.length !== 66) {
|
||||
logger.throwError("unsupported topic format", Logger.Errors.UNSUPPORTED_OPERATION, { topic0: topic0 });
|
||||
}
|
||||
args.topic0 = topic0;
|
||||
}
|
||||
}
|
||||
|
||||
const logs: Array<any> = await this.fetch("logs", args);
|
||||
|
||||
// Cache txHash => blockHash
|
||||
let blocks: { [tag: string]: string } = {};
|
||||
|
||||
// Add any missing blockHash to the logs
|
||||
for (let i = 0; i < logs.length; i++) {
|
||||
const log = logs[i];
|
||||
if (log.blockHash != null) { continue; }
|
||||
if (blocks[log.blockNumber] == null) {
|
||||
const block = await this.getBlock(log.blockNumber);
|
||||
if (block) {
|
||||
blocks[log.blockNumber] = block.hash;
|
||||
}
|
||||
}
|
||||
|
||||
log.blockHash = blocks[log.blockNumber];
|
||||
}
|
||||
|
||||
return logs;
|
||||
}
|
||||
*/
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return super._perform(req);
|
||||
}
|
||||
|
||||
async getNetwork(): Promise<Network> {
|
||||
return this.network;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to the current price of ether.
|
||||
*
|
||||
* This returns ``0`` on any network other than ``mainnet``.
|
||||
*/
|
||||
async getEtherPrice(): Promise<number> {
|
||||
if (this.network.name !== "mainnet") { return 0.0; }
|
||||
return parseFloat((await this.fetch("stats", { action: "ethprice" })).ethusd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves to a [Contract]] for %%address%%, using the
|
||||
* Etherscan API to retreive the Contract ABI.
|
||||
*/
|
||||
async getContract(_address: string): Promise<null | Contract> {
|
||||
let address = this._getAddress(_address);
|
||||
if (isPromise(address)) { address = await address; }
|
||||
|
||||
try {
|
||||
const resp = await this.fetch("contract", {
|
||||
action: "getabi", address });
|
||||
const abi = JSON.parse(resp);
|
||||
return new Contract(address, abi, this);
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
isCommunityResource(): boolean {
|
||||
return (this.apiKey == null);
|
||||
}
|
||||
}
|
||||
801
dev/env/node_modules/ethers/src.ts/providers/provider-fallback.ts
generated
vendored
Executable file
801
dev/env/node_modules/ethers/src.ts/providers/provider-fallback.ts
generated
vendored
Executable file
@@ -0,0 +1,801 @@
|
||||
/**
|
||||
* A **FallbackProvider** provides resilience, security and performance
|
||||
* in a way that is customizable and configurable.
|
||||
*
|
||||
* @_section: api/providers/fallback-provider:Fallback Provider [about-fallback-provider]
|
||||
*/
|
||||
import {
|
||||
assert, assertArgument, getBigInt, getNumber, isError
|
||||
} from "../utils/index.js";
|
||||
|
||||
import { AbstractProvider } from "./abstract-provider.js";
|
||||
import { Network } from "./network.js"
|
||||
|
||||
import type { PerformActionRequest } from "./abstract-provider.js";
|
||||
import type { Networkish } from "./network.js"
|
||||
|
||||
const BN_1 = BigInt("1");
|
||||
const BN_2 = BigInt("2");
|
||||
|
||||
function shuffle<T = any>(array: Array<T>): void {
|
||||
for (let i = array.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
const tmp = array[i];
|
||||
array[i] = array[j];
|
||||
array[j] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
function stall(duration: number): Promise<void> {
|
||||
return new Promise((resolve) => { setTimeout(resolve, duration); });
|
||||
}
|
||||
|
||||
function getTime(): number { return (new Date()).getTime(); }
|
||||
|
||||
function stringify(value: any): string {
|
||||
return JSON.stringify(value, (key, value) => {
|
||||
if (typeof(value) === "bigint") {
|
||||
return { type: "bigint", value: value.toString() };
|
||||
}
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* A configuration entry for how to use a [[Provider]].
|
||||
*/
|
||||
export interface FallbackProviderConfig {
|
||||
|
||||
/**
|
||||
* The provider.
|
||||
*/
|
||||
provider: AbstractProvider;
|
||||
|
||||
/**
|
||||
* The amount of time to wait before kicking off the next provider.
|
||||
*
|
||||
* Any providers that have not responded can still respond and be
|
||||
* counted, but this ensures new providers start.
|
||||
*/
|
||||
stallTimeout?: number;
|
||||
|
||||
/**
|
||||
* The priority. Lower priority providers are dispatched first.
|
||||
*/
|
||||
priority?: number;
|
||||
|
||||
/**
|
||||
* The amount of weight a provider is given against the quorum.
|
||||
*/
|
||||
weight?: number;
|
||||
};
|
||||
|
||||
const defaultConfig = { stallTimeout: 400, priority: 1, weight: 1 };
|
||||
|
||||
// We track a bunch of extra stuff that might help debug problems or
|
||||
// optimize infrastructure later on.
|
||||
/**
|
||||
* The statistics and state maintained for a [[Provider]].
|
||||
*/
|
||||
export interface FallbackProviderState extends Required<FallbackProviderConfig> {
|
||||
|
||||
/**
|
||||
* The most recent blockNumber this provider has reported (-2 if none).
|
||||
*/
|
||||
blockNumber: number;
|
||||
|
||||
/**
|
||||
* The number of total requests ever sent to this provider.
|
||||
*/
|
||||
requests: number;
|
||||
|
||||
/**
|
||||
* The number of responses that errored.
|
||||
*/
|
||||
errorResponses: number;
|
||||
|
||||
/**
|
||||
* The number of responses that occured after the result resolved.
|
||||
*/
|
||||
lateResponses: number;
|
||||
|
||||
/**
|
||||
* How many times syncing was required to catch up the expected block.
|
||||
*/
|
||||
outOfSync: number;
|
||||
|
||||
/**
|
||||
* The number of requests which reported unsupported operation.
|
||||
*/
|
||||
unsupportedEvents: number;
|
||||
|
||||
/**
|
||||
* A rolling average (5% current duration) for response time.
|
||||
*/
|
||||
rollingDuration: number;
|
||||
|
||||
/**
|
||||
* The ratio of quorum-agreed results to total.
|
||||
*/
|
||||
score: number;
|
||||
}
|
||||
|
||||
interface Config extends FallbackProviderState {
|
||||
_updateNumber: null | Promise<any>;
|
||||
_network: null | Network;
|
||||
_totalTime: number;
|
||||
_lastFatalError: null | Error;
|
||||
_lastFatalErrorTimestamp: number;
|
||||
}
|
||||
|
||||
const defaultState = {
|
||||
blockNumber: -2, requests: 0, lateResponses: 0, errorResponses: 0,
|
||||
outOfSync: -1, unsupportedEvents: 0, rollingDuration: 0, score: 0,
|
||||
_network: null, _updateNumber: null, _totalTime: 0,
|
||||
_lastFatalError: null, _lastFatalErrorTimestamp: 0
|
||||
};
|
||||
|
||||
|
||||
async function waitForSync(config: Config, blockNumber: number): Promise<void> {
|
||||
while (config.blockNumber < 0 || config.blockNumber < blockNumber) {
|
||||
if (!config._updateNumber) {
|
||||
config._updateNumber = (async () => {
|
||||
try {
|
||||
const blockNumber = await config.provider.getBlockNumber();
|
||||
if (blockNumber > config.blockNumber) {
|
||||
config.blockNumber = blockNumber;
|
||||
}
|
||||
} catch (error: any) {
|
||||
config.blockNumber = -2;
|
||||
config._lastFatalError = error;
|
||||
config._lastFatalErrorTimestamp = getTime();
|
||||
}
|
||||
config._updateNumber = null;
|
||||
})();
|
||||
}
|
||||
await config._updateNumber;
|
||||
config.outOfSync++;
|
||||
if (config._lastFatalError) { break; }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Additional options to configure a [[FallbackProvider]].
|
||||
*/
|
||||
export type FallbackProviderOptions = {
|
||||
// How many providers must agree on a value before reporting
|
||||
// back the response
|
||||
quorum?: number;
|
||||
|
||||
// How many providers must have reported the same event
|
||||
// for it to be emitted (currently unimplmented)
|
||||
eventQuorum?: number;
|
||||
|
||||
// How many providers to dispatch each event to simultaneously.
|
||||
// Set this to 0 to use getLog polling, which implies eventQuorum
|
||||
// is equal to quorum. (currently unimplemented)
|
||||
eventWorkers?: number;
|
||||
|
||||
cacheTimeout?: number;
|
||||
|
||||
pollingInterval?: number;
|
||||
};
|
||||
|
||||
type RunnerResult = { result: any } | { error: Error };
|
||||
|
||||
type RunnerState = {
|
||||
config: Config;
|
||||
staller: null | Promise<void>;
|
||||
didBump: boolean;
|
||||
perform: null | Promise<any>;
|
||||
result: null | RunnerResult;
|
||||
}
|
||||
|
||||
function _normalize(value: any): string {
|
||||
if (value == null) { return "null"; }
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
return "[" + (value.map(_normalize)).join(",") + "]";
|
||||
}
|
||||
|
||||
if (typeof(value) === "object" && typeof(value.toJSON) === "function") {
|
||||
return _normalize(value.toJSON());
|
||||
}
|
||||
|
||||
switch (typeof(value)) {
|
||||
case "boolean": case "symbol":
|
||||
return value.toString();
|
||||
case "bigint": case "number":
|
||||
return BigInt(value).toString();
|
||||
case "string":
|
||||
return JSON.stringify(value);
|
||||
case "object": {
|
||||
const keys = Object.keys(value);
|
||||
keys.sort();
|
||||
return "{" + keys.map((k) => `${ JSON.stringify(k) }:${ _normalize(value[k]) }`).join(",") + "}";
|
||||
}
|
||||
}
|
||||
|
||||
console.log("Could not serialize", value);
|
||||
throw new Error("Hmm...");
|
||||
}
|
||||
|
||||
function normalizeResult(method: string, value: RunnerResult): { tag: string, value: any } {
|
||||
|
||||
if ("error" in value) {
|
||||
const error = value.error;
|
||||
|
||||
let tag: string;
|
||||
if (isError(error, "CALL_EXCEPTION")) {
|
||||
tag = _normalize(Object.assign({ }, error, {
|
||||
shortMessage: undefined, reason: undefined, info: undefined
|
||||
}));
|
||||
} else {
|
||||
tag = _normalize(error)
|
||||
}
|
||||
|
||||
return { tag, value: error };
|
||||
}
|
||||
|
||||
const result = value.result;
|
||||
return { tag: _normalize(result), value: result };
|
||||
}
|
||||
|
||||
type TallyResult = {
|
||||
tag: string;
|
||||
value: any;
|
||||
weight: number;
|
||||
};
|
||||
|
||||
// This strategy picks the highest weight result, as long as the weight is
|
||||
// equal to or greater than quorum
|
||||
function checkQuorum(quorum: number, results: Array<TallyResult>): any | Error {
|
||||
const tally: Map<string, { value: any, weight: number }> = new Map();
|
||||
for (const { value, tag, weight } of results) {
|
||||
const t = tally.get(tag) || { value, weight: 0 };
|
||||
t.weight += weight;
|
||||
tally.set(tag, t);
|
||||
}
|
||||
|
||||
let best: null | { value: any, weight: number } = null;
|
||||
for (const r of tally.values()) {
|
||||
if (r.weight >= quorum && (!best || r.weight > best.weight)) {
|
||||
best = r;
|
||||
}
|
||||
}
|
||||
|
||||
if (best) { return best.value; }
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getMedian(quorum: number, results: Array<TallyResult>): undefined | bigint | Error {
|
||||
let resultWeight = 0;
|
||||
|
||||
const errorMap: Map<string, { weight: number, value: Error }> = new Map();
|
||||
let bestError: null | { weight: number, value: Error } = null;
|
||||
|
||||
const values: Array<bigint> = [ ];
|
||||
for (const { value, tag, weight } of results) {
|
||||
if (value instanceof Error) {
|
||||
const e = errorMap.get(tag) || { value, weight: 0 };
|
||||
e.weight += weight;
|
||||
errorMap.set(tag, e);
|
||||
|
||||
if (bestError == null || e.weight > bestError.weight) { bestError = e; }
|
||||
} else {
|
||||
values.push(BigInt(value));
|
||||
resultWeight += weight;
|
||||
}
|
||||
}
|
||||
|
||||
if (resultWeight < quorum) {
|
||||
// We have quorum for an error
|
||||
if (bestError && bestError.weight >= quorum) { return bestError.value; }
|
||||
|
||||
// We do not have quorum for a result
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Get the sorted values
|
||||
values.sort((a, b) => ((a < b) ? -1: (b > a) ? 1: 0));
|
||||
|
||||
const mid = Math.floor(values.length / 2);
|
||||
|
||||
// Odd-length; take the middle value
|
||||
if (values.length % 2) { return values[mid]; }
|
||||
|
||||
// Even length; take the ceiling of the mean of the center two values
|
||||
return (values[mid - 1] + values[mid] + BN_1) / BN_2;
|
||||
}
|
||||
|
||||
function getAnyResult(quorum: number, results: Array<TallyResult>): undefined | any | Error {
|
||||
// If any value or error meets quorum, that is our preferred result
|
||||
const result = checkQuorum(quorum, results);
|
||||
if (result !== undefined) { return result; }
|
||||
|
||||
// Otherwise, do we have any result?
|
||||
for (const r of results) {
|
||||
if (r.value) { return r.value; }
|
||||
}
|
||||
|
||||
// Nope!
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getFuzzyMode(quorum: number, results: Array<TallyResult>): undefined | number {
|
||||
if (quorum === 1) { return getNumber(<bigint>getMedian(quorum, results), "%internal"); }
|
||||
|
||||
const tally: Map<number, { result: number, weight: number }> = new Map();
|
||||
const add = (result: number, weight: number) => {
|
||||
const t = tally.get(result) || { result, weight: 0 };
|
||||
t.weight += weight;
|
||||
tally.set(result, t);
|
||||
};
|
||||
|
||||
for (const { weight, value } of results) {
|
||||
const r = getNumber(value);
|
||||
add(r - 1, weight);
|
||||
add(r, weight);
|
||||
add(r + 1, weight);
|
||||
}
|
||||
|
||||
let bestWeight = 0;
|
||||
let bestResult: undefined | number = undefined;
|
||||
|
||||
for (const { weight, result } of tally.values()) {
|
||||
// Use this result, if this result meets quorum and has either:
|
||||
// - a better weight
|
||||
// - or equal weight, but the result is larger
|
||||
if (weight >= quorum && (weight > bestWeight || (bestResult != null && weight === bestWeight && result > bestResult))) {
|
||||
bestWeight = weight;
|
||||
bestResult = result;
|
||||
}
|
||||
}
|
||||
|
||||
return bestResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* A **FallbackProvider** manages several [[Providers]] providing
|
||||
* resilience by switching between slow or misbehaving nodes, security
|
||||
* by requiring multiple backends to aggree and performance by allowing
|
||||
* faster backends to respond earlier.
|
||||
*
|
||||
*/
|
||||
export class FallbackProvider extends AbstractProvider {
|
||||
|
||||
/**
|
||||
* The number of backends that must agree on a value before it is
|
||||
* accpeted.
|
||||
*/
|
||||
readonly quorum: number;
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
readonly eventQuorum: number;
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
readonly eventWorkers: number;
|
||||
|
||||
readonly #configs: Array<Config>;
|
||||
|
||||
#height: number;
|
||||
#initialSyncPromise: null | Promise<void>;
|
||||
|
||||
/**
|
||||
* Creates a new **FallbackProvider** with %%providers%% connected to
|
||||
* %%network%%.
|
||||
*
|
||||
* If a [[Provider]] is included in %%providers%%, defaults are used
|
||||
* for the configuration.
|
||||
*/
|
||||
constructor(providers: Array<AbstractProvider | FallbackProviderConfig>, network?: Networkish, options?: FallbackProviderOptions) {
|
||||
super(network, options);
|
||||
|
||||
this.#configs = providers.map((p) => {
|
||||
if (p instanceof AbstractProvider) {
|
||||
return Object.assign({ provider: p }, defaultConfig, defaultState );
|
||||
} else {
|
||||
return Object.assign({ }, defaultConfig, p, defaultState );
|
||||
}
|
||||
});
|
||||
|
||||
this.#height = -2;
|
||||
this.#initialSyncPromise = null;
|
||||
|
||||
if (options && options.quorum != null) {
|
||||
this.quorum = options.quorum;
|
||||
} else {
|
||||
this.quorum = Math.ceil(this.#configs.reduce((accum, config) => {
|
||||
accum += config.weight;
|
||||
return accum;
|
||||
}, 0) / 2);
|
||||
}
|
||||
|
||||
this.eventQuorum = 1;
|
||||
this.eventWorkers = 1;
|
||||
|
||||
assertArgument(this.quorum <= this.#configs.reduce((a, c) => (a + c.weight), 0),
|
||||
"quorum exceed provider weight", "quorum", this.quorum);
|
||||
}
|
||||
|
||||
get providerConfigs(): Array<FallbackProviderState> {
|
||||
return this.#configs.map((c) => {
|
||||
const result: any = Object.assign({ }, c);
|
||||
for (const key in result) {
|
||||
if (key[0] === "_") { delete result[key]; }
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
async _detectNetwork(): Promise<Network> {
|
||||
return Network.from(getBigInt(await this._perform({ method: "chainId" })));
|
||||
}
|
||||
|
||||
// @TODO: Add support to select providers to be the event subscriber
|
||||
//_getSubscriber(sub: Subscription): Subscriber {
|
||||
// throw new Error("@TODO");
|
||||
//}
|
||||
|
||||
/**
|
||||
* Transforms a %%req%% into the correct method call on %%provider%%.
|
||||
*/
|
||||
async _translatePerform(provider: AbstractProvider, req: PerformActionRequest): Promise<any> {
|
||||
switch (req.method) {
|
||||
case "broadcastTransaction":
|
||||
return await provider.broadcastTransaction(req.signedTransaction);
|
||||
case "call":
|
||||
return await provider.call(Object.assign({ }, req.transaction, { blockTag: req.blockTag }));
|
||||
case "chainId":
|
||||
return (await provider.getNetwork()).chainId;
|
||||
case "estimateGas":
|
||||
return await provider.estimateGas(req.transaction);
|
||||
case "getBalance":
|
||||
return await provider.getBalance(req.address, req.blockTag);
|
||||
case "getBlock": {
|
||||
const block = ("blockHash" in req) ? req.blockHash: req.blockTag;
|
||||
return await provider.getBlock(block, req.includeTransactions);
|
||||
}
|
||||
case "getBlockNumber":
|
||||
return await provider.getBlockNumber();
|
||||
case "getCode":
|
||||
return await provider.getCode(req.address, req.blockTag);
|
||||
case "getGasPrice":
|
||||
return (await provider.getFeeData()).gasPrice;
|
||||
case "getPriorityFee":
|
||||
return (await provider.getFeeData()).maxPriorityFeePerGas;
|
||||
case "getLogs":
|
||||
return await provider.getLogs(req.filter);
|
||||
case "getStorage":
|
||||
return await provider.getStorage(req.address, req.position, req.blockTag);
|
||||
case "getTransaction":
|
||||
return await provider.getTransaction(req.hash);
|
||||
case "getTransactionCount":
|
||||
return await provider.getTransactionCount(req.address, req.blockTag);
|
||||
case "getTransactionReceipt":
|
||||
return await provider.getTransactionReceipt(req.hash);
|
||||
case "getTransactionResult":
|
||||
return await provider.getTransactionResult(req.hash);
|
||||
}
|
||||
}
|
||||
|
||||
// Grab the next (random) config that is not already part of
|
||||
// the running set
|
||||
#getNextConfig(running: Set<RunnerState>): null | Config {
|
||||
// @TODO: Maybe do a check here to favour (heavily) providers that
|
||||
// do not require waitForSync and disfavour providers that
|
||||
// seem down-ish or are behaving slowly
|
||||
|
||||
const configs = Array.from(running).map((r) => r.config)
|
||||
|
||||
// Shuffle the states, sorted by priority
|
||||
const allConfigs = this.#configs.slice();
|
||||
shuffle(allConfigs);
|
||||
allConfigs.sort((a, b) => (a.priority - b.priority));
|
||||
|
||||
for (const config of allConfigs) {
|
||||
if (config._lastFatalError) { continue; }
|
||||
if (configs.indexOf(config) === -1) { return config; }
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Adds a new runner (if available) to running.
|
||||
#addRunner(running: Set<RunnerState>, req: PerformActionRequest): null | RunnerState {
|
||||
const config = this.#getNextConfig(running);
|
||||
|
||||
// No runners available
|
||||
if (config == null) { return null; }
|
||||
|
||||
// Create a new runner
|
||||
const runner: RunnerState = {
|
||||
config, result: null, didBump: false,
|
||||
perform: null, staller: null
|
||||
};
|
||||
|
||||
const now = getTime();
|
||||
|
||||
// Start performing this operation
|
||||
runner.perform = (async () => {
|
||||
try {
|
||||
config.requests++;
|
||||
const result = await this._translatePerform(config.provider, req);
|
||||
runner.result = { result };
|
||||
} catch (error: any) {
|
||||
config.errorResponses++;
|
||||
runner.result = { error };
|
||||
}
|
||||
|
||||
const dt = (getTime() - now);
|
||||
config._totalTime += dt;
|
||||
|
||||
config.rollingDuration = 0.95 * config.rollingDuration + 0.05 * dt;
|
||||
|
||||
runner.perform = null;
|
||||
})();
|
||||
|
||||
// Start a staller; when this times out, it's time to force
|
||||
// kicking off another runner because we are taking too long
|
||||
runner.staller = (async () => {
|
||||
await stall(config.stallTimeout);
|
||||
runner.staller = null;
|
||||
})();
|
||||
|
||||
running.add(runner);
|
||||
return runner;
|
||||
}
|
||||
|
||||
// Initializes the blockNumber and network for each runner and
|
||||
// blocks until initialized
|
||||
async #initialSync(): Promise<void> {
|
||||
let initialSync = this.#initialSyncPromise;
|
||||
if (!initialSync) {
|
||||
const promises: Array<Promise<any>> = [ ];
|
||||
this.#configs.forEach((config) => {
|
||||
promises.push((async () => {
|
||||
await waitForSync(config, 0);
|
||||
if (!config._lastFatalError) {
|
||||
config._network = await config.provider.getNetwork();
|
||||
}
|
||||
})());
|
||||
});
|
||||
|
||||
this.#initialSyncPromise = initialSync = (async () => {
|
||||
// Wait for all providers to have a block number and network
|
||||
await Promise.all(promises);
|
||||
|
||||
// Check all the networks match
|
||||
let chainId: null | bigint = null;
|
||||
for (const config of this.#configs) {
|
||||
if (config._lastFatalError) { continue; }
|
||||
const network = <Network>(config._network);
|
||||
if (chainId == null) {
|
||||
chainId = network.chainId;
|
||||
} else if (network.chainId !== chainId) {
|
||||
assert(false, "cannot mix providers on different networks", "UNSUPPORTED_OPERATION", {
|
||||
operation: "new FallbackProvider"
|
||||
});
|
||||
}
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
await initialSync
|
||||
}
|
||||
|
||||
|
||||
async #checkQuorum(running: Set<RunnerState>, req: PerformActionRequest): Promise<any> {
|
||||
// Get all the result objects
|
||||
const results: Array<TallyResult> = [ ];
|
||||
for (const runner of running) {
|
||||
if (runner.result != null) {
|
||||
const { tag, value } = normalizeResult(req.method, runner.result);
|
||||
results.push({ tag, value, weight: runner.config.weight });
|
||||
}
|
||||
}
|
||||
|
||||
// Are there enough results to event meet quorum?
|
||||
if (results.reduce((a, r) => (a + r.weight), 0) < this.quorum) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
switch (req.method) {
|
||||
case "getBlockNumber": {
|
||||
// We need to get the bootstrap block height
|
||||
if (this.#height === -2) {
|
||||
this.#height = Math.ceil(getNumber(<bigint>getMedian(this.quorum, this.#configs.filter((c) => (!c._lastFatalError)).map((c) => ({
|
||||
value: c.blockNumber,
|
||||
tag: getNumber(c.blockNumber).toString(),
|
||||
weight: c.weight
|
||||
})))));
|
||||
}
|
||||
|
||||
// Find the mode across all the providers, allowing for
|
||||
// a little drift between block heights
|
||||
const mode = getFuzzyMode(this.quorum, results);
|
||||
if (mode === undefined) { return undefined; }
|
||||
if (mode > this.#height) { this.#height = mode; }
|
||||
return this.#height;
|
||||
}
|
||||
|
||||
case "getGasPrice":
|
||||
case "getPriorityFee":
|
||||
case "estimateGas":
|
||||
return getMedian(this.quorum, results);
|
||||
|
||||
case "getBlock":
|
||||
// Pending blocks are in the mempool and already
|
||||
// quite untrustworthy; just grab anything
|
||||
if ("blockTag" in req && req.blockTag === "pending") {
|
||||
return getAnyResult(this.quorum, results);
|
||||
}
|
||||
return checkQuorum(this.quorum, results);
|
||||
|
||||
case "call":
|
||||
case "chainId":
|
||||
case "getBalance":
|
||||
case "getTransactionCount":
|
||||
case "getCode":
|
||||
case "getStorage":
|
||||
case "getTransaction":
|
||||
case "getTransactionReceipt":
|
||||
case "getLogs":
|
||||
return checkQuorum(this.quorum, results);
|
||||
|
||||
case "broadcastTransaction":
|
||||
return getAnyResult(this.quorum, results);
|
||||
}
|
||||
|
||||
assert(false, "unsupported method", "UNSUPPORTED_OPERATION", {
|
||||
operation: `_perform(${ stringify((<any>req).method) })`
|
||||
});
|
||||
}
|
||||
|
||||
async #waitForQuorum(running: Set<RunnerState>, req: PerformActionRequest): Promise<any> {
|
||||
if (running.size === 0) { throw new Error("no runners?!"); }
|
||||
|
||||
// Any promises that are interesting to watch for; an expired stall
|
||||
// or a successful perform
|
||||
const interesting: Array<Promise<void>> = [ ];
|
||||
|
||||
let newRunners = 0;
|
||||
for (const runner of running) {
|
||||
|
||||
// No responses, yet; keep an eye on it
|
||||
if (runner.perform) {
|
||||
interesting.push(runner.perform);
|
||||
}
|
||||
|
||||
// Still stalling...
|
||||
if (runner.staller) {
|
||||
interesting.push(runner.staller);
|
||||
continue;
|
||||
}
|
||||
|
||||
// This runner has already triggered another runner
|
||||
if (runner.didBump) { continue; }
|
||||
|
||||
// Got a response (result or error) or stalled; kick off another runner
|
||||
runner.didBump = true;
|
||||
newRunners++;
|
||||
}
|
||||
|
||||
// Check if we have reached quorum on a result (or error)
|
||||
const value = await this.#checkQuorum(running, req);
|
||||
if (value !== undefined) {
|
||||
if (value instanceof Error) { throw value; }
|
||||
return value;
|
||||
}
|
||||
|
||||
// Add any new runners, because a staller timed out or a result
|
||||
// or error response came in.
|
||||
for (let i = 0; i < newRunners; i++) {
|
||||
this.#addRunner(running, req);
|
||||
}
|
||||
|
||||
// All providers have returned, and we have no result
|
||||
|
||||
assert(interesting.length > 0, "quorum not met", "SERVER_ERROR", {
|
||||
request: "%sub-requests",
|
||||
info: { request: req, results: Array.from(running).map((r) => stringify(r.result)) }
|
||||
});
|
||||
|
||||
// Wait for someone to either complete its perform or stall out
|
||||
await Promise.race(interesting);
|
||||
|
||||
// This is recursive, but at worst case the depth is 2x the
|
||||
// number of providers (each has a perform and a staller)
|
||||
return await this.#waitForQuorum(running, req);
|
||||
}
|
||||
|
||||
async _perform<T = any>(req: PerformActionRequest): Promise<T> {
|
||||
// Broadcasting a transaction is rare (ish) and already incurs
|
||||
// a cost on the user, so spamming is safe-ish. Just send it to
|
||||
// every backend.
|
||||
if (req.method === "broadcastTransaction") {
|
||||
// Once any broadcast provides a positive result, use it. No
|
||||
// need to wait for anyone else
|
||||
const results: Array<null | TallyResult> = this.#configs.map((c) => null);
|
||||
const broadcasts = this.#configs.map(async ({ provider, weight }, index) => {
|
||||
try {
|
||||
const result = await provider._perform(req);
|
||||
results[index] = Object.assign(normalizeResult(req.method, { result }), { weight });
|
||||
} catch (error: any) {
|
||||
results[index] = Object.assign(normalizeResult(req.method, { error }), { weight });
|
||||
}
|
||||
});
|
||||
|
||||
// As each promise finishes...
|
||||
while (true) {
|
||||
// Check for a valid broadcast result
|
||||
const done = <Array<any>>results.filter((r) => (r != null));
|
||||
for (const { value } of done) {
|
||||
if (!(value instanceof Error)) { return value; }
|
||||
}
|
||||
|
||||
// Check for a legit broadcast error (one which we cannot
|
||||
// recover from; some nodes may return the following red
|
||||
// herring events:
|
||||
// - alredy seend (UNKNOWN_ERROR)
|
||||
// - NONCE_EXPIRED
|
||||
// - REPLACEMENT_UNDERPRICED
|
||||
const result = checkQuorum(this.quorum, <Array<any>>results.filter((r) => (r != null)));
|
||||
if (isError(result, "INSUFFICIENT_FUNDS")) {
|
||||
throw result;
|
||||
}
|
||||
|
||||
// Kick off the next provider (if any)
|
||||
const waiting = broadcasts.filter((b, i) => (results[i] == null));
|
||||
if (waiting.length === 0) { break; }
|
||||
await Promise.race(waiting);
|
||||
}
|
||||
|
||||
// Use standard quorum results; any result was returned above,
|
||||
// so this will find any error that met quorum if any
|
||||
const result = getAnyResult(this.quorum, <Array<any>>results);
|
||||
assert(result !== undefined, "problem multi-broadcasting", "SERVER_ERROR", {
|
||||
request: "%sub-requests",
|
||||
info: { request: req, results: results.map(stringify) }
|
||||
})
|
||||
if (result instanceof Error) { throw result; }
|
||||
return result;
|
||||
}
|
||||
|
||||
await this.#initialSync();
|
||||
|
||||
// Bootstrap enough runners to meet quorum
|
||||
const running: Set<RunnerState> = new Set();
|
||||
let inflightQuorum = 0;
|
||||
while (true) {
|
||||
const runner = this.#addRunner(running, req);
|
||||
if (runner == null) { break; }
|
||||
inflightQuorum += runner.config.weight;
|
||||
if (inflightQuorum >= this.quorum) { break; }
|
||||
}
|
||||
|
||||
const result = await this.#waitForQuorum(running, req);
|
||||
|
||||
// Track requests sent to a provider that are still
|
||||
// outstanding after quorum has been otherwise found
|
||||
for (const runner of running) {
|
||||
if (runner.perform && runner.result == null) {
|
||||
runner.config.lateResponses++;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async destroy(): Promise<void> {
|
||||
for (const { provider } of this.#configs) {
|
||||
provider.destroy();
|
||||
}
|
||||
super.destroy();
|
||||
}
|
||||
}
|
||||
220
dev/env/node_modules/ethers/src.ts/providers/provider-infura.ts
generated
vendored
Executable file
220
dev/env/node_modules/ethers/src.ts/providers/provider-infura.ts
generated
vendored
Executable file
@@ -0,0 +1,220 @@
|
||||
/**
|
||||
* [[link-infura]] provides a third-party service for connecting to
|
||||
* various blockchains over JSON-RPC.
|
||||
*
|
||||
* **Supported Networks**
|
||||
*
|
||||
* - Ethereum Mainnet (``mainnet``)
|
||||
* - Goerli Testnet (``goerli``)
|
||||
* - Sepolia Testnet (``sepolia``)
|
||||
* - Arbitrum (``arbitrum``)
|
||||
* - Arbitrum Goerli Testnet (``arbitrum-goerli``)
|
||||
* - Arbitrum Sepolia Testnet (``arbitrum-sepolia``)
|
||||
* - Base (``base``)
|
||||
* - Base Goerlia Testnet (``base-goerli``)
|
||||
* - Base Sepolia Testnet (``base-sepolia``)
|
||||
* - BNB Smart Chain Mainnet (``bnb``)
|
||||
* - BNB Smart Chain Testnet (``bnbt``)
|
||||
* - Linea (``linea``)
|
||||
* - Linea Goerli Testnet (``linea-goerli``)
|
||||
* - Linea Sepolia Testnet (``linea-sepolia``)
|
||||
* - Optimism (``optimism``)
|
||||
* - Optimism Goerli Testnet (``optimism-goerli``)
|
||||
* - Optimism Sepolia Testnet (``optimism-sepolia``)
|
||||
* - Polygon (``matic``)
|
||||
* - Polygon Amoy Testnet (``matic-amoy``)
|
||||
* - Polygon Mumbai Testnet (``matic-mumbai``)
|
||||
*
|
||||
* @_subsection: api/providers/thirdparty:INFURA [providers-infura]
|
||||
*/
|
||||
import {
|
||||
defineProperties, FetchRequest, assert, assertArgument
|
||||
} from "../utils/index.js";
|
||||
|
||||
import { showThrottleMessage } from "./community.js";
|
||||
import { Network } from "./network.js";
|
||||
import { JsonRpcProvider } from "./provider-jsonrpc.js";
|
||||
import { WebSocketProvider } from "./provider-websocket.js";
|
||||
|
||||
import type { AbstractProvider } from "./abstract-provider.js";
|
||||
import type { CommunityResourcable } from "./community.js";
|
||||
import type { Networkish } from "./network.js";
|
||||
|
||||
|
||||
const defaultProjectId = "84842078b09946638c03157f83405213";
|
||||
|
||||
function getHost(name: string): string {
|
||||
switch(name) {
|
||||
case "mainnet":
|
||||
return "mainnet.infura.io";
|
||||
case "goerli":
|
||||
return "goerli.infura.io";
|
||||
case "sepolia":
|
||||
return "sepolia.infura.io";
|
||||
|
||||
case "arbitrum":
|
||||
return "arbitrum-mainnet.infura.io";
|
||||
case "arbitrum-goerli":
|
||||
return "arbitrum-goerli.infura.io";
|
||||
case "arbitrum-sepolia":
|
||||
return "arbitrum-sepolia.infura.io";
|
||||
case "base":
|
||||
return "base-mainnet.infura.io";
|
||||
case "base-goerlia": // @TODO: Remove this typo in the future!
|
||||
case "base-goerli":
|
||||
return "base-goerli.infura.io";
|
||||
case "base-sepolia":
|
||||
return "base-sepolia.infura.io";
|
||||
case "bnb":
|
||||
return "bsc-mainnet.infura.io";
|
||||
case "bnbt":
|
||||
return "bsc-testnet.infura.io";
|
||||
case "linea":
|
||||
return "linea-mainnet.infura.io";
|
||||
case "linea-goerli":
|
||||
return "linea-goerli.infura.io";
|
||||
case "linea-sepolia":
|
||||
return "linea-sepolia.infura.io";
|
||||
case "matic":
|
||||
return "polygon-mainnet.infura.io";
|
||||
case "matic-amoy":
|
||||
return "polygon-amoy.infura.io";
|
||||
case "matic-mumbai":
|
||||
return "polygon-mumbai.infura.io";
|
||||
case "optimism":
|
||||
return "optimism-mainnet.infura.io";
|
||||
case "optimism-goerli":
|
||||
return "optimism-goerli.infura.io";
|
||||
case "optimism-sepolia":
|
||||
return "optimism-sepolia.infura.io";
|
||||
}
|
||||
|
||||
assertArgument(false, "unsupported network", "network", name);
|
||||
}
|
||||
|
||||
/**
|
||||
* The **InfuraWebSocketProvider** connects to the [[link-infura]]
|
||||
* WebSocket end-points.
|
||||
*
|
||||
* By default, a highly-throttled API key is used, which is
|
||||
* appropriate for quick prototypes and simple scripts. To
|
||||
* gain access to an increased rate-limit, it is highly
|
||||
* recommended to [sign up here](link-infura-signup).
|
||||
*/
|
||||
export class InfuraWebSocketProvider extends WebSocketProvider implements CommunityResourcable {
|
||||
|
||||
/**
|
||||
* The Project ID for the INFURA connection.
|
||||
*/
|
||||
readonly projectId!: string;
|
||||
|
||||
/**
|
||||
* The Project Secret.
|
||||
*
|
||||
* If null, no authenticated requests are made. This should not
|
||||
* be used outside of private contexts.
|
||||
*/
|
||||
readonly projectSecret!: null | string;
|
||||
|
||||
/**
|
||||
* Creates a new **InfuraWebSocketProvider**.
|
||||
*/
|
||||
constructor(network?: Networkish, projectId?: string) {
|
||||
const provider = new InfuraProvider(network, projectId);
|
||||
|
||||
const req = provider._getConnection();
|
||||
assert(!req.credentials, "INFURA WebSocket project secrets unsupported",
|
||||
"UNSUPPORTED_OPERATION", { operation: "InfuraProvider.getWebSocketProvider()" });
|
||||
|
||||
const url = req.url.replace(/^http/i, "ws").replace("/v3/", "/ws/v3/");
|
||||
super(url, provider._network);
|
||||
|
||||
defineProperties<InfuraWebSocketProvider>(this, {
|
||||
projectId: provider.projectId,
|
||||
projectSecret: provider.projectSecret
|
||||
});
|
||||
}
|
||||
|
||||
isCommunityResource(): boolean {
|
||||
return (this.projectId === defaultProjectId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The **InfuraProvider** connects to the [[link-infura]]
|
||||
* JSON-RPC end-points.
|
||||
*
|
||||
* By default, a highly-throttled API key is used, which is
|
||||
* appropriate for quick prototypes and simple scripts. To
|
||||
* gain access to an increased rate-limit, it is highly
|
||||
* recommended to [sign up here](link-infura-signup).
|
||||
*/
|
||||
export class InfuraProvider extends JsonRpcProvider implements CommunityResourcable {
|
||||
/**
|
||||
* The Project ID for the INFURA connection.
|
||||
*/
|
||||
readonly projectId!: string;
|
||||
|
||||
/**
|
||||
* The Project Secret.
|
||||
*
|
||||
* If null, no authenticated requests are made. This should not
|
||||
* be used outside of private contexts.
|
||||
*/
|
||||
readonly projectSecret!: null | string;
|
||||
|
||||
/**
|
||||
* Creates a new **InfuraProvider**.
|
||||
*/
|
||||
constructor(_network?: Networkish, projectId?: null | string, projectSecret?: null | string) {
|
||||
if (_network == null) { _network = "mainnet"; }
|
||||
const network = Network.from(_network);
|
||||
if (projectId == null) { projectId = defaultProjectId; }
|
||||
if (projectSecret == null) { projectSecret = null; }
|
||||
|
||||
const request = InfuraProvider.getRequest(network, projectId, projectSecret);
|
||||
super(request, network, { staticNetwork: network });
|
||||
|
||||
defineProperties<InfuraProvider>(this, { projectId, projectSecret });
|
||||
}
|
||||
|
||||
_getProvider(chainId: number): AbstractProvider {
|
||||
try {
|
||||
return new InfuraProvider(chainId, this.projectId, this.projectSecret);
|
||||
} catch (error) { }
|
||||
return super._getProvider(chainId);
|
||||
}
|
||||
|
||||
isCommunityResource(): boolean {
|
||||
return (this.projectId === defaultProjectId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new **InfuraWebSocketProvider**.
|
||||
*/
|
||||
static getWebSocketProvider(network?: Networkish, projectId?: string): InfuraWebSocketProvider {
|
||||
return new InfuraWebSocketProvider(network, projectId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a prepared request for connecting to %%network%%
|
||||
* with %%projectId%% and %%projectSecret%%.
|
||||
*/
|
||||
static getRequest(network: Network, projectId?: null | string, projectSecret?: null | string): FetchRequest {
|
||||
if (projectId == null) { projectId = defaultProjectId; }
|
||||
if (projectSecret == null) { projectSecret = null; }
|
||||
|
||||
const request = new FetchRequest(`https:/\/${ getHost(network.name) }/v3/${ projectId }`);
|
||||
request.allowGzip = true;
|
||||
if (projectSecret) { request.setCredentials("", projectSecret); }
|
||||
|
||||
if (projectId === defaultProjectId) {
|
||||
request.retryFunc = async (request, response, attempt) => {
|
||||
showThrottleMessage("InfuraProvider");
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
}
|
||||
3
dev/env/node_modules/ethers/src.ts/providers/provider-ipcsocket-browser.ts
generated
vendored
Executable file
3
dev/env/node_modules/ethers/src.ts/providers/provider-ipcsocket-browser.ts
generated
vendored
Executable file
@@ -0,0 +1,3 @@
|
||||
const IpcSocketProvider = undefined;
|
||||
|
||||
export { IpcSocketProvider };
|
||||
81
dev/env/node_modules/ethers/src.ts/providers/provider-ipcsocket.ts
generated
vendored
Executable file
81
dev/env/node_modules/ethers/src.ts/providers/provider-ipcsocket.ts
generated
vendored
Executable file
@@ -0,0 +1,81 @@
|
||||
|
||||
import { connect } from "net";
|
||||
import { SocketProvider } from "./provider-socket.js";
|
||||
|
||||
import type { Socket } from "net";
|
||||
|
||||
import type { JsonRpcApiProviderOptions } from "./provider-jsonrpc.js";
|
||||
import type { Networkish } from "./network.js";
|
||||
|
||||
|
||||
// @TODO: Is this sufficient? Is this robust? Will newlines occur between
|
||||
// all payloads and only between payloads?
|
||||
function splitBuffer(data: Buffer): { messages: Array<string>, remaining: Buffer } {
|
||||
const messages: Array<string> = [ ];
|
||||
|
||||
let lastStart = 0;
|
||||
while (true) {
|
||||
const nl = data.indexOf(10, lastStart);
|
||||
if (nl === -1) { break; }
|
||||
messages.push(data.subarray(lastStart, nl).toString().trim());
|
||||
lastStart = nl + 1;
|
||||
}
|
||||
|
||||
return { messages, remaining: data.subarray(lastStart) };
|
||||
}
|
||||
|
||||
/**
|
||||
* An **IpcSocketProvider** connects over an IPC socket on the host
|
||||
* which provides fast access to the node, but requires the node and
|
||||
* the script run on the same machine.
|
||||
*/
|
||||
export class IpcSocketProvider extends SocketProvider {
|
||||
#socket: Socket;
|
||||
|
||||
/**
|
||||
* The connected socket.
|
||||
*/
|
||||
get socket(): Socket { return this.#socket; }
|
||||
|
||||
constructor(path: string, network?: Networkish, options?: JsonRpcApiProviderOptions) {
|
||||
super(network, options);
|
||||
this.#socket = connect(path);
|
||||
|
||||
this.socket.on("ready", async () => {
|
||||
try {
|
||||
await this._start();
|
||||
} catch (error) {
|
||||
console.log("failed to start IpcSocketProvider", error);
|
||||
// @TODO: Now what? Restart?
|
||||
}
|
||||
});
|
||||
|
||||
let response = Buffer.alloc(0);
|
||||
this.socket.on("data", (data) => {
|
||||
response = Buffer.concat([ response, data ]);
|
||||
const { messages, remaining } = splitBuffer(response);
|
||||
messages.forEach((message) => {
|
||||
this._processMessage(message);
|
||||
});
|
||||
response = remaining;
|
||||
});
|
||||
|
||||
this.socket.on("end", () => {
|
||||
this.emit("close");
|
||||
this.socket.destroy();
|
||||
this.socket.end();
|
||||
});
|
||||
}
|
||||
|
||||
destroy(): void {
|
||||
this.socket.destroy();
|
||||
this.socket.end();
|
||||
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
async _write(message: string): Promise<void> {
|
||||
if (!message.endsWith("\n")) { message += "\n"; }
|
||||
this.socket.write(message);
|
||||
}
|
||||
}
|
||||
1335
dev/env/node_modules/ethers/src.ts/providers/provider-jsonrpc.ts
generated
vendored
Executable file
1335
dev/env/node_modules/ethers/src.ts/providers/provider-jsonrpc.ts
generated
vendored
Executable file
File diff suppressed because it is too large
Load Diff
121
dev/env/node_modules/ethers/src.ts/providers/provider-pocket.ts
generated
vendored
Executable file
121
dev/env/node_modules/ethers/src.ts/providers/provider-pocket.ts
generated
vendored
Executable file
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* [[link-pocket]] provides a third-party service for connecting to
|
||||
* various blockchains over JSON-RPC.
|
||||
*
|
||||
* **Supported Networks**
|
||||
*
|
||||
* - Ethereum Mainnet (``mainnet``)
|
||||
* - Goerli Testnet (``goerli``)
|
||||
* - Polygon (``matic``)
|
||||
* - Arbitrum (``arbitrum``)
|
||||
*
|
||||
* @_subsection: api/providers/thirdparty:Pocket [providers-pocket]
|
||||
*/
|
||||
import {
|
||||
defineProperties, FetchRequest, assertArgument
|
||||
} from "../utils/index.js";
|
||||
|
||||
import { AbstractProvider } from "./abstract-provider.js";
|
||||
import { showThrottleMessage } from "./community.js";
|
||||
import { Network } from "./network.js";
|
||||
import { JsonRpcProvider } from "./provider-jsonrpc.js";
|
||||
|
||||
import type { CommunityResourcable } from "./community.js";
|
||||
import type { Networkish } from "./network.js";
|
||||
|
||||
const defaultApplicationId = "62e1ad51b37b8e00394bda3b";
|
||||
|
||||
function getHost(name: string): string {
|
||||
switch (name) {
|
||||
case "mainnet":
|
||||
return "eth-mainnet.gateway.pokt.network";
|
||||
case "goerli":
|
||||
return "eth-goerli.gateway.pokt.network";
|
||||
|
||||
case "matic":
|
||||
return "poly-mainnet.gateway.pokt.network";
|
||||
case "matic-mumbai":
|
||||
return "polygon-mumbai-rpc.gateway.pokt.network";
|
||||
}
|
||||
|
||||
assertArgument(false, "unsupported network", "network", name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The **PocketProvider** connects to the [[link-pocket]]
|
||||
* JSON-RPC end-points.
|
||||
*
|
||||
* By default, a highly-throttled API key is used, which is
|
||||
* appropriate for quick prototypes and simple scripts. To
|
||||
* gain access to an increased rate-limit, it is highly
|
||||
* recommended to [sign up here](link-pocket-signup).
|
||||
*/
|
||||
export class PocketProvider extends JsonRpcProvider implements CommunityResourcable {
|
||||
|
||||
/**
|
||||
* The Application ID for the Pocket connection.
|
||||
*/
|
||||
readonly applicationId!: string;
|
||||
|
||||
/**
|
||||
* The Application Secret for making authenticated requests
|
||||
* to the Pocket connection.
|
||||
*/
|
||||
readonly applicationSecret!: null | string;
|
||||
|
||||
/**
|
||||
* Create a new **PocketProvider**.
|
||||
*
|
||||
* By default connecting to ``mainnet`` with a highly throttled
|
||||
* API key.
|
||||
*/
|
||||
constructor(_network?: Networkish, applicationId?: null | string, applicationSecret?: null | string) {
|
||||
if (_network == null) { _network = "mainnet"; }
|
||||
const network = Network.from(_network);
|
||||
if (applicationId == null) { applicationId = defaultApplicationId; }
|
||||
if (applicationSecret == null) { applicationSecret = null; }
|
||||
|
||||
const options = { staticNetwork: network };
|
||||
|
||||
const request = PocketProvider.getRequest(network, applicationId, applicationSecret);
|
||||
super(request, network, options);
|
||||
|
||||
defineProperties<PocketProvider>(this, { applicationId, applicationSecret });
|
||||
}
|
||||
|
||||
_getProvider(chainId: number): AbstractProvider {
|
||||
try {
|
||||
return new PocketProvider(chainId, this.applicationId, this.applicationSecret);
|
||||
} catch (error) { }
|
||||
return super._getProvider(chainId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a prepared request for connecting to %%network%% with
|
||||
* %%applicationId%%.
|
||||
*/
|
||||
static getRequest(network: Network, applicationId?: null | string, applicationSecret?: null | string): FetchRequest {
|
||||
if (applicationId == null) { applicationId = defaultApplicationId; }
|
||||
|
||||
const request = new FetchRequest(`https:/\/${ getHost(network.name) }/v1/lb/${ applicationId }`);
|
||||
request.allowGzip = true;
|
||||
|
||||
if (applicationSecret) {
|
||||
request.setCredentials("", applicationSecret);
|
||||
}
|
||||
|
||||
if (applicationId === defaultApplicationId) {
|
||||
request.retryFunc = async (request, response, attempt) => {
|
||||
showThrottleMessage("PocketProvider");
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
isCommunityResource(): boolean {
|
||||
return (this.applicationId === defaultApplicationId);
|
||||
}
|
||||
}
|
||||
177
dev/env/node_modules/ethers/src.ts/providers/provider-quicknode.ts
generated
vendored
Executable file
177
dev/env/node_modules/ethers/src.ts/providers/provider-quicknode.ts
generated
vendored
Executable file
@@ -0,0 +1,177 @@
|
||||
/**
|
||||
* [[link-quicknode]] provides a third-party service for connecting to
|
||||
* various blockchains over JSON-RPC.
|
||||
*
|
||||
* **Supported Networks**
|
||||
*
|
||||
* - Ethereum Mainnet (``mainnet``)
|
||||
* - Goerli Testnet (``goerli``)
|
||||
* - Sepolia Testnet (``sepolia``)
|
||||
* - Holesky Testnet (``holesky``)
|
||||
* - Arbitrum (``arbitrum``)
|
||||
* - Arbitrum Goerli Testnet (``arbitrum-goerli``)
|
||||
* - Arbitrum Sepolia Testnet (``arbitrum-sepolia``)
|
||||
* - Base Mainnet (``base``);
|
||||
* - Base Goerli Testnet (``base-goerli``);
|
||||
* - Base Sepolia Testnet (``base-sepolia``);
|
||||
* - BNB Smart Chain Mainnet (``bnb``)
|
||||
* - BNB Smart Chain Testnet (``bnbt``)
|
||||
* - Optimism (``optimism``)
|
||||
* - Optimism Goerli Testnet (``optimism-goerli``)
|
||||
* - Optimism Sepolia Testnet (``optimism-sepolia``)
|
||||
* - Polygon (``matic``)
|
||||
* - Polygon Mumbai Testnet (``matic-mumbai``)
|
||||
*
|
||||
* @_subsection: api/providers/thirdparty:QuickNode [providers-quicknode]
|
||||
*/
|
||||
|
||||
import {
|
||||
defineProperties, FetchRequest, assertArgument
|
||||
} from "../utils/index.js";
|
||||
|
||||
import { showThrottleMessage } from "./community.js";
|
||||
import { Network } from "./network.js";
|
||||
import { JsonRpcProvider } from "./provider-jsonrpc.js";
|
||||
|
||||
import type { AbstractProvider } from "./abstract-provider.js";
|
||||
import type { CommunityResourcable } from "./community.js";
|
||||
import type { Networkish } from "./network.js";
|
||||
|
||||
|
||||
const defaultToken = "919b412a057b5e9c9b6dce193c5a60242d6efadb";
|
||||
|
||||
function getHost(name: string): string {
|
||||
switch(name) {
|
||||
case "mainnet":
|
||||
return "ethers.quiknode.pro";
|
||||
case "goerli":
|
||||
return "ethers.ethereum-goerli.quiknode.pro";
|
||||
case "sepolia":
|
||||
return "ethers.ethereum-sepolia.quiknode.pro";
|
||||
case "holesky":
|
||||
return "ethers.ethereum-holesky.quiknode.pro";
|
||||
|
||||
case "arbitrum":
|
||||
return "ethers.arbitrum-mainnet.quiknode.pro";
|
||||
case "arbitrum-goerli":
|
||||
return "ethers.arbitrum-goerli.quiknode.pro";
|
||||
case "arbitrum-sepolia":
|
||||
return "ethers.arbitrum-sepolia.quiknode.pro";
|
||||
case "base":
|
||||
return "ethers.base-mainnet.quiknode.pro";
|
||||
case "base-goerli":
|
||||
return "ethers.base-goerli.quiknode.pro";
|
||||
case "base-spolia":
|
||||
return "ethers.base-sepolia.quiknode.pro";
|
||||
case "bnb":
|
||||
return "ethers.bsc.quiknode.pro";
|
||||
case "bnbt":
|
||||
return "ethers.bsc-testnet.quiknode.pro";
|
||||
case "matic":
|
||||
return "ethers.matic.quiknode.pro";
|
||||
case "matic-mumbai":
|
||||
return "ethers.matic-testnet.quiknode.pro";
|
||||
case "optimism":
|
||||
return "ethers.optimism.quiknode.pro";
|
||||
case "optimism-goerli":
|
||||
return "ethers.optimism-goerli.quiknode.pro";
|
||||
case "optimism-sepolia":
|
||||
return "ethers.optimism-sepolia.quiknode.pro";
|
||||
case "xdai":
|
||||
return "ethers.xdai.quiknode.pro";
|
||||
}
|
||||
|
||||
assertArgument(false, "unsupported network", "network", name);
|
||||
}
|
||||
|
||||
/*
|
||||
@TODO:
|
||||
These networks are not currently present in the Network
|
||||
default included networks. Research them and ensure they
|
||||
are EVM compatible and work with ethers
|
||||
|
||||
http://ethers.matic-amoy.quiknode.pro
|
||||
|
||||
http://ethers.avalanche-mainnet.quiknode.pro
|
||||
http://ethers.avalanche-testnet.quiknode.pro
|
||||
http://ethers.blast-sepolia.quiknode.pro
|
||||
http://ethers.celo-mainnet.quiknode.pro
|
||||
http://ethers.fantom.quiknode.pro
|
||||
http://ethers.imx-demo.quiknode.pro
|
||||
http://ethers.imx-mainnet.quiknode.pro
|
||||
http://ethers.imx-testnet.quiknode.pro
|
||||
http://ethers.near-mainnet.quiknode.pro
|
||||
http://ethers.near-testnet.quiknode.pro
|
||||
http://ethers.nova-mainnet.quiknode.pro
|
||||
http://ethers.scroll-mainnet.quiknode.pro
|
||||
http://ethers.scroll-testnet.quiknode.pro
|
||||
http://ethers.tron-mainnet.quiknode.pro
|
||||
http://ethers.zkevm-mainnet.quiknode.pro
|
||||
http://ethers.zkevm-testnet.quiknode.pro
|
||||
http://ethers.zksync-mainnet.quiknode.pro
|
||||
http://ethers.zksync-testnet.quiknode.pro
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The **QuickNodeProvider** connects to the [[link-quicknode]]
|
||||
* JSON-RPC end-points.
|
||||
*
|
||||
* By default, a highly-throttled API token is used, which is
|
||||
* appropriate for quick prototypes and simple scripts. To
|
||||
* gain access to an increased rate-limit, it is highly
|
||||
* recommended to [sign up here](link-quicknode).
|
||||
*/
|
||||
export class QuickNodeProvider extends JsonRpcProvider implements CommunityResourcable {
|
||||
/**
|
||||
* The API token.
|
||||
*/
|
||||
readonly token!: string;
|
||||
|
||||
/**
|
||||
* Creates a new **QuickNodeProvider**.
|
||||
*/
|
||||
constructor(_network?: Networkish, token?: null | string) {
|
||||
if (_network == null) { _network = "mainnet"; }
|
||||
const network = Network.from(_network);
|
||||
if (token == null) { token = defaultToken; }
|
||||
|
||||
const request = QuickNodeProvider.getRequest(network, token);
|
||||
super(request, network, { staticNetwork: network });
|
||||
|
||||
defineProperties<QuickNodeProvider>(this, { token });
|
||||
}
|
||||
|
||||
_getProvider(chainId: number): AbstractProvider {
|
||||
try {
|
||||
return new QuickNodeProvider(chainId, this.token);
|
||||
} catch (error) { }
|
||||
return super._getProvider(chainId);
|
||||
}
|
||||
|
||||
isCommunityResource(): boolean {
|
||||
return (this.token === defaultToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new request prepared for %%network%% and the
|
||||
* %%token%%.
|
||||
*/
|
||||
static getRequest(network: Network, token?: null | string): FetchRequest {
|
||||
if (token == null) { token = defaultToken; }
|
||||
|
||||
const request = new FetchRequest(`https:/\/${ getHost(network.name) }/${ token }`);
|
||||
request.allowGzip = true;
|
||||
//if (projectSecret) { request.setCredentials("", projectSecret); }
|
||||
|
||||
if (token === defaultToken) {
|
||||
request.retryFunc = async (request, response, attempt) => {
|
||||
showThrottleMessage("QuickNodeProvider");
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
}
|
||||
352
dev/env/node_modules/ethers/src.ts/providers/provider-socket.ts
generated
vendored
Executable file
352
dev/env/node_modules/ethers/src.ts/providers/provider-socket.ts
generated
vendored
Executable file
@@ -0,0 +1,352 @@
|
||||
/**
|
||||
* Generic long-lived socket provider.
|
||||
*
|
||||
* Sub-classing notes
|
||||
* - a sub-class MUST call the `_start()` method once connected
|
||||
* - a sub-class MUST override the `_write(string)` method
|
||||
* - a sub-class MUST call `_processMessage(string)` for each message
|
||||
*
|
||||
* @_subsection: api/providers/abstract-provider:Socket Providers [about-socketProvider]
|
||||
*/
|
||||
|
||||
import { UnmanagedSubscriber } from "./abstract-provider.js";
|
||||
import { assert, assertArgument, makeError } from "../utils/index.js";
|
||||
import { JsonRpcApiProvider } from "./provider-jsonrpc.js";
|
||||
|
||||
import type { Subscriber, Subscription } from "./abstract-provider.js";
|
||||
import type { EventFilter } from "./provider.js";
|
||||
import type {
|
||||
JsonRpcApiProviderOptions, JsonRpcError, JsonRpcPayload, JsonRpcResult
|
||||
} from "./provider-jsonrpc.js";
|
||||
import type { Networkish } from "./network.js";
|
||||
|
||||
|
||||
type JsonRpcSubscription = {
|
||||
method: string,
|
||||
params: {
|
||||
result: any,
|
||||
subscription: string
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A **SocketSubscriber** uses a socket transport to handle events and
|
||||
* should use [[_emit]] to manage the events.
|
||||
*/
|
||||
export class SocketSubscriber implements Subscriber {
|
||||
#provider: SocketProvider;
|
||||
|
||||
#filter: string;
|
||||
|
||||
/**
|
||||
* The filter.
|
||||
*/
|
||||
get filter(): Array<any> { return JSON.parse(this.#filter); }
|
||||
|
||||
#filterId: null | Promise<string |number>;
|
||||
#paused: null | boolean;
|
||||
|
||||
#emitPromise: null | Promise<void>;
|
||||
|
||||
/**
|
||||
* Creates a new **SocketSubscriber** attached to %%provider%% listening
|
||||
* to %%filter%%.
|
||||
*/
|
||||
constructor(provider: SocketProvider, filter: Array<any>) {
|
||||
this.#provider = provider;
|
||||
this.#filter = JSON.stringify(filter);
|
||||
this.#filterId = null;
|
||||
this.#paused = null;
|
||||
this.#emitPromise = null;
|
||||
}
|
||||
|
||||
start(): void {
|
||||
this.#filterId = this.#provider.send("eth_subscribe", this.filter).then((filterId) => {;
|
||||
this.#provider._register(filterId, this);
|
||||
return filterId;
|
||||
});
|
||||
}
|
||||
|
||||
stop(): void {
|
||||
(<Promise<number>>(this.#filterId)).then((filterId) => {
|
||||
if (this.#provider.destroyed) { return; }
|
||||
this.#provider.send("eth_unsubscribe", [ filterId ]);
|
||||
});
|
||||
this.#filterId = null;
|
||||
}
|
||||
|
||||
// @TODO: pause should trap the current blockNumber, unsub, and on resume use getLogs
|
||||
// and resume
|
||||
pause(dropWhilePaused?: boolean): void {
|
||||
assert(dropWhilePaused, "preserve logs while paused not supported by SocketSubscriber yet",
|
||||
"UNSUPPORTED_OPERATION", { operation: "pause(false)" });
|
||||
this.#paused = !!dropWhilePaused;
|
||||
}
|
||||
|
||||
resume(): void {
|
||||
this.#paused = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
_handleMessage(message: any): void {
|
||||
if (this.#filterId == null) { return; }
|
||||
if (this.#paused === null) {
|
||||
let emitPromise: null | Promise<void> = this.#emitPromise;
|
||||
if (emitPromise == null) {
|
||||
emitPromise = this._emit(this.#provider, message);
|
||||
} else {
|
||||
emitPromise = emitPromise.then(async () => {
|
||||
await this._emit(this.#provider, message);
|
||||
});
|
||||
}
|
||||
this.#emitPromise = emitPromise.then(() => {
|
||||
if (this.#emitPromise === emitPromise) {
|
||||
this.#emitPromise = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sub-classes **must** override this to emit the events on the
|
||||
* provider.
|
||||
*/
|
||||
async _emit(provider: SocketProvider, message: any): Promise<void> {
|
||||
throw new Error("sub-classes must implemente this; _emit");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A **SocketBlockSubscriber** listens for ``newHeads`` events and emits
|
||||
* ``"block"`` events.
|
||||
*/
|
||||
export class SocketBlockSubscriber extends SocketSubscriber {
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
constructor(provider: SocketProvider) {
|
||||
super(provider, [ "newHeads" ]);
|
||||
}
|
||||
|
||||
async _emit(provider: SocketProvider, message: any): Promise<void> {
|
||||
provider.emit("block", parseInt(message.number));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A **SocketPendingSubscriber** listens for pending transacitons and emits
|
||||
* ``"pending"`` events.
|
||||
*/
|
||||
export class SocketPendingSubscriber extends SocketSubscriber {
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
constructor(provider: SocketProvider) {
|
||||
super(provider, [ "newPendingTransactions" ]);
|
||||
}
|
||||
|
||||
async _emit(provider: SocketProvider, message: any): Promise<void> {
|
||||
provider.emit("pending", message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A **SocketEventSubscriber** listens for event logs.
|
||||
*/
|
||||
export class SocketEventSubscriber extends SocketSubscriber {
|
||||
#logFilter: string;
|
||||
|
||||
/**
|
||||
* The filter.
|
||||
*/
|
||||
get logFilter(): EventFilter { return JSON.parse(this.#logFilter); }
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*/
|
||||
constructor(provider: SocketProvider, filter: EventFilter) {
|
||||
super(provider, [ "logs", filter ]);
|
||||
this.#logFilter = JSON.stringify(filter);
|
||||
}
|
||||
|
||||
async _emit(provider: SocketProvider, message: any): Promise<void> {
|
||||
provider.emit(this.logFilter, provider._wrapLog(message, provider._network));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A **SocketProvider** is backed by a long-lived connection over a
|
||||
* socket, which can subscribe and receive real-time messages over
|
||||
* its communication channel.
|
||||
*/
|
||||
export class SocketProvider extends JsonRpcApiProvider {
|
||||
#callbacks: Map<number, { payload: JsonRpcPayload, resolve: (r: any) => void, reject: (e: Error) => void }>;
|
||||
|
||||
// Maps each filterId to its subscriber
|
||||
#subs: Map<number | string, SocketSubscriber>;
|
||||
|
||||
// If any events come in before a subscriber has finished
|
||||
// registering, queue them
|
||||
#pending: Map<number | string, Array<any>>;
|
||||
|
||||
/**
|
||||
* Creates a new **SocketProvider** connected to %%network%%.
|
||||
*
|
||||
* If unspecified, the network will be discovered.
|
||||
*/
|
||||
constructor(network?: Networkish, _options?: JsonRpcApiProviderOptions) {
|
||||
// Copy the options
|
||||
const options = Object.assign({ }, (_options != null) ? _options: { });
|
||||
|
||||
// Support for batches is generally not supported for
|
||||
// connection-base providers; if this changes in the future
|
||||
// the _send should be updated to reflect this
|
||||
assertArgument(options.batchMaxCount == null || options.batchMaxCount === 1,
|
||||
"sockets-based providers do not support batches", "options.batchMaxCount", _options);
|
||||
options.batchMaxCount = 1;
|
||||
|
||||
// Socket-based Providers (generally) cannot change their network,
|
||||
// since they have a long-lived connection; but let people override
|
||||
// this if they have just cause.
|
||||
if (options.staticNetwork == null) { options.staticNetwork = true; }
|
||||
|
||||
super(network, options);
|
||||
this.#callbacks = new Map();
|
||||
this.#subs = new Map();
|
||||
this.#pending = new Map();
|
||||
}
|
||||
|
||||
// This value is only valid after _start has been called
|
||||
/*
|
||||
get _network(): Network {
|
||||
if (this.#network == null) {
|
||||
throw new Error("this shouldn't happen");
|
||||
}
|
||||
return this.#network.clone();
|
||||
}
|
||||
*/
|
||||
|
||||
_getSubscriber(sub: Subscription): Subscriber {
|
||||
switch (sub.type) {
|
||||
case "close":
|
||||
return new UnmanagedSubscriber("close");
|
||||
case "block":
|
||||
return new SocketBlockSubscriber(this);
|
||||
case "pending":
|
||||
return new SocketPendingSubscriber(this);
|
||||
case "event":
|
||||
return new SocketEventSubscriber(this, sub.filter);
|
||||
case "orphan":
|
||||
// Handled auto-matically within AbstractProvider
|
||||
// when the log.removed = true
|
||||
if (sub.filter.orphan === "drop-log") {
|
||||
return new UnmanagedSubscriber("drop-log");
|
||||
}
|
||||
}
|
||||
return super._getSubscriber(sub);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new subscriber. This is used internalled by Subscribers
|
||||
* and generally is unecessary unless extending capabilities.
|
||||
*/
|
||||
_register(filterId: number | string, subscriber: SocketSubscriber): void {
|
||||
this.#subs.set(filterId, subscriber);
|
||||
const pending = this.#pending.get(filterId);
|
||||
if (pending) {
|
||||
for (const message of pending) {
|
||||
subscriber._handleMessage(message);
|
||||
}
|
||||
this.#pending.delete(filterId);
|
||||
}
|
||||
}
|
||||
|
||||
async _send(payload: JsonRpcPayload | Array<JsonRpcPayload>): Promise<Array<JsonRpcResult | JsonRpcError>> {
|
||||
// WebSocket provider doesn't accept batches
|
||||
assertArgument(!Array.isArray(payload), "WebSocket does not support batch send", "payload", payload);
|
||||
|
||||
// @TODO: stringify payloads here and store to prevent mutations
|
||||
|
||||
// Prepare a promise to respond to
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
this.#callbacks.set(payload.id, { payload, resolve, reject });
|
||||
});
|
||||
|
||||
// Wait until the socket is connected before writing to it
|
||||
await this._waitUntilReady();
|
||||
|
||||
// Write the request to the socket
|
||||
await this._write(JSON.stringify(payload));
|
||||
|
||||
return <Array<JsonRpcResult | JsonRpcError>>[ await promise ];
|
||||
}
|
||||
|
||||
// Sub-classes must call this once they are connected
|
||||
/*
|
||||
async _start(): Promise<void> {
|
||||
if (this.#ready) { return; }
|
||||
|
||||
for (const { payload } of this.#callbacks.values()) {
|
||||
await this._write(JSON.stringify(payload));
|
||||
}
|
||||
|
||||
this.#ready = (async function() {
|
||||
await super._start();
|
||||
})();
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sub-classes **must** call this with messages received over their
|
||||
* transport to be processed and dispatched.
|
||||
*/
|
||||
async _processMessage(message: string): Promise<void> {
|
||||
const result = <JsonRpcResult | JsonRpcError | JsonRpcSubscription>(JSON.parse(message));
|
||||
|
||||
if (result && typeof(result) === "object" && "id" in result) {
|
||||
const callback = this.#callbacks.get(result.id);
|
||||
if (callback == null) {
|
||||
this.emit("error", makeError("received result for unknown id", "UNKNOWN_ERROR", {
|
||||
reasonCode: "UNKNOWN_ID",
|
||||
result
|
||||
}));
|
||||
return;
|
||||
}
|
||||
this.#callbacks.delete(result.id);
|
||||
|
||||
callback.resolve(result);
|
||||
|
||||
} else if (result && result.method === "eth_subscription") {
|
||||
const filterId = result.params.subscription;
|
||||
const subscriber = this.#subs.get(filterId);
|
||||
if (subscriber) {
|
||||
subscriber._handleMessage(result.params.result);
|
||||
} else {
|
||||
let pending = this.#pending.get(filterId);
|
||||
if (pending == null) {
|
||||
pending = [ ];
|
||||
this.#pending.set(filterId, pending);
|
||||
}
|
||||
pending.push(result.params.result);
|
||||
}
|
||||
|
||||
} else {
|
||||
this.emit("error", makeError("received unexpected message", "UNKNOWN_ERROR", {
|
||||
reasonCode: "UNEXPECTED_MESSAGE",
|
||||
result
|
||||
}));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sub-classes **must** override this to send %%message%% over their
|
||||
* transport.
|
||||
*/
|
||||
async _write(message: string): Promise<void> {
|
||||
throw new Error("sub-classes must override this");
|
||||
}
|
||||
}
|
||||
103
dev/env/node_modules/ethers/src.ts/providers/provider-websocket.ts
generated
vendored
Executable file
103
dev/env/node_modules/ethers/src.ts/providers/provider-websocket.ts
generated
vendored
Executable file
@@ -0,0 +1,103 @@
|
||||
|
||||
|
||||
import { WebSocket as _WebSocket } from "./ws.js"; /*-browser*/
|
||||
|
||||
import { SocketProvider } from "./provider-socket.js";
|
||||
|
||||
import type { JsonRpcApiProviderOptions} from "./provider-jsonrpc.js";
|
||||
import type { Networkish } from "./network.js";
|
||||
|
||||
/**
|
||||
* A generic interface to a Websocket-like object.
|
||||
*/
|
||||
export interface WebSocketLike {
|
||||
onopen: null | ((...args: Array<any>) => any);
|
||||
onmessage: null | ((...args: Array<any>) => any);
|
||||
onerror: null | ((...args: Array<any>) => any);
|
||||
|
||||
readyState: number;
|
||||
|
||||
send(payload: any): void;
|
||||
close(code?: number, reason?: string): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* A function which can be used to re-create a WebSocket connection
|
||||
* on disconnect.
|
||||
*/
|
||||
export type WebSocketCreator = () => WebSocketLike;
|
||||
|
||||
/**
|
||||
* A JSON-RPC provider which is backed by a WebSocket.
|
||||
*
|
||||
* WebSockets are often preferred because they retain a live connection
|
||||
* to a server, which permits more instant access to events.
|
||||
*
|
||||
* However, this incurs higher server infrasturture costs, so additional
|
||||
* resources may be required to host your own WebSocket nodes and many
|
||||
* third-party services charge additional fees for WebSocket endpoints.
|
||||
*/
|
||||
export class WebSocketProvider extends SocketProvider {
|
||||
#connect: null | WebSocketCreator;
|
||||
|
||||
#websocket: null | WebSocketLike;
|
||||
get websocket(): WebSocketLike {
|
||||
if (this.#websocket == null) { throw new Error("websocket closed"); }
|
||||
return this.#websocket;
|
||||
}
|
||||
|
||||
constructor(url: string | WebSocketLike | WebSocketCreator, network?: Networkish, options?: JsonRpcApiProviderOptions) {
|
||||
super(network, options);
|
||||
if (typeof(url) === "string") {
|
||||
this.#connect = () => { return new _WebSocket(url); };
|
||||
this.#websocket = this.#connect();
|
||||
} else if (typeof(url) === "function") {
|
||||
this.#connect = url;
|
||||
this.#websocket = url();
|
||||
} else {
|
||||
this.#connect = null;
|
||||
this.#websocket = url;
|
||||
}
|
||||
|
||||
this.websocket.onopen = async () => {
|
||||
try {
|
||||
await this._start()
|
||||
this.resume();
|
||||
} catch (error) {
|
||||
console.log("failed to start WebsocketProvider", error);
|
||||
// @TODO: now what? Attempt reconnect?
|
||||
}
|
||||
};
|
||||
|
||||
this.websocket.onmessage = (message: { data: string }) => {
|
||||
this._processMessage(message.data);
|
||||
};
|
||||
/*
|
||||
this.websocket.onclose = (event) => {
|
||||
// @TODO: What event.code should we reconnect on?
|
||||
const reconnect = false;
|
||||
if (reconnect) {
|
||||
this.pause(true);
|
||||
if (this.#connect) {
|
||||
this.#websocket = this.#connect();
|
||||
this.#websocket.onopen = ...
|
||||
// @TODO: this requires the super class to rebroadcast; move it there
|
||||
}
|
||||
this._reconnect();
|
||||
}
|
||||
};
|
||||
*/
|
||||
}
|
||||
|
||||
async _write(message: string): Promise<void> {
|
||||
this.websocket.send(message);
|
||||
}
|
||||
|
||||
async destroy(): Promise<void> {
|
||||
if (this.#websocket != null) {
|
||||
this.#websocket.close();
|
||||
this.#websocket = null;
|
||||
}
|
||||
super.destroy();
|
||||
}
|
||||
}
|
||||
2146
dev/env/node_modules/ethers/src.ts/providers/provider.ts
generated
vendored
Executable file
2146
dev/env/node_modules/ethers/src.ts/providers/provider.ts
generated
vendored
Executable file
File diff suppressed because it is too large
Load Diff
98
dev/env/node_modules/ethers/src.ts/providers/signer-noncemanager.ts
generated
vendored
Executable file
98
dev/env/node_modules/ethers/src.ts/providers/signer-noncemanager.ts
generated
vendored
Executable file
@@ -0,0 +1,98 @@
|
||||
import { defineProperties } from "../utils/index.js";
|
||||
import { AbstractSigner } from "./abstract-signer.js";
|
||||
|
||||
import type { TypedDataDomain, TypedDataField } from "../hash/index.js";
|
||||
|
||||
import type {
|
||||
BlockTag, Provider, TransactionRequest, TransactionResponse
|
||||
} from "./provider.js";
|
||||
import type { Signer } from "./signer.js";
|
||||
|
||||
|
||||
/**
|
||||
* A **NonceManager** wraps another [[Signer]] and automatically manages
|
||||
* the nonce, ensuring serialized and sequential nonces are used during
|
||||
* transaction.
|
||||
*/
|
||||
export class NonceManager extends AbstractSigner {
|
||||
/**
|
||||
* The Signer being managed.
|
||||
*/
|
||||
signer!: Signer;
|
||||
|
||||
#noncePromise: null | Promise<number>;
|
||||
#delta: number;
|
||||
|
||||
/**
|
||||
* Creates a new **NonceManager** to manage %%signer%%.
|
||||
*/
|
||||
constructor(signer: Signer) {
|
||||
super(signer.provider);
|
||||
defineProperties<NonceManager>(this, { signer });
|
||||
|
||||
this.#noncePromise = null;
|
||||
this.#delta = 0;
|
||||
}
|
||||
|
||||
async getAddress(): Promise<string> {
|
||||
return this.signer.getAddress();
|
||||
}
|
||||
|
||||
connect(provider: null | Provider): NonceManager {
|
||||
return new NonceManager(this.signer.connect(provider));
|
||||
}
|
||||
|
||||
async getNonce(blockTag?: BlockTag): Promise<number> {
|
||||
if (blockTag === "pending") {
|
||||
if (this.#noncePromise == null) {
|
||||
this.#noncePromise = super.getNonce("pending");
|
||||
}
|
||||
|
||||
const delta = this.#delta;
|
||||
return (await this.#noncePromise) + delta;
|
||||
}
|
||||
|
||||
return super.getNonce(blockTag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually increment the nonce. This may be useful when managng
|
||||
* offline transactions.
|
||||
*/
|
||||
increment(): void {
|
||||
this.#delta++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the nonce, causing the **NonceManager** to reload the current
|
||||
* nonce from the blockchain on the next transaction.
|
||||
*/
|
||||
reset(): void {
|
||||
this.#delta = 0;
|
||||
this.#noncePromise = null;
|
||||
}
|
||||
|
||||
async sendTransaction(tx: TransactionRequest): Promise<TransactionResponse> {
|
||||
const noncePromise = this.getNonce("pending");
|
||||
this.increment();
|
||||
|
||||
tx = await this.signer.populateTransaction(tx);
|
||||
tx.nonce = await noncePromise;
|
||||
|
||||
// @TODO: Maybe handle interesting/recoverable errors?
|
||||
// Like don't increment if the tx was certainly not sent
|
||||
return await this.signer.sendTransaction(tx);
|
||||
}
|
||||
|
||||
signTransaction(tx: TransactionRequest): Promise<string> {
|
||||
return this.signer.signTransaction(tx);
|
||||
}
|
||||
|
||||
signMessage(message: string | Uint8Array): Promise<string> {
|
||||
return this.signer.signMessage(message);
|
||||
}
|
||||
|
||||
signTypedData(domain: TypedDataDomain, types: Record<string, Array<TypedDataField>>, value: Record<string, any>): Promise<string> {
|
||||
return this.signer.signTypedData(domain, types, value);
|
||||
}
|
||||
}
|
||||
166
dev/env/node_modules/ethers/src.ts/providers/signer.ts
generated
vendored
Executable file
166
dev/env/node_modules/ethers/src.ts/providers/signer.ts
generated
vendored
Executable file
@@ -0,0 +1,166 @@
|
||||
|
||||
import type { Addressable, NameResolver } from "../address/index.js";
|
||||
import type {
|
||||
AuthorizationRequest, TypedDataDomain, TypedDataField
|
||||
} from "../hash/index.js";
|
||||
import type { Authorization, TransactionLike } from "../transaction/index.js";
|
||||
|
||||
import type { ContractRunner } from "./contracts.js";
|
||||
import type { BlockTag, Provider, TransactionRequest, TransactionResponse } from "./provider.js";
|
||||
|
||||
/**
|
||||
* A Signer represents an account on the Ethereum Blockchain, and is most often
|
||||
* backed by a private key represented by a mnemonic or residing on a Hardware Wallet.
|
||||
*
|
||||
* The API remains abstract though, so that it can deal with more advanced exotic
|
||||
* Signing entities, such as Smart Contract Wallets or Virtual Wallets (where the
|
||||
* private key may not be known).
|
||||
*/
|
||||
export interface Signer extends Addressable, ContractRunner, NameResolver {
|
||||
|
||||
/**
|
||||
* The [[Provider]] attached to this Signer (if any).
|
||||
*/
|
||||
provider: null | Provider;
|
||||
|
||||
/**
|
||||
* Returns a new instance of this Signer connected to //provider// or detached
|
||||
* from any Provider if null.
|
||||
*/
|
||||
connect(provider: null | Provider): Signer;
|
||||
|
||||
|
||||
////////////////////
|
||||
// State
|
||||
|
||||
/**
|
||||
* Get the address of the Signer.
|
||||
*/
|
||||
getAddress(): Promise<string>;
|
||||
|
||||
/**
|
||||
* Gets the next nonce required for this Signer to send a transaction.
|
||||
*
|
||||
* @param blockTag - The blocktag to base the transaction count on, keep in mind
|
||||
* many nodes do not honour this value and silently ignore it [default: ``"latest"``]
|
||||
*/
|
||||
getNonce(blockTag?: BlockTag): Promise<number>;
|
||||
|
||||
|
||||
////////////////////
|
||||
// Preparation
|
||||
|
||||
/**
|
||||
* Prepares a {@link TransactionRequest} for calling:
|
||||
* - resolves ``to`` and ``from`` addresses
|
||||
* - if ``from`` is specified , check that it matches this Signer
|
||||
*
|
||||
* @param tx - The call to prepare
|
||||
*/
|
||||
populateCall(tx: TransactionRequest): Promise<TransactionLike<string>>;
|
||||
|
||||
/**
|
||||
* Prepares a {@link TransactionRequest} for sending to the network by
|
||||
* populating any missing properties:
|
||||
* - resolves ``to`` and ``from`` addresses
|
||||
* - if ``from`` is specified , check that it matches this Signer
|
||||
* - populates ``nonce`` via ``signer.getNonce("pending")``
|
||||
* - populates ``gasLimit`` via ``signer.estimateGas(tx)``
|
||||
* - populates ``chainId`` via ``signer.provider.getNetwork()``
|
||||
* - populates ``type`` and relevant fee data for that type (``gasPrice``
|
||||
* for legacy transactions, ``maxFeePerGas`` for EIP-1559, etc)
|
||||
*
|
||||
* @note Some Signer implementations may skip populating properties that
|
||||
* are populated downstream; for example JsonRpcSigner defers to the
|
||||
* node to populate the nonce and fee data.
|
||||
*
|
||||
* @param tx - The call to prepare
|
||||
*/
|
||||
populateTransaction(tx: TransactionRequest): Promise<TransactionLike<string>>;
|
||||
|
||||
|
||||
////////////////////
|
||||
// Execution
|
||||
|
||||
/**
|
||||
* Estimates the required gas required to execute //tx// on the Blockchain. This
|
||||
* will be the expected amount a transaction will require as its ``gasLimit``
|
||||
* to successfully run all the necessary computations and store the needed state
|
||||
* that the transaction intends.
|
||||
*
|
||||
* Keep in mind that this is **best efforts**, since the state of the Blockchain
|
||||
* is in flux, which could affect transaction gas requirements.
|
||||
*
|
||||
* @throws UNPREDICTABLE_GAS_LIMIT A transaction that is believed by the node to likely
|
||||
* fail will throw an error during gas estimation. This could indicate that it
|
||||
* will actually fail or that the circumstances are simply too complex for the
|
||||
* node to take into account. In these cases, a manually determined ``gasLimit``
|
||||
* will need to be made.
|
||||
*/
|
||||
estimateGas(tx: TransactionRequest): Promise<bigint>;
|
||||
|
||||
/**
|
||||
* Evaluates the //tx// by running it against the current Blockchain state. This
|
||||
* cannot change state and has no cost in ether, as it is effectively simulating
|
||||
* execution.
|
||||
*
|
||||
* This can be used to have the Blockchain perform computations based on its state
|
||||
* (e.g. running a Contract's getters) or to simulate the effect of a transaction
|
||||
* before actually performing an operation.
|
||||
*/
|
||||
call(tx: TransactionRequest): Promise<string>;
|
||||
|
||||
/**
|
||||
* Resolves an ENS Name to an address.
|
||||
*/
|
||||
resolveName(name: string): Promise<null | string>;
|
||||
|
||||
|
||||
////////////////////
|
||||
// Signing
|
||||
|
||||
/**
|
||||
* Signs %%tx%%, returning the fully signed transaction. This does not
|
||||
* populate any additional properties within the transaction.
|
||||
*/
|
||||
signTransaction(tx: TransactionRequest): Promise<string>;
|
||||
|
||||
/**
|
||||
* Sends %%tx%% to the Network. The ``signer.populateTransaction(tx)``
|
||||
* is called first to ensure all necessary properties for the
|
||||
* transaction to be valid have been popualted first.
|
||||
*/
|
||||
sendTransaction(tx: TransactionRequest): Promise<TransactionResponse>;
|
||||
|
||||
/**
|
||||
* Signs an [[link-eip-191]] prefixed personal message.
|
||||
*
|
||||
* If the %%message%% is a string, it is signed as UTF-8 encoded bytes. It is **not**
|
||||
* interpretted as a [[BytesLike]]; so the string ``"0x1234"`` is signed as six
|
||||
* characters, **not** two bytes.
|
||||
*
|
||||
* To sign that example as two bytes, the Uint8Array should be used
|
||||
* (i.e. ``new Uint8Array([ 0x12, 0x34 ])``).
|
||||
*/
|
||||
signMessage(message: string | Uint8Array): Promise<string>;
|
||||
|
||||
/**
|
||||
* Signs the [[link-eip-712]] typed data.
|
||||
*/
|
||||
signTypedData(domain: TypedDataDomain, types: Record<string, Array<TypedDataField>>, value: Record<string, any>): Promise<string>;
|
||||
|
||||
/**
|
||||
* Prepares an [[AuthorizationRequest]] for authorization by
|
||||
* populating any missing properties:
|
||||
* - resolves ``address`` (if an Addressable or ENS name)
|
||||
* - populates ``nonce`` via ``signer.getNonce("pending")``
|
||||
* - populates ``chainId`` via ``signer.provider.getNetwork()``
|
||||
*/
|
||||
populateAuthorization(auth: AuthorizationRequest): Promise<AuthorizationRequest>;
|
||||
|
||||
/**
|
||||
* Signs an %%authorization%% to be used in [[link-eip-7702]]
|
||||
* transactions.
|
||||
*/
|
||||
authorize(authorization: AuthorizationRequest): Promise<Authorization>;
|
||||
}
|
||||
74
dev/env/node_modules/ethers/src.ts/providers/subscriber-connection.ts
generated
vendored
Executable file
74
dev/env/node_modules/ethers/src.ts/providers/subscriber-connection.ts
generated
vendored
Executable file
@@ -0,0 +1,74 @@
|
||||
|
||||
import { getNumber } from "../utils/index.js";
|
||||
|
||||
import type { Subscriber } from "./abstract-provider.js";
|
||||
|
||||
|
||||
//#TODO: Temp
|
||||
import type { Provider } from "./provider.js";
|
||||
|
||||
/**
|
||||
* @TODO
|
||||
*
|
||||
* @_docloc: api/providers/abstract-provider
|
||||
*/
|
||||
export interface ConnectionRpcProvider extends Provider {
|
||||
//send(method: string, params: Array<any>): Promise<any>;
|
||||
_subscribe(param: Array<any>, processFunc: (result: any) => void): number;
|
||||
_unsubscribe(filterId: number): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* @TODO
|
||||
*
|
||||
* @_docloc: api/providers/abstract-provider
|
||||
*/
|
||||
export class BlockConnectionSubscriber implements Subscriber {
|
||||
#provider: ConnectionRpcProvider;
|
||||
#blockNumber: number;
|
||||
|
||||
#running: boolean;
|
||||
|
||||
#filterId: null | number;
|
||||
|
||||
constructor(provider: ConnectionRpcProvider) {
|
||||
this.#provider = provider;
|
||||
this.#blockNumber = -2;
|
||||
this.#running = false;
|
||||
this.#filterId = null;
|
||||
}
|
||||
|
||||
start(): void {
|
||||
if (this.#running) { return; }
|
||||
this.#running = true;
|
||||
|
||||
this.#filterId = this.#provider._subscribe([ "newHeads" ], (result: any) => {
|
||||
const blockNumber = getNumber(result.number);
|
||||
const initial = (this.#blockNumber === -2) ? blockNumber: (this.#blockNumber + 1)
|
||||
for (let b = initial; b <= blockNumber; b++) {
|
||||
this.#provider.emit("block", b);
|
||||
}
|
||||
this.#blockNumber = blockNumber;
|
||||
});
|
||||
}
|
||||
|
||||
stop(): void {
|
||||
if (!this.#running) { return; }
|
||||
this.#running = false;
|
||||
|
||||
if (this.#filterId != null) {
|
||||
this.#provider._unsubscribe(this.#filterId);
|
||||
this.#filterId = null;
|
||||
}
|
||||
}
|
||||
|
||||
pause(dropWhilePaused?: boolean): void {
|
||||
if (dropWhilePaused) { this.#blockNumber = -2; }
|
||||
this.stop();
|
||||
}
|
||||
|
||||
resume(): void {
|
||||
this.start();
|
||||
}
|
||||
}
|
||||
|
||||
199
dev/env/node_modules/ethers/src.ts/providers/subscriber-filterid.ts
generated
vendored
Executable file
199
dev/env/node_modules/ethers/src.ts/providers/subscriber-filterid.ts
generated
vendored
Executable file
@@ -0,0 +1,199 @@
|
||||
import { isError } from "../utils/index.js";
|
||||
|
||||
import { PollingEventSubscriber } from "./subscriber-polling.js";
|
||||
|
||||
import type { AbstractProvider, Subscriber } from "./abstract-provider.js";
|
||||
import type { Network } from "./network.js";
|
||||
import type { EventFilter } from "./provider.js";
|
||||
import type { JsonRpcApiProvider } from "./provider-jsonrpc.js";
|
||||
|
||||
function copy(obj: any): any {
|
||||
return JSON.parse(JSON.stringify(obj));
|
||||
}
|
||||
|
||||
/**
|
||||
* Some backends support subscribing to events using a Filter ID.
|
||||
*
|
||||
* When subscribing with this technique, the node issues a unique
|
||||
* //Filter ID//. At this point the node dedicates resources to
|
||||
* the filter, so that periodic calls to follow up on the //Filter ID//
|
||||
* will receive any events since the last call.
|
||||
*
|
||||
* @_docloc: api/providers/abstract-provider
|
||||
*/
|
||||
export class FilterIdSubscriber implements Subscriber {
|
||||
#provider: JsonRpcApiProvider;
|
||||
|
||||
#filterIdPromise: null | Promise<string>;
|
||||
#poller: (b: number) => Promise<void>;
|
||||
|
||||
#running: boolean;
|
||||
|
||||
#network: null | Network;
|
||||
|
||||
#hault: boolean;
|
||||
|
||||
/**
|
||||
* Creates a new **FilterIdSubscriber** which will used [[_subscribe]]
|
||||
* and [[_emitResults]] to setup the subscription and provide the event
|
||||
* to the %%provider%%.
|
||||
*/
|
||||
constructor(provider: JsonRpcApiProvider) {
|
||||
this.#provider = provider;
|
||||
|
||||
this.#filterIdPromise = null;
|
||||
this.#poller = this.#poll.bind(this);
|
||||
|
||||
this.#running = false;
|
||||
|
||||
this.#network = null;
|
||||
|
||||
this.#hault = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sub-classes **must** override this to begin the subscription.
|
||||
*/
|
||||
_subscribe(provider: JsonRpcApiProvider): Promise<string> {
|
||||
throw new Error("subclasses must override this");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sub-classes **must** override this handle the events.
|
||||
*/
|
||||
_emitResults(provider: AbstractProvider, result: Array<any>): Promise<void> {
|
||||
throw new Error("subclasses must override this");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sub-classes **must** override this handle recovery on errors.
|
||||
*/
|
||||
_recover(provider: AbstractProvider): Subscriber {
|
||||
throw new Error("subclasses must override this");
|
||||
}
|
||||
|
||||
async #poll(blockNumber: number): Promise<void> {
|
||||
try {
|
||||
// Subscribe if necessary
|
||||
if (this.#filterIdPromise == null) {
|
||||
this.#filterIdPromise = this._subscribe(this.#provider);
|
||||
}
|
||||
|
||||
// Get the Filter ID
|
||||
let filterId: null | string = null;
|
||||
try {
|
||||
filterId = await this.#filterIdPromise;
|
||||
} catch (error) {
|
||||
if (!isError(error, "UNSUPPORTED_OPERATION") || error.operation !== "eth_newFilter") {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// The backend does not support Filter ID; downgrade to
|
||||
// polling
|
||||
if (filterId == null) {
|
||||
this.#filterIdPromise = null;
|
||||
this.#provider._recoverSubscriber(this, this._recover(this.#provider));
|
||||
return;
|
||||
}
|
||||
|
||||
const network = await this.#provider.getNetwork();
|
||||
if (!this.#network) { this.#network = network; }
|
||||
|
||||
if ((this.#network as Network).chainId !== network.chainId) {
|
||||
throw new Error("chaid changed");
|
||||
}
|
||||
|
||||
if (this.#hault) { return; }
|
||||
|
||||
const result = await this.#provider.send("eth_getFilterChanges", [ filterId ]);
|
||||
await this._emitResults(this.#provider, result);
|
||||
} catch (error) { console.log("@TODO", error); }
|
||||
|
||||
this.#provider.once("block", this.#poller);
|
||||
}
|
||||
|
||||
#teardown(): void {
|
||||
const filterIdPromise = this.#filterIdPromise;
|
||||
if (filterIdPromise) {
|
||||
this.#filterIdPromise = null;
|
||||
filterIdPromise.then((filterId) => {
|
||||
if (this.#provider.destroyed) { return; }
|
||||
this.#provider.send("eth_uninstallFilter", [ filterId ]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
start(): void {
|
||||
if (this.#running) { return; }
|
||||
this.#running = true;
|
||||
|
||||
this.#poll(-2);
|
||||
}
|
||||
|
||||
stop(): void {
|
||||
if (!this.#running) { return; }
|
||||
this.#running = false;
|
||||
|
||||
this.#hault = true;
|
||||
this.#teardown();
|
||||
this.#provider.off("block", this.#poller);
|
||||
}
|
||||
|
||||
pause(dropWhilePaused?: boolean): void {
|
||||
if (dropWhilePaused){ this.#teardown(); }
|
||||
this.#provider.off("block", this.#poller);
|
||||
}
|
||||
|
||||
resume(): void { this.start(); }
|
||||
}
|
||||
|
||||
/**
|
||||
* A **FilterIdSubscriber** for receiving contract events.
|
||||
*
|
||||
* @_docloc: api/providers/abstract-provider
|
||||
*/
|
||||
export class FilterIdEventSubscriber extends FilterIdSubscriber {
|
||||
#event: EventFilter;
|
||||
|
||||
/**
|
||||
* Creates a new **FilterIdEventSubscriber** attached to %%provider%%
|
||||
* listening for %%filter%%.
|
||||
*/
|
||||
constructor(provider: JsonRpcApiProvider, filter: EventFilter) {
|
||||
super(provider);
|
||||
this.#event = copy(filter);
|
||||
}
|
||||
|
||||
_recover(provider: AbstractProvider): Subscriber {
|
||||
return new PollingEventSubscriber(provider, this.#event);
|
||||
}
|
||||
|
||||
async _subscribe(provider: JsonRpcApiProvider): Promise<string> {
|
||||
const filterId = await provider.send("eth_newFilter", [ this.#event ]);
|
||||
return filterId;
|
||||
}
|
||||
|
||||
async _emitResults(provider: JsonRpcApiProvider, results: Array<any>): Promise<void> {
|
||||
for (const result of results) {
|
||||
provider.emit(this.#event, provider._wrapLog(result, provider._network));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A **FilterIdSubscriber** for receiving pending transactions events.
|
||||
*
|
||||
* @_docloc: api/providers/abstract-provider
|
||||
*/
|
||||
export class FilterIdPendingSubscriber extends FilterIdSubscriber {
|
||||
async _subscribe(provider: JsonRpcApiProvider): Promise<string> {
|
||||
return await provider.send("eth_newPendingTransactionFilter", [ ]);
|
||||
}
|
||||
|
||||
async _emitResults(provider: JsonRpcApiProvider, results: Array<any>): Promise<void> {
|
||||
for (const result of results) {
|
||||
provider.emit("pending", result);
|
||||
}
|
||||
}
|
||||
}
|
||||
321
dev/env/node_modules/ethers/src.ts/providers/subscriber-polling.ts
generated
vendored
Executable file
321
dev/env/node_modules/ethers/src.ts/providers/subscriber-polling.ts
generated
vendored
Executable file
@@ -0,0 +1,321 @@
|
||||
import { assert, isHexString } from "../utils/index.js";
|
||||
|
||||
import type { AbstractProvider, Subscriber } from "./abstract-provider.js";
|
||||
import type { EventFilter, OrphanFilter, ProviderEvent } from "./provider.js";
|
||||
|
||||
function copy(obj: any): any {
|
||||
return JSON.parse(JSON.stringify(obj));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the polling subscriber for common events.
|
||||
*
|
||||
* @_docloc: api/providers/abstract-provider
|
||||
*/
|
||||
export function getPollingSubscriber(provider: AbstractProvider, event: ProviderEvent): Subscriber {
|
||||
if (event === "block") { return new PollingBlockSubscriber(provider); }
|
||||
if (isHexString(event, 32)) { return new PollingTransactionSubscriber(provider, event); }
|
||||
|
||||
assert(false, "unsupported polling event", "UNSUPPORTED_OPERATION", {
|
||||
operation: "getPollingSubscriber", info: { event }
|
||||
});
|
||||
}
|
||||
|
||||
// @TODO: refactor this
|
||||
|
||||
/**
|
||||
* A **PollingBlockSubscriber** polls at a regular interval for a change
|
||||
* in the block number.
|
||||
*
|
||||
* @_docloc: api/providers/abstract-provider
|
||||
*/
|
||||
export class PollingBlockSubscriber implements Subscriber {
|
||||
#provider: AbstractProvider;
|
||||
#poller: null | number;
|
||||
|
||||
#interval: number;
|
||||
|
||||
// The most recent block we have scanned for events. The value -2
|
||||
// indicates we still need to fetch an initial block number
|
||||
#blockNumber: number;
|
||||
|
||||
/**
|
||||
* Create a new **PollingBlockSubscriber** attached to %%provider%%.
|
||||
*/
|
||||
constructor(provider: AbstractProvider) {
|
||||
this.#provider = provider;
|
||||
this.#poller = null;
|
||||
this.#interval = 4000;
|
||||
|
||||
this.#blockNumber = -2;
|
||||
}
|
||||
|
||||
/**
|
||||
* The polling interval.
|
||||
*/
|
||||
get pollingInterval(): number { return this.#interval; }
|
||||
set pollingInterval(value: number) { this.#interval = value; }
|
||||
|
||||
async #poll(): Promise<void> {
|
||||
try {
|
||||
const blockNumber = await this.#provider.getBlockNumber();
|
||||
|
||||
// Bootstrap poll to setup our initial block number
|
||||
if (this.#blockNumber === -2) {
|
||||
this.#blockNumber = blockNumber;
|
||||
return;
|
||||
}
|
||||
|
||||
// @TODO: Put a cap on the maximum number of events per loop?
|
||||
|
||||
if (blockNumber !== this.#blockNumber) {
|
||||
for (let b = this.#blockNumber + 1; b <= blockNumber; b++) {
|
||||
// We have been stopped
|
||||
if (this.#poller == null) { return; }
|
||||
|
||||
await this.#provider.emit("block", b);
|
||||
}
|
||||
|
||||
this.#blockNumber = blockNumber;
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
// @TODO: Minor bump, add an "error" event to let subscribers
|
||||
// know things went awry.
|
||||
//console.log(error);
|
||||
}
|
||||
|
||||
// We have been stopped
|
||||
if (this.#poller == null) { return; }
|
||||
|
||||
this.#poller = this.#provider._setTimeout(this.#poll.bind(this), this.#interval);
|
||||
}
|
||||
|
||||
start(): void {
|
||||
if (this.#poller) { return; }
|
||||
this.#poller = this.#provider._setTimeout(this.#poll.bind(this), this.#interval);
|
||||
this.#poll();
|
||||
}
|
||||
|
||||
stop(): void {
|
||||
if (!this.#poller) { return; }
|
||||
this.#provider._clearTimeout(this.#poller);
|
||||
this.#poller = null;
|
||||
}
|
||||
|
||||
pause(dropWhilePaused?: boolean): void {
|
||||
this.stop();
|
||||
if (dropWhilePaused) { this.#blockNumber = -2; }
|
||||
}
|
||||
|
||||
resume(): void {
|
||||
this.start();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* An **OnBlockSubscriber** can be sub-classed, with a [[_poll]]
|
||||
* implmentation which will be called on every new block.
|
||||
*
|
||||
* @_docloc: api/providers/abstract-provider
|
||||
*/
|
||||
export class OnBlockSubscriber implements Subscriber {
|
||||
#provider: AbstractProvider;
|
||||
#poll: (b: number) => void;
|
||||
#running: boolean;
|
||||
|
||||
/**
|
||||
* Create a new **OnBlockSubscriber** attached to %%provider%%.
|
||||
*/
|
||||
constructor(provider: AbstractProvider) {
|
||||
this.#provider = provider;
|
||||
this.#running = false;
|
||||
this.#poll = (blockNumber: number) => {
|
||||
this._poll(blockNumber, this.#provider);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on every new block.
|
||||
*/
|
||||
async _poll(blockNumber: number, provider: AbstractProvider): Promise<void> {
|
||||
throw new Error("sub-classes must override this");
|
||||
}
|
||||
|
||||
start(): void {
|
||||
if (this.#running) { return; }
|
||||
this.#running = true;
|
||||
|
||||
this.#poll(-2);
|
||||
this.#provider.on("block", this.#poll);
|
||||
}
|
||||
|
||||
stop(): void {
|
||||
if (!this.#running) { return; }
|
||||
this.#running = false;
|
||||
|
||||
this.#provider.off("block", this.#poll);
|
||||
}
|
||||
|
||||
pause(dropWhilePaused?: boolean): void { this.stop(); }
|
||||
resume(): void { this.start(); }
|
||||
}
|
||||
|
||||
export class PollingBlockTagSubscriber extends OnBlockSubscriber {
|
||||
readonly #tag: string;
|
||||
#lastBlock: number;
|
||||
|
||||
constructor(provider: AbstractProvider, tag: string) {
|
||||
super(provider);
|
||||
this.#tag = tag;
|
||||
this.#lastBlock = -2;
|
||||
}
|
||||
|
||||
pause(dropWhilePaused?: boolean): void {
|
||||
if (dropWhilePaused) { this.#lastBlock = -2; }
|
||||
super.pause(dropWhilePaused);
|
||||
}
|
||||
|
||||
async _poll(blockNumber: number, provider: AbstractProvider): Promise<void> {
|
||||
const block = await provider.getBlock(this.#tag);
|
||||
if (block == null) { return; }
|
||||
|
||||
if (this.#lastBlock === -2) {
|
||||
this.#lastBlock = block.number;
|
||||
} else if (block.number > this.#lastBlock) {
|
||||
provider.emit(this.#tag, block.number);
|
||||
this.#lastBlock = block.number;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @_ignore:
|
||||
*
|
||||
* @_docloc: api/providers/abstract-provider
|
||||
*/
|
||||
export class PollingOrphanSubscriber extends OnBlockSubscriber {
|
||||
#filter: OrphanFilter;
|
||||
|
||||
constructor(provider: AbstractProvider, filter: OrphanFilter) {
|
||||
super(provider);
|
||||
this.#filter = copy(filter);
|
||||
}
|
||||
|
||||
async _poll(blockNumber: number, provider: AbstractProvider): Promise<void> {
|
||||
throw new Error("@TODO");
|
||||
console.log(this.#filter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A **PollingTransactionSubscriber** will poll for a given transaction
|
||||
* hash for its receipt.
|
||||
*
|
||||
* @_docloc: api/providers/abstract-provider
|
||||
*/
|
||||
export class PollingTransactionSubscriber extends OnBlockSubscriber {
|
||||
#hash: string;
|
||||
|
||||
/**
|
||||
* Create a new **PollingTransactionSubscriber** attached to
|
||||
* %%provider%%, listening for %%hash%%.
|
||||
*/
|
||||
constructor(provider: AbstractProvider, hash: string) {
|
||||
super(provider);
|
||||
this.#hash = hash;
|
||||
}
|
||||
|
||||
async _poll(blockNumber: number, provider: AbstractProvider): Promise<void> {
|
||||
const tx = await provider.getTransactionReceipt(this.#hash);
|
||||
if (tx) { provider.emit(this.#hash, tx); }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A **PollingEventSubscriber** will poll for a given filter for its logs.
|
||||
*
|
||||
* @_docloc: api/providers/abstract-provider
|
||||
*/
|
||||
export class PollingEventSubscriber implements Subscriber {
|
||||
#provider: AbstractProvider;
|
||||
#filter: EventFilter;
|
||||
#poller: (b: number) => void;
|
||||
|
||||
#running: boolean;
|
||||
|
||||
// The most recent block we have scanned for events. The value -2
|
||||
// indicates we still need to fetch an initial block number
|
||||
#blockNumber: number;
|
||||
|
||||
/**
|
||||
* Create a new **PollingTransactionSubscriber** attached to
|
||||
* %%provider%%, listening for %%filter%%.
|
||||
*/
|
||||
constructor(provider: AbstractProvider, filter: EventFilter) {
|
||||
this.#provider = provider;
|
||||
this.#filter = copy(filter);
|
||||
this.#poller = this.#poll.bind(this);
|
||||
this.#running = false;
|
||||
this.#blockNumber = -2;
|
||||
}
|
||||
|
||||
async #poll(blockNumber: number): Promise<void> {
|
||||
// The initial block hasn't been determined yet
|
||||
if (this.#blockNumber === -2) { return; }
|
||||
|
||||
const filter = copy(this.#filter);
|
||||
filter.fromBlock = this.#blockNumber + 1;
|
||||
filter.toBlock = blockNumber;
|
||||
|
||||
const logs = await this.#provider.getLogs(filter);
|
||||
|
||||
// No logs could just mean the node has not indexed them yet,
|
||||
// so we keep a sliding window of 60 blocks to keep scanning
|
||||
if (logs.length === 0) {
|
||||
if (this.#blockNumber < blockNumber - 60) {
|
||||
this.#blockNumber = blockNumber - 60;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (const log of logs) {
|
||||
this.#provider.emit(this.#filter, log);
|
||||
|
||||
// Only advance the block number when logs were found to
|
||||
// account for networks (like BNB and Polygon) which may
|
||||
// sacrifice event consistency for block event speed
|
||||
this.#blockNumber = log.blockNumber;
|
||||
}
|
||||
}
|
||||
|
||||
start(): void {
|
||||
if (this.#running) { return; }
|
||||
this.#running = true;
|
||||
|
||||
if (this.#blockNumber === -2) {
|
||||
this.#provider.getBlockNumber().then((blockNumber) => {
|
||||
this.#blockNumber = blockNumber;
|
||||
});
|
||||
}
|
||||
this.#provider.on("block", this.#poller);
|
||||
}
|
||||
|
||||
stop(): void {
|
||||
if (!this.#running) { return; }
|
||||
this.#running = false;
|
||||
|
||||
this.#provider.off("block", this.#poller);
|
||||
}
|
||||
|
||||
pause(dropWhilePaused?: boolean): void {
|
||||
this.stop();
|
||||
if (dropWhilePaused) { this.#blockNumber = -2; }
|
||||
}
|
||||
|
||||
resume(): void {
|
||||
this.start();
|
||||
}
|
||||
}
|
||||
11
dev/env/node_modules/ethers/src.ts/providers/ws-browser.ts
generated
vendored
Executable file
11
dev/env/node_modules/ethers/src.ts/providers/ws-browser.ts
generated
vendored
Executable file
@@ -0,0 +1,11 @@
|
||||
|
||||
function getGlobal(): any {
|
||||
if (typeof self !== 'undefined') { return self; }
|
||||
if (typeof window !== 'undefined') { return window; }
|
||||
if (typeof global !== 'undefined') { return global; }
|
||||
throw new Error('unable to locate global object');
|
||||
};
|
||||
|
||||
const _WebSocket = getGlobal().WebSocket;
|
||||
|
||||
export { _WebSocket as WebSocket };
|
||||
3
dev/env/node_modules/ethers/src.ts/providers/ws.ts
generated
vendored
Executable file
3
dev/env/node_modules/ethers/src.ts/providers/ws.ts
generated
vendored
Executable file
@@ -0,0 +1,3 @@
|
||||
export { WebSocket } from "ws";
|
||||
|
||||
|
||||
16
dev/env/node_modules/ethers/src.ts/thirdparty.d.ts
generated
vendored
Executable file
16
dev/env/node_modules/ethers/src.ts/thirdparty.d.ts
generated
vendored
Executable file
@@ -0,0 +1,16 @@
|
||||
|
||||
|
||||
declare module "ws" {
|
||||
export class WebSocket {
|
||||
constructor(...args: Array<any>);
|
||||
|
||||
onopen: null | ((...args: Array<any>) => any);
|
||||
onmessage: null | ((...args: Array<any>) => any);
|
||||
onerror: null | ((...args: Array<any>) => any);
|
||||
|
||||
readyState: number;
|
||||
|
||||
send(payload: any): void;
|
||||
close(code?: number, reason?: string): void;
|
||||
}
|
||||
}
|
||||
43
dev/env/node_modules/ethers/src.ts/transaction/accesslist.ts
generated
vendored
Executable file
43
dev/env/node_modules/ethers/src.ts/transaction/accesslist.ts
generated
vendored
Executable file
@@ -0,0 +1,43 @@
|
||||
import { getAddress } from "../address/index.js";
|
||||
import { assertArgument, isHexString } from "../utils/index.js";
|
||||
|
||||
import type { AccessList, AccessListish } from "./index.js";
|
||||
|
||||
|
||||
function accessSetify(addr: string, storageKeys: Array<string>): { address: string,storageKeys: Array<string> } {
|
||||
return {
|
||||
address: getAddress(addr),
|
||||
storageKeys: storageKeys.map((storageKey, index) => {
|
||||
assertArgument(isHexString(storageKey, 32), "invalid slot", `storageKeys[${ index }]`, storageKey);
|
||||
return storageKey.toLowerCase();
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a [[AccessList]] from any ethers-supported access-list structure.
|
||||
*/
|
||||
export function accessListify(value: AccessListish): AccessList {
|
||||
if (Array.isArray(value)) {
|
||||
return (<Array<[ string, Array<string>] | { address: string, storageKeys: Array<string>}>>value).map((set, index) => {
|
||||
if (Array.isArray(set)) {
|
||||
assertArgument(set.length === 2, "invalid slot set", `value[${ index }]`, set);
|
||||
return accessSetify(set[0], set[1])
|
||||
}
|
||||
assertArgument(set != null && typeof(set) === "object", "invalid address-slot set", "value", value);
|
||||
return accessSetify(set.address, set.storageKeys);
|
||||
});
|
||||
}
|
||||
|
||||
assertArgument(value != null && typeof(value) === "object", "invalid access list", "value", value);
|
||||
|
||||
const result: Array<{ address: string, storageKeys: Array<string> }> = Object.keys(value).map((addr) => {
|
||||
const storageKeys: Record<string, true> = value[addr].reduce((accum, storageKey) => {
|
||||
accum[storageKey] = true;
|
||||
return accum;
|
||||
}, <Record<string, true>>{ });
|
||||
return accessSetify(addr, Object.keys(storageKeys).sort())
|
||||
});
|
||||
result.sort((a, b) => (a.address.localeCompare(b.address)));
|
||||
return result;
|
||||
}
|
||||
28
dev/env/node_modules/ethers/src.ts/transaction/address.ts
generated
vendored
Executable file
28
dev/env/node_modules/ethers/src.ts/transaction/address.ts
generated
vendored
Executable file
@@ -0,0 +1,28 @@
|
||||
import { getAddress } from "../address/index.js";
|
||||
import { keccak256, SigningKey } from "../crypto/index.js";
|
||||
|
||||
import type { SignatureLike } from "../crypto/index.js";
|
||||
import type { BytesLike } from "../utils/index.js";
|
||||
|
||||
/**
|
||||
* Returns the address for the %%key%%.
|
||||
*
|
||||
* The key may be any standard form of public key or a private key.
|
||||
*/
|
||||
export function computeAddress(key: string | SigningKey): string {
|
||||
let pubkey: string;
|
||||
if (typeof(key) === "string") {
|
||||
pubkey = SigningKey.computePublicKey(key, false);
|
||||
} else {
|
||||
pubkey = key.publicKey;
|
||||
}
|
||||
return getAddress(keccak256("0x" + pubkey.substring(4)).substring(26));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the recovered address for the private key that was
|
||||
* used to sign %%digest%% that resulted in %%signature%%.
|
||||
*/
|
||||
export function recoverAddress(digest: BytesLike, signature: SignatureLike): string {
|
||||
return computeAddress(SigningKey.recoverPublicKey(digest, signature));
|
||||
}
|
||||
14
dev/env/node_modules/ethers/src.ts/transaction/authorization.ts
generated
vendored
Executable file
14
dev/env/node_modules/ethers/src.ts/transaction/authorization.ts
generated
vendored
Executable file
@@ -0,0 +1,14 @@
|
||||
import { getAddress } from "../address/index.js";
|
||||
import { Signature } from "../crypto/index.js";
|
||||
import { getBigInt } from "../utils/index.js";
|
||||
|
||||
import type { Authorization, AuthorizationLike } from "./index.js";
|
||||
|
||||
export function authorizationify(auth: AuthorizationLike): Authorization {
|
||||
return {
|
||||
address: getAddress(auth.address),
|
||||
nonce: getBigInt((auth.nonce != null) ? auth.nonce: 0),
|
||||
chainId: getBigInt((auth.chainId != null)? auth.chainId: 0),
|
||||
signature: Signature.from(auth.signature)
|
||||
};
|
||||
}
|
||||
51
dev/env/node_modules/ethers/src.ts/transaction/index.ts
generated
vendored
Executable file
51
dev/env/node_modules/ethers/src.ts/transaction/index.ts
generated
vendored
Executable file
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Each state-changing operation on Ethereum requires a transaction.
|
||||
*
|
||||
* @_section api/transaction:Transactions [about-transactions]
|
||||
*/
|
||||
|
||||
null;
|
||||
|
||||
import type { BigNumberish } from "../utils/maths.js";
|
||||
import type { Signature, SignatureLike } from "../crypto/index.js";
|
||||
|
||||
/**
|
||||
* A single [[AccessList]] entry of storage keys (slots) for an address.
|
||||
*/
|
||||
export type AccessListEntry = { address: string, storageKeys: Array<string> };
|
||||
|
||||
/**
|
||||
* An ordered collection of [[AccessList]] entries.
|
||||
*/
|
||||
export type AccessList = Array<AccessListEntry>;
|
||||
|
||||
/**
|
||||
* Any ethers-supported access list structure.
|
||||
*/
|
||||
export type AccessListish = AccessList |
|
||||
Array<[ string, Array<string> ]> |
|
||||
Record<string, Array<string>>;
|
||||
|
||||
// Keep here?
|
||||
export interface Authorization {
|
||||
address: string;
|
||||
nonce: bigint;
|
||||
chainId: bigint;
|
||||
signature: Signature;
|
||||
}
|
||||
|
||||
export type AuthorizationLike = {
|
||||
address: string;
|
||||
nonce: BigNumberish;
|
||||
chainId: BigNumberish;
|
||||
signature: SignatureLike
|
||||
};
|
||||
|
||||
export { accessListify } from "./accesslist.js";
|
||||
export { authorizationify } from "./authorization.js";
|
||||
export { computeAddress, recoverAddress } from "./address.js";
|
||||
export { Transaction } from "./transaction.js";
|
||||
|
||||
export type {
|
||||
Blob, BlobLike, KzgLibrary, KzgLibraryLike, TransactionLike
|
||||
} from "./transaction.js";
|
||||
1556
dev/env/node_modules/ethers/src.ts/transaction/transaction.ts
generated
vendored
Executable file
1556
dev/env/node_modules/ethers/src.ts/transaction/transaction.ts
generated
vendored
Executable file
File diff suppressed because it is too large
Load Diff
73
dev/env/node_modules/ethers/src.ts/utils/base58.ts
generated
vendored
Executable file
73
dev/env/node_modules/ethers/src.ts/utils/base58.ts
generated
vendored
Executable 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
25
dev/env/node_modules/ethers/src.ts/utils/base64-browser.ts
generated
vendored
Executable 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
56
dev/env/node_modules/ethers/src.ts/utils/base64.ts
generated
vendored
Executable 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
200
dev/env/node_modules/ethers/src.ts/utils/data.ts
generated
vendored
Executable 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);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user