Replaced logger class with simpler functions.
This commit is contained in:
parent
2740976d8b
commit
29949a6309
@ -1,6 +1,6 @@
|
||||
// See: https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
|
||||
|
||||
import { logger } from "../utils/logger.js";
|
||||
import { assertArgumentCount, throwArgumentError } from "../utils/index.js";
|
||||
|
||||
import { Coder, Reader, Result, Writer } from "./coders/abstract-coder.js";
|
||||
import { AddressCoder } from "./coders/address.js";
|
||||
@ -49,7 +49,7 @@ export class AbiCoder {
|
||||
if (match) {
|
||||
let size = parseInt(match[2] || "256");
|
||||
if (size === 0 || size > 256 || (size % 8) !== 0) {
|
||||
logger.throwArgumentError("invalid " + match[1] + " bit length", "param", param);
|
||||
throwArgumentError("invalid " + match[1] + " bit length", "param", param);
|
||||
}
|
||||
return new NumberCoder(size / 8, (match[1] === "int"), param.name);
|
||||
}
|
||||
@ -59,12 +59,12 @@ export class AbiCoder {
|
||||
if (match) {
|
||||
let size = parseInt(match[1]);
|
||||
if (size === 0 || size > 32) {
|
||||
logger.throwArgumentError("invalid bytes length", "param", param);
|
||||
throwArgumentError("invalid bytes length", "param", param);
|
||||
}
|
||||
return new FixedBytesCoder(size, param.name);
|
||||
}
|
||||
|
||||
return logger.throwArgumentError("invalid type", "type", param.type);
|
||||
return throwArgumentError("invalid type", "type", param.type);
|
||||
}
|
||||
|
||||
getDefaultValue(types: ReadonlyArray<string | ParamType>): Result {
|
||||
@ -74,7 +74,7 @@ export class AbiCoder {
|
||||
}
|
||||
|
||||
encode(types: ReadonlyArray<string | ParamType>, values: ReadonlyArray<any>): string {
|
||||
logger.assertArgumentCount(values.length, types.length, "types/values length mismatch");
|
||||
assertArgumentCount(values.length, types.length, "types/values length mismatch");
|
||||
|
||||
const coders = types.map((type) => this.#getCoder(ParamType.from(type)));
|
||||
const coder = (new TupleCoder(coders, "_"));
|
||||
|
@ -1,9 +1,7 @@
|
||||
|
||||
import { zeroPadBytes } from "../utils/data.js";
|
||||
|
||||
import { logger } from "../utils/logger.js";
|
||||
|
||||
import { toUtf8Bytes, toUtf8String } from "../utils/utf8.js";
|
||||
import {
|
||||
getBytes, toUtf8Bytes, toUtf8String, zeroPadBytes
|
||||
} from "../utils/index.js";
|
||||
|
||||
import type { BytesLike } from "../utils/index.js";
|
||||
|
||||
@ -21,7 +19,7 @@ export function formatBytes32String(text: string): string {
|
||||
}
|
||||
|
||||
export function parseBytes32String(_bytes: BytesLike): string {
|
||||
const data = logger.getBytes(_bytes, "bytes");
|
||||
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"); }
|
||||
|
@ -1,9 +1,9 @@
|
||||
|
||||
import { toArray, toBigInt, toNumber } from "../../utils/maths.js";
|
||||
import { concat, hexlify } from "../../utils/data.js";
|
||||
import { defineProperties } from "../../utils/properties.js";
|
||||
|
||||
import { logger } from "../../utils/logger.js";
|
||||
import {
|
||||
defineProperties, concat, getBytesCopy, getNumber, hexlify,
|
||||
toArray, toBigInt, toNumber,
|
||||
assertPrivate, throwArgumentError, throwError
|
||||
} from "../../utils/index.js";
|
||||
|
||||
import type { BigNumberish, BytesLike } from "../../utils/index.js";
|
||||
|
||||
@ -22,7 +22,7 @@ export class Result extends Array<any> {
|
||||
[ K: string | number ]: any
|
||||
|
||||
constructor(guard: any, items: Array<any>, keys?: Array<null | string>) {
|
||||
logger.assertPrivate(guard, _guard, "Result");
|
||||
assertPrivate(guard, _guard, "Result");
|
||||
super(...items);
|
||||
|
||||
// Name lookup table
|
||||
@ -44,7 +44,7 @@ export class Result extends Array<any> {
|
||||
get: (target, prop, receiver) => {
|
||||
if (typeof(prop) === "string") {
|
||||
if (prop.match(/^[0-9]+$/)) {
|
||||
const index = logger.getNumber(prop, "%index");
|
||||
const index = getNumber(prop, "%index");
|
||||
if (index < 0 || index >= this.length) {
|
||||
throw new RangeError("out of result range");
|
||||
}
|
||||
@ -153,7 +153,7 @@ function getValue(value: BigNumberish): Uint8Array {
|
||||
let bytes = toArray(value);
|
||||
|
||||
if (bytes.length > WordSize) {
|
||||
logger.throwError("value out-of-bounds", "BUFFER_OVERRUN", {
|
||||
throwError("value out-of-bounds", "BUFFER_OVERRUN", {
|
||||
buffer: bytes,
|
||||
length: WordSize,
|
||||
offset: bytes.length
|
||||
@ -161,7 +161,7 @@ function getValue(value: BigNumberish): Uint8Array {
|
||||
}
|
||||
|
||||
if (bytes.length !== WordSize) {
|
||||
bytes = logger.getBytesCopy(concat([ Padding.slice(bytes.length % WordSize), bytes ]));
|
||||
bytes = getBytesCopy(concat([ Padding.slice(bytes.length % WordSize), bytes ]));
|
||||
}
|
||||
|
||||
return bytes;
|
||||
@ -194,7 +194,7 @@ export abstract class Coder {
|
||||
}
|
||||
|
||||
_throwError(message: string, value: any): never {
|
||||
return logger.throwArgumentError(message, this.localName, value);
|
||||
return throwArgumentError(message, this.localName, value);
|
||||
}
|
||||
|
||||
abstract encode(writer: Writer, value: any): number;
|
||||
@ -225,15 +225,15 @@ export class Writer {
|
||||
}
|
||||
|
||||
appendWriter(writer: Writer): number {
|
||||
return this.#writeData(logger.getBytesCopy(writer.data));
|
||||
return this.#writeData(getBytesCopy(writer.data));
|
||||
}
|
||||
|
||||
// Arrayish item; pad on the right to *nearest* WordSize
|
||||
writeBytes(value: BytesLike): number {
|
||||
let bytes = logger.getBytesCopy(value);
|
||||
let bytes = getBytesCopy(value);
|
||||
const paddingOffset = bytes.length % WordSize;
|
||||
if (paddingOffset) {
|
||||
bytes = logger.getBytesCopy(concat([ bytes, Padding.slice(paddingOffset) ]))
|
||||
bytes = getBytesCopy(concat([ bytes, Padding.slice(paddingOffset) ]))
|
||||
}
|
||||
return this.#writeData(bytes);
|
||||
}
|
||||
@ -268,7 +268,7 @@ export class Reader {
|
||||
constructor(data: BytesLike, allowLoose?: boolean) {
|
||||
defineProperties<Reader>(this, { allowLoose: !!allowLoose });
|
||||
|
||||
this.#data = logger.getBytesCopy(data);
|
||||
this.#data = getBytesCopy(data);
|
||||
|
||||
this.#offset = 0;
|
||||
}
|
||||
@ -284,8 +284,8 @@ export class Reader {
|
||||
if (this.allowLoose && loose && this.#offset + length <= this.#data.length) {
|
||||
alignedLength = length;
|
||||
} else {
|
||||
logger.throwError("data out-of-bounds", "BUFFER_OVERRUN", {
|
||||
buffer: logger.getBytesCopy(this.#data),
|
||||
throwError("data out-of-bounds", "BUFFER_OVERRUN", {
|
||||
buffer: getBytesCopy(this.#data),
|
||||
length: this.#data.length,
|
||||
offset: this.#offset + alignedLength
|
||||
});
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { defineProperties } from "../../utils/properties.js";
|
||||
import { isError } from "../../utils/errors.js";
|
||||
import { logger } from "../../utils/logger.js";
|
||||
import {
|
||||
defineProperties, isError, assertArgumentCount, throwArgumentError, throwError
|
||||
} from "../../utils/index.js";
|
||||
|
||||
import { Typed } from "../typed.js";
|
||||
|
||||
import { Coder, Result, WordSize, Writer } from "./abstract-coder.js";
|
||||
import { AnonymousCoder } from "./anonymous.js";
|
||||
|
||||
@ -21,7 +22,7 @@ export function pack(writer: Writer, coders: ReadonlyArray<Coder>, values: Array
|
||||
arrayValues = coders.map((coder) => {
|
||||
const name = coder.localName;
|
||||
if (!name) {
|
||||
logger.throwError("cannot encode object for signature with missing names", "INVALID_ARGUMENT", {
|
||||
throwError("cannot encode object for signature with missing names", "INVALID_ARGUMENT", {
|
||||
argument: "values",
|
||||
info: { coder },
|
||||
value: values
|
||||
@ -29,7 +30,7 @@ export function pack(writer: Writer, coders: ReadonlyArray<Coder>, values: Array
|
||||
}
|
||||
|
||||
if (unique[name]) {
|
||||
logger.throwError("cannot encode object for signature with duplicate names", "INVALID_ARGUMENT", {
|
||||
throwError("cannot encode object for signature with duplicate names", "INVALID_ARGUMENT", {
|
||||
argument: "values",
|
||||
info: { coder },
|
||||
value: values
|
||||
@ -42,11 +43,11 @@ export function pack(writer: Writer, coders: ReadonlyArray<Coder>, values: Array
|
||||
});
|
||||
|
||||
} else {
|
||||
logger.throwArgumentError("invalid tuple value", "tuple", values);
|
||||
throwArgumentError("invalid tuple value", "tuple", values);
|
||||
}
|
||||
|
||||
if (coders.length !== arrayValues.length) {
|
||||
logger.throwArgumentError("types/value length mismatch", "tuple", values);
|
||||
throwArgumentError("types/value length mismatch", "tuple", values);
|
||||
}
|
||||
|
||||
let staticWriter = new Writer();
|
||||
@ -173,7 +174,7 @@ export class ArrayCoder extends Coder {
|
||||
writer.writeValue(value.length);
|
||||
}
|
||||
|
||||
logger.assertArgumentCount(value.length, count, "coder array" + (this.localName? (" "+ this.localName): ""));
|
||||
assertArgumentCount(value.length, count, "coder array" + (this.localName? (" "+ this.localName): ""));
|
||||
|
||||
let coders = [];
|
||||
for (let i = 0; i < value.length; i++) { coders.push(this.coder); }
|
||||
@ -192,7 +193,7 @@ export class ArrayCoder extends Coder {
|
||||
// bytes as a link to the data). This could use a much
|
||||
// tighter bound, but we are erroring on the side of safety.
|
||||
if (count * WordSize > reader.dataLength) {
|
||||
logger.throwError("insufficient data length", "BUFFER_OVERRUN", {
|
||||
throwError("insufficient data length", "BUFFER_OVERRUN", {
|
||||
buffer: reader.bytes,
|
||||
offset: count * WordSize,
|
||||
length: reader.dataLength
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { logger } from "../../utils/logger.js";
|
||||
import { hexlify } from "../../utils/data.js";
|
||||
import { getBytesCopy, hexlify } from "../../utils/index.js";
|
||||
|
||||
import { Coder } from "./abstract-coder.js";
|
||||
|
||||
@ -16,7 +15,7 @@ export class DynamicBytesCoder extends Coder {
|
||||
}
|
||||
|
||||
encode(writer: Writer, value: any): number {
|
||||
value = logger.getBytesCopy(value);
|
||||
value = getBytesCopy(value);
|
||||
let length = writer.writeValue(value.length);
|
||||
length += writer.writeBytes(value);
|
||||
return length;
|
||||
|
@ -1,7 +1,5 @@
|
||||
|
||||
import { logger } from "../../utils/logger.js";
|
||||
import { hexlify } from "../../utils/data.js";
|
||||
import { defineProperties } from "../../utils/properties.js";
|
||||
import { defineProperties, getBytesCopy, hexlify } from "../../utils/index.js";
|
||||
|
||||
import { Typed } from "../typed.js";
|
||||
import { Coder } from "./abstract-coder.js";
|
||||
@ -25,7 +23,7 @@ export class FixedBytesCoder extends Coder {
|
||||
}
|
||||
|
||||
encode(writer: Writer, _value: BytesLike | Typed): number {
|
||||
let data = logger.getBytesCopy(Typed.dereference(_value, this.type));
|
||||
let data = getBytesCopy(Typed.dereference(_value, this.type));
|
||||
if (data.length !== this.size) { this._throwError("incorrect data length", _value); }
|
||||
return writer.writeBytes(data);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { fromTwos, mask, toTwos } from "../../utils/maths.js";
|
||||
import { defineProperties } from "../../utils/properties.js";
|
||||
import {
|
||||
defineProperties, fromTwos, getBigInt, mask, toTwos
|
||||
} from "../../utils/index.js";
|
||||
|
||||
import { logger } from "../../utils/logger.js";
|
||||
import { Typed } from "../typed.js";
|
||||
import { Coder, WordSize } from "./abstract-coder.js";
|
||||
|
||||
@ -30,7 +30,7 @@ export class NumberCoder extends Coder {
|
||||
}
|
||||
|
||||
encode(writer: Writer, _value: BigNumberish | Typed): number {
|
||||
let value = logger.getBigInt(Typed.dereference(_value, this.type));
|
||||
let value = getBigInt(Typed.dereference(_value, this.type));
|
||||
|
||||
// Check bounds are safe for encoding
|
||||
let maxUintValue = mask(BN_MAX_UINT256, WordSize * 8);
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { logger } from "../utils/logger.js";
|
||||
import { defineProperties } from "../utils/index.js";
|
||||
import {
|
||||
defineProperties, getBigInt, getNumber,
|
||||
assertPrivate, throwArgumentError, throwError
|
||||
} from "../utils/index.js";
|
||||
|
||||
|
||||
export interface JsonFragmentType {
|
||||
@ -76,7 +78,9 @@ const regexNumber = new RegExp("^([0-9]+)");
|
||||
const regexIdentifier = new RegExp("^([a-zA-Z$_][a-zA-Z0-9$_]*)");
|
||||
const regexType = new RegExp("^(address|bool|bytes([0-9]*)|string|u?int([0-9]*))");
|
||||
|
||||
|
||||
/**
|
||||
* @ignore:
|
||||
*/
|
||||
export type Token = Readonly<{
|
||||
// Type of token (e.g. TYPE, KEYWORD, NUMBER, etc)
|
||||
type: string;
|
||||
@ -268,7 +272,7 @@ export function lex(text: string): TokenString {
|
||||
if (tokens.length > 0 && tokens[tokens.length - 1].type === "NUMBER") {
|
||||
const value = (tokens.pop() as Token).text;
|
||||
suffix = value + suffix;
|
||||
(<Writeable<Token>>(tokens[tokens.length - 1])).value = logger.getNumber(value);
|
||||
(<Writeable<Token>>(tokens[tokens.length - 1])).value = getNumber(value);
|
||||
}
|
||||
if (tokens.length === 0 || tokens[tokens.length - 1].type !== "BRACKET") {
|
||||
throw new Error("missing opening bracket");
|
||||
@ -381,7 +385,7 @@ function consumeGas(tokens: TokenString): null | bigint {
|
||||
if (tokens.peekType("AT")) {
|
||||
tokens.pop();
|
||||
if (tokens.peekType("NUMBER")) {
|
||||
return logger.getBigInt(tokens.pop().text);
|
||||
return getBigInt(tokens.pop().text);
|
||||
}
|
||||
throw new Error("invalid gas");
|
||||
}
|
||||
@ -399,7 +403,7 @@ const regexArrayType = new RegExp(/^(.*)\[([0-9]*)\]$/);
|
||||
function verifyBasicType(type: string): string {
|
||||
const match = type.match(regexType);
|
||||
if (!match) {
|
||||
return logger.throwArgumentError("invalid type", "type", type);
|
||||
return throwArgumentError("invalid type", "type", type);
|
||||
}
|
||||
if (type === "uint") { return "uint256"; }
|
||||
if (type === "int") { return "int256"; }
|
||||
@ -408,14 +412,14 @@ function verifyBasicType(type: string): string {
|
||||
// bytesXX
|
||||
const length = parseInt(match[2]);
|
||||
if (length === 0 || length > 32) {
|
||||
logger.throwArgumentError("invalid bytes length", "type", type);
|
||||
throwArgumentError("invalid bytes length", "type", type);
|
||||
}
|
||||
|
||||
} else if (match[3]) {
|
||||
// intXX or uintXX
|
||||
const size = parseInt(match[3] as string);
|
||||
if (size === 0 || size > 256 || size % 8) {
|
||||
logger.throwArgumentError("invalid numeric width", "type", type);
|
||||
throwArgumentError("invalid numeric width", "type", type);
|
||||
}
|
||||
}
|
||||
|
||||
@ -470,7 +474,7 @@ export class ParamType {
|
||||
|
||||
|
||||
constructor(guard: any, name: string, type: string, baseType: string, indexed: null | boolean, components: null | ReadonlyArray<ParamType>, arrayLength: null | number, arrayChildren: null | ParamType) {
|
||||
logger.assertPrivate(guard, _guard, "ParamType");
|
||||
assertPrivate(guard, _guard, "ParamType");
|
||||
Object.defineProperty(this, internal, { value: ParamTypeInternal });
|
||||
|
||||
if (components) { components = Object.freeze(components.slice()); }
|
||||
@ -500,7 +504,7 @@ export class ParamType {
|
||||
// - full: "tuple(uint256 foo, address bar) indexed baz"
|
||||
format(format: FormatType = FormatType.sighash): string {
|
||||
if (!FormatType[format]) {
|
||||
logger.throwArgumentError("invalid format type", "format", format);
|
||||
throwArgumentError("invalid format type", "format", format);
|
||||
}
|
||||
|
||||
if (format === FormatType.json) {
|
||||
@ -656,13 +660,13 @@ export class ParamType {
|
||||
|
||||
const name = obj.name;
|
||||
if (name && (typeof(name) !== "string" || !name.match(regexIdentifier))) {
|
||||
logger.throwArgumentError("invalid name", "obj.name", name);
|
||||
throwArgumentError("invalid name", "obj.name", name);
|
||||
}
|
||||
|
||||
let indexed = obj.indexed;
|
||||
if (indexed != null) {
|
||||
if (!allowIndexed) {
|
||||
logger.throwArgumentError("parameter cannot be indexed", "obj.indexed", obj.indexed);
|
||||
throwArgumentError("parameter cannot be indexed", "obj.indexed", obj.indexed);
|
||||
}
|
||||
indexed = !!indexed;
|
||||
}
|
||||
@ -756,7 +760,7 @@ export abstract class Fragment {
|
||||
readonly inputs!: ReadonlyArray<ParamType>;
|
||||
|
||||
constructor(guard: any, type: FragmentType, inputs: ReadonlyArray<ParamType>) {
|
||||
logger.assertPrivate(guard, _guard, "Fragment");
|
||||
assertPrivate(guard, _guard, "Fragment");
|
||||
inputs = Object.freeze(inputs.slice());
|
||||
defineProperties<Fragment>(this, { type, inputs });
|
||||
}
|
||||
@ -864,7 +868,7 @@ export class ErrorFragment extends NamedFragment {
|
||||
|
||||
format(format: FormatType = FormatType.sighash): string {
|
||||
if (!FormatType[format]) {
|
||||
logger.throwArgumentError("invalid format type", "format", format);
|
||||
throwArgumentError("invalid format type", "format", format);
|
||||
}
|
||||
|
||||
if (format === FormatType.json) {
|
||||
@ -905,7 +909,7 @@ export class EventFragment extends NamedFragment {
|
||||
|
||||
format(format: FormatType = FormatType.sighash): string {
|
||||
if (!FormatType[format]) {
|
||||
logger.throwArgumentError("invalid format type", "format", format);
|
||||
throwArgumentError("invalid format type", "format", format);
|
||||
}
|
||||
|
||||
if (format === FormatType.json) {
|
||||
@ -950,11 +954,11 @@ export class ConstructorFragment extends Fragment {
|
||||
|
||||
format(format: FormatType = FormatType.sighash): string {
|
||||
if (!FormatType[format]) {
|
||||
logger.throwArgumentError("invalid format type", "format", format);
|
||||
throwArgumentError("invalid format type", "format", format);
|
||||
}
|
||||
|
||||
if (format === FormatType.sighash) {
|
||||
logger.throwError("cannot format a constructor for sighash", "UNSUPPORTED_OPERATION", {
|
||||
throwError("cannot format a constructor for sighash", "UNSUPPORTED_OPERATION", {
|
||||
operation: "format(sighash)"
|
||||
});
|
||||
}
|
||||
@ -1012,7 +1016,7 @@ export class FunctionFragment extends NamedFragment {
|
||||
|
||||
format(format: FormatType = FormatType.sighash): string {
|
||||
if (!FormatType[format]) {
|
||||
logger.throwArgumentError("invalid format type", "format", format);
|
||||
throwArgumentError("invalid format type", "format", format);
|
||||
}
|
||||
|
||||
if (format === FormatType.json) {
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { concat, dataSlice, hexlify, zeroPadValue, isHexString } from "../utils/data.js";
|
||||
import { keccak256 } from "../crypto/index.js"
|
||||
import { id } from "../hash/index.js"
|
||||
import { logger } from "../utils/logger.js";
|
||||
import { defineProperties } from "../utils/properties.js";
|
||||
import { toHex } from "../utils/maths.js";
|
||||
import {
|
||||
concat, dataSlice, getBigInt, getBytes, getBytesCopy, hexlify,
|
||||
zeroPadValue, isHexString, defineProperties, throwArgumentError, toHex,
|
||||
throwError, makeError
|
||||
} from "../utils/index.js";
|
||||
|
||||
import { AbiCoder, defaultAbiCoder } from "./abi-coder.js";
|
||||
import { checkResultErrors, Result } from "./coders/abstract-coder.js";
|
||||
@ -182,7 +183,7 @@ export class Interface {
|
||||
switch (fragment.type) {
|
||||
case "constructor":
|
||||
if (this.deploy) {
|
||||
logger.warn("duplicate definition - constructor");
|
||||
console.log("duplicate definition - constructor");
|
||||
return;
|
||||
}
|
||||
//checkNames(fragment, "input", fragment.inputs);
|
||||
@ -208,11 +209,9 @@ export class Interface {
|
||||
return;
|
||||
}
|
||||
|
||||
// Two identical entries; ignore it
|
||||
const signature = fragment.format();
|
||||
if (bucket.has(signature)) {
|
||||
logger.warn("duplicate definition - " + signature);
|
||||
return;
|
||||
}
|
||||
if (bucket.has(signature)) { return; }
|
||||
|
||||
bucket.set(signature, fragment);
|
||||
});
|
||||
@ -228,7 +227,7 @@ export class Interface {
|
||||
format(format?: FormatType): string | Array<string> {
|
||||
if (!format) { format = FormatType.full; }
|
||||
if (format === FormatType.sighash) {
|
||||
logger.throwArgumentError("interface does not support formatting sighash", "format", format);
|
||||
throwArgumentError("interface does not support formatting sighash", "format", format);
|
||||
}
|
||||
|
||||
const abi = this.fragments.map((f) => f.format(format));
|
||||
@ -266,7 +265,7 @@ export class Interface {
|
||||
for (const fragment of this.#functions.values()) {
|
||||
if (selector === this.getSelector(fragment)) { return fragment; }
|
||||
}
|
||||
logger.throwArgumentError("no matching function", "selector", key);
|
||||
throwArgumentError("no matching function", "selector", key);
|
||||
}
|
||||
|
||||
// It is a bare name, look up the function (will return null if ambiguous)
|
||||
@ -328,11 +327,11 @@ export class Interface {
|
||||
}
|
||||
|
||||
if (matching.length === 0) {
|
||||
logger.throwArgumentError("no matching function", "name", key);
|
||||
throwArgumentError("no matching function", "name", key);
|
||||
|
||||
} else if (matching.length > 1 && forceUnique) {
|
||||
const matchStr = matching.map((m) => JSON.stringify(m.format())).join(", ");
|
||||
logger.throwArgumentError(`multiple matching functions (i.e. ${ matchStr })`, "name", key);
|
||||
throwArgumentError(`multiple matching functions (i.e. ${ matchStr })`, "name", key);
|
||||
}
|
||||
|
||||
return matching[0];
|
||||
@ -342,7 +341,7 @@ export class Interface {
|
||||
const result = this.#functions.get(FunctionFragment.fromString(key).format());
|
||||
if (result) { return result; }
|
||||
|
||||
return logger.throwArgumentError("no matching function", "signature", key);
|
||||
return throwArgumentError("no matching function", "signature", key);
|
||||
}
|
||||
getFunctionName(key: string): string {
|
||||
return (this.#getFunction(key, null, false)).name;
|
||||
@ -361,7 +360,7 @@ export class Interface {
|
||||
for (const fragment of this.#events.values()) {
|
||||
if (eventTopic === this.getEventTopic(fragment)) { return fragment; }
|
||||
}
|
||||
logger.throwArgumentError("no matching event", "eventTopic", key);
|
||||
throwArgumentError("no matching event", "eventTopic", key);
|
||||
}
|
||||
|
||||
// It is a bare name, look up the function (will return null if ambiguous)
|
||||
@ -396,10 +395,10 @@ export class Interface {
|
||||
}
|
||||
|
||||
if (matching.length === 0) {
|
||||
logger.throwArgumentError("no matching event", "name", key);
|
||||
throwArgumentError("no matching event", "name", key);
|
||||
} else if (matching.length > 1 && forceUnique) {
|
||||
// @TODO: refine by Typed
|
||||
logger.throwArgumentError("multiple matching events", "name", key);
|
||||
throwArgumentError("multiple matching events", "name", key);
|
||||
}
|
||||
|
||||
return matching[0];
|
||||
@ -409,7 +408,7 @@ export class Interface {
|
||||
const result = this.#events.get(EventFragment.fromString(key).format());
|
||||
if (result) { return result; }
|
||||
|
||||
return logger.throwArgumentError("no matching event", "signature", key);
|
||||
return throwArgumentError("no matching event", "signature", key);
|
||||
}
|
||||
getEventName(key: string): string {
|
||||
return (this.#getEvent(key, null, false)).name;
|
||||
@ -430,7 +429,7 @@ export class Interface {
|
||||
for (const fragment of this.#errors.values()) {
|
||||
if (selector === this.getSelector(fragment)) { return fragment; }
|
||||
}
|
||||
logger.throwArgumentError("no matching error", "selector", key);
|
||||
throwArgumentError("no matching error", "selector", key);
|
||||
}
|
||||
|
||||
// It is a bare name, look up the function (will return null if ambiguous)
|
||||
@ -443,10 +442,10 @@ export class Interface {
|
||||
if (matching.length === 0) {
|
||||
if (key === "Error") { return ErrorFragment.fromString("error Error(string)"); }
|
||||
if (key === "Panic") { return ErrorFragment.fromString("error Panic(uint256)"); }
|
||||
logger.throwArgumentError("no matching error", "name", key);
|
||||
throwArgumentError("no matching error", "name", key);
|
||||
} else if (matching.length > 1) {
|
||||
// @TODO: refine by Typed
|
||||
logger.throwArgumentError("multiple matching errors", "name", key);
|
||||
throwArgumentError("multiple matching errors", "name", key);
|
||||
}
|
||||
|
||||
return matching[0];
|
||||
@ -460,7 +459,7 @@ export class Interface {
|
||||
const result = this.#errors.get(key);
|
||||
if (result) { return result; }
|
||||
|
||||
return logger.throwArgumentError("no matching error", "signature", key);
|
||||
return throwArgumentError("no matching error", "signature", key);
|
||||
}
|
||||
|
||||
// Get the 4-byte selector used by Solidity to identify a function
|
||||
@ -508,7 +507,7 @@ export class Interface {
|
||||
if (typeof(fragment) === "string") { fragment = this.getError(fragment); }
|
||||
|
||||
if (dataSlice(data, 0, 4) !== this.getSelector(fragment)) {
|
||||
logger.throwArgumentError(`data signature does not match error ${ fragment.name }.`, "data", data);
|
||||
throwArgumentError(`data signature does not match error ${ fragment.name }.`, "data", data);
|
||||
}
|
||||
|
||||
return this._decodeParams(fragment.inputs, dataSlice(data, 4));
|
||||
@ -528,7 +527,7 @@ export class Interface {
|
||||
if (typeof(fragment) === "string") { fragment = this.getFunction(fragment); }
|
||||
|
||||
if (dataSlice(data, 0, 4) !== this.getSelector(fragment)) {
|
||||
logger.throwArgumentError(`data signature does not match function ${ fragment.name }.`, "data", data);
|
||||
throwArgumentError(`data signature does not match function ${ fragment.name }.`, "data", data);
|
||||
}
|
||||
|
||||
return this._decodeParams(fragment.inputs, dataSlice(data, 4));
|
||||
@ -550,7 +549,7 @@ export class Interface {
|
||||
|
||||
let message = "invalid length for result data";
|
||||
|
||||
const bytes = logger.getBytesCopy(data);
|
||||
const bytes = getBytesCopy(data);
|
||||
if ((bytes.length % 32) === 0) {
|
||||
try {
|
||||
return this.#abiCoder.decode(fragment.outputs, bytes);
|
||||
@ -560,7 +559,7 @@ export class Interface {
|
||||
}
|
||||
|
||||
// Call returned data with no error, but the data is junk
|
||||
return logger.throwError(message, "BAD_DATA", {
|
||||
return throwError(message, "BAD_DATA", {
|
||||
value: hexlify(bytes),
|
||||
info: { method: fragment.name, signature: fragment.format() }
|
||||
});
|
||||
@ -569,7 +568,7 @@ export class Interface {
|
||||
makeError(fragment: FunctionFragment | string, _data: BytesLike, tx?: { data: string }): Error {
|
||||
if (typeof(fragment) === "string") { fragment = this.getFunction(fragment); }
|
||||
|
||||
const data = logger.getBytes(_data);
|
||||
const data = getBytes(_data);
|
||||
|
||||
let args: undefined | Result = undefined;
|
||||
if (tx) {
|
||||
@ -616,7 +615,7 @@ export class Interface {
|
||||
}
|
||||
}
|
||||
|
||||
return logger.makeError("call revert exception", "CALL_EXCEPTION", {
|
||||
return makeError("call revert exception", "CALL_EXCEPTION", {
|
||||
data: hexlify(data), transaction: null,
|
||||
method: fragment.name, signature: fragment.format(), args,
|
||||
errorArgs, errorName, errorSignature, reason
|
||||
@ -668,7 +667,7 @@ export class Interface {
|
||||
}
|
||||
|
||||
if (values.length > eventFragment.inputs.length) {
|
||||
logger.throwError("too many arguments for " + eventFragment.format(), "UNEXPECTED_ARGUMENT", {
|
||||
throwError("too many arguments for " + eventFragment.format(), "UNEXPECTED_ARGUMENT", {
|
||||
count: values.length,
|
||||
expectedCount: eventFragment.inputs.length
|
||||
})
|
||||
@ -705,7 +704,7 @@ export class Interface {
|
||||
|
||||
if (!param.indexed) {
|
||||
if (value != null) {
|
||||
logger.throwArgumentError("cannot filter non-indexed parameters; must be null", ("contract." + param.name), value);
|
||||
throwArgumentError("cannot filter non-indexed parameters; must be null", ("contract." + param.name), value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -713,7 +712,7 @@ export class Interface {
|
||||
if (value == null) {
|
||||
topics.push(null);
|
||||
} else if (param.baseType === "array" || param.baseType === "tuple") {
|
||||
logger.throwArgumentError("filtering with tuples or arrays not supported", ("contract." + param.name), value);
|
||||
throwArgumentError("filtering with tuples or arrays not supported", ("contract." + param.name), value);
|
||||
} else if (Array.isArray(value)) {
|
||||
topics.push(value.map((value) => encodeTopic(param, value)));
|
||||
} else {
|
||||
@ -744,7 +743,7 @@ export class Interface {
|
||||
}
|
||||
|
||||
if (values.length !== eventFragment.inputs.length) {
|
||||
logger.throwArgumentError("event arguments/values mismatch", "values", values);
|
||||
throwArgumentError("event arguments/values mismatch", "values", values);
|
||||
}
|
||||
|
||||
eventFragment.inputs.forEach((param, index) => {
|
||||
@ -781,7 +780,7 @@ export class Interface {
|
||||
if (topics != null && !eventFragment.anonymous) {
|
||||
const eventTopic = this.getEventTopic(eventFragment);
|
||||
if (!isHexString(topics[0], 32) || topics[0].toLowerCase() !== eventTopic) {
|
||||
logger.throwArgumentError("fragment/topic mismatch", "topics[0]", topics[0]);
|
||||
throwArgumentError("fragment/topic mismatch", "topics[0]", topics[0]);
|
||||
}
|
||||
topics = topics.slice(1);
|
||||
}
|
||||
@ -846,8 +845,8 @@ export class Interface {
|
||||
// Given a transaction, find the matching function fragment (if any) and
|
||||
// determine all its properties and call parameters
|
||||
parseTransaction(tx: { data: string, value?: BigNumberish }): null | TransactionDescription {
|
||||
const data = logger.getBytes(tx.data, "tx.data");
|
||||
const value = logger.getBigInt((tx.value != null) ? tx.value: 0, "tx.value");
|
||||
const data = getBytes(tx.data, "tx.data");
|
||||
const value = getBigInt((tx.value != null) ? tx.value: 0, "tx.value");
|
||||
|
||||
const fragment = this.getFunction(hexlify(data.slice(0, 4)));
|
||||
|
||||
@ -887,7 +886,7 @@ export class Interface {
|
||||
}
|
||||
|
||||
|
||||
static from(value: ReadonlyArray<Fragment | string | JsonFragment> | string | Interface) {
|
||||
static from(value: ReadonlyArray<Fragment | string | JsonFragment> | string | Interface): Interface {
|
||||
// Already an Interface, which is immutable
|
||||
if (value instanceof Interface) { return value; }
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { keccak256 } from "../crypto/keccak.js";
|
||||
import { logger } from "../utils/logger.js";
|
||||
import { getBytes, throwArgumentError } from "../utils/index.js";
|
||||
|
||||
|
||||
const BN_0 = BigInt(0);
|
||||
@ -19,7 +19,7 @@ function getChecksumAddress(address: string): string {
|
||||
expanded[i] = chars[i].charCodeAt(0);
|
||||
}
|
||||
|
||||
const hashed = logger.getBytes(keccak256(expanded));
|
||||
const hashed = getBytes(keccak256(expanded));
|
||||
|
||||
for (let i = 0; i < 40; i += 2) {
|
||||
if ((hashed[i >> 1] >> 4) >= 8) {
|
||||
@ -84,7 +84,7 @@ function fromBase36(value: string): bigint {
|
||||
export function getAddress(address: string): string {
|
||||
|
||||
if (typeof(address) !== "string") {
|
||||
logger.throwArgumentError("invalid address", "address", address);
|
||||
throwArgumentError("invalid address", "address", address);
|
||||
}
|
||||
|
||||
if (address.match(/^(0x)?[0-9a-fA-F]{40}$/)) {
|
||||
@ -96,7 +96,7 @@ export function getAddress(address: string): string {
|
||||
|
||||
// It is a checksummed address with a bad checksum
|
||||
if (address.match(/([A-F].*[a-f])|([a-f].*[A-F])/) && result !== address) {
|
||||
logger.throwArgumentError("bad address checksum", "address", address);
|
||||
throwArgumentError("bad address checksum", "address", address);
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -106,7 +106,7 @@ export function getAddress(address: string): string {
|
||||
if (address.match(/^XE[0-9]{2}[0-9A-Za-z]{30,31}$/)) {
|
||||
// It is an ICAP address with a bad checksum
|
||||
if (address.substring(2, 4) !== ibanChecksum(address)) {
|
||||
logger.throwArgumentError("bad icap checksum", "address", address);
|
||||
throwArgumentError("bad icap checksum", "address", address);
|
||||
}
|
||||
|
||||
let result = fromBase36(address.substring(4)).toString(16);
|
||||
@ -114,7 +114,7 @@ export function getAddress(address: string): string {
|
||||
return getChecksumAddress("0x" + result);
|
||||
}
|
||||
|
||||
return logger.throwArgumentError("invalid address", "address", address);
|
||||
return throwArgumentError("invalid address", "address", address);
|
||||
}
|
||||
|
||||
export function getIcapAddress(address: string): string {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { logger } from "../utils/logger.js";
|
||||
import { throwArgumentError, throwError } from "../utils/index.js";
|
||||
|
||||
import { getAddress } from "./address.js";
|
||||
|
||||
@ -21,9 +21,9 @@ async function checkAddress(target: any, promise: Promise<null | string>): Promi
|
||||
const result = await promise;
|
||||
if (result == null || result === "0x0000000000000000000000000000000000000000") {
|
||||
if (typeof(target) === "string") {
|
||||
return logger.throwError("unconfigured name", "UNCONFIGURED_NAME", { value: target });
|
||||
return throwError("unconfigured name", "UNCONFIGURED_NAME", { value: target });
|
||||
}
|
||||
return logger.throwArgumentError("invalid AddressLike value; did not resolve to a value address", "target", target);
|
||||
return throwArgumentError("invalid AddressLike value; did not resolve to a value address", "target", target);
|
||||
}
|
||||
return getAddress(result);
|
||||
}
|
||||
@ -36,7 +36,7 @@ export function resolveAddress(target: AddressLike, resolver?: null | NameResolv
|
||||
if (target.match(/^0x[0-9a-f]{40}$/i)) { return getAddress(target); }
|
||||
|
||||
if (resolver == null) {
|
||||
return logger.throwError("ENS resolution requires a provider", "UNSUPPORTED_OPERATION", {
|
||||
return throwError("ENS resolution requires a provider", "UNSUPPORTED_OPERATION", {
|
||||
operation: "resolveName",
|
||||
});
|
||||
}
|
||||
@ -50,5 +50,5 @@ export function resolveAddress(target: AddressLike, resolver?: null | NameResolv
|
||||
return checkAddress(target, target);
|
||||
}
|
||||
|
||||
return logger.throwArgumentError("unsupported addressable value", "target", target);
|
||||
return throwArgumentError("unsupported addressable value", "target", target);
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { keccak256 } from "../crypto/keccak.js";
|
||||
import { concat, dataSlice, encodeRlp, logger } from "../utils/index.js";
|
||||
import {
|
||||
concat, dataSlice, getBigInt, getBytes, encodeRlp, throwArgumentError
|
||||
} from "../utils/index.js";
|
||||
|
||||
import { getAddress } from "./address.js";
|
||||
|
||||
@ -9,7 +11,7 @@ import type { BigNumberish, BytesLike } from "../utils/index.js";
|
||||
// http://ethereum.stackexchange.com/questions/760/how-is-the-address-of-an-ethereum-contract-computed
|
||||
export function getCreateAddress(tx: { from: string, nonce: BigNumberish }): string {
|
||||
const from = getAddress(tx.from);
|
||||
const nonce = logger.getBigInt(tx.nonce, "tx.nonce");
|
||||
const nonce = getBigInt(tx.nonce, "tx.nonce");
|
||||
|
||||
let nonceHex = nonce.toString(16);
|
||||
if (nonceHex === "0") {
|
||||
@ -25,15 +27,15 @@ export function getCreateAddress(tx: { from: string, nonce: BigNumberish }): str
|
||||
|
||||
export function getCreate2Address(_from: string, _salt: BytesLike, _initCodeHash: BytesLike): string {
|
||||
const from = getAddress(_from);
|
||||
const salt = logger.getBytes(_salt, "salt");
|
||||
const initCodeHash = logger.getBytes(_initCodeHash, "initCodeHash");
|
||||
const salt = getBytes(_salt, "salt");
|
||||
const initCodeHash = getBytes(_initCodeHash, "initCodeHash");
|
||||
|
||||
if (salt.length !== 32) {
|
||||
logger.throwArgumentError("salt must be 32 bytes", "salt", _salt);
|
||||
throwArgumentError("salt must be 32 bytes", "salt", _salt);
|
||||
}
|
||||
|
||||
if (initCodeHash.length !== 32) {
|
||||
logger.throwArgumentError("initCodeHash must be 32 bytes", "initCodeHash", _initCodeHash);
|
||||
throwArgumentError("initCodeHash must be 32 bytes", "initCodeHash", _initCodeHash);
|
||||
}
|
||||
|
||||
return getAddress(dataSlice(keccak256(concat([ "0xff", from, salt, initCodeHash ])), 12))
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { resolveAddress } from "../address/index.js";
|
||||
import { Interface, Typed } from "../abi/index.js";
|
||||
import {
|
||||
defineProperties, isCallException, isHexString, resolveProperties, logger
|
||||
} from "../utils/index.js";
|
||||
import { resolveAddress } from "../address/index.js";
|
||||
import { copyRequest, Log, TransactionResponse } from "../providers/index.js";
|
||||
import {
|
||||
defineProperties, isCallException, isHexString, resolveProperties,
|
||||
makeError, throwArgumentError, throwError
|
||||
} from "../utils/index.js";
|
||||
|
||||
import {
|
||||
ContractEventPayload,
|
||||
@ -132,9 +133,9 @@ export async function copyOverrides(arg: any): Promise<Omit<ContractTransaction,
|
||||
// Some sanity checking; these are what these methods adds
|
||||
//if ((<any>overrides).to) {
|
||||
if (overrides.to) {
|
||||
logger.throwArgumentError("cannot override to", "overrides.to", overrides.to);
|
||||
throwArgumentError("cannot override to", "overrides.to", overrides.to);
|
||||
} else if (overrides.data) {
|
||||
logger.throwArgumentError("cannot override data", "overrides.data", overrides.data);
|
||||
throwArgumentError("cannot override data", "overrides.data", overrides.data);
|
||||
}
|
||||
|
||||
// Resolve any from
|
||||
@ -223,7 +224,7 @@ class WrappedMethod<A extends Array<any> = Array<any>, R = any, D extends R | Co
|
||||
async send(...args: ContractMethodArgs<A>): Promise<ContractTransactionResponse> {
|
||||
const runner = this._contract.runner;
|
||||
if (!canSend(runner)) {
|
||||
return logger.throwError("contract runner does not support sending transactions", "UNSUPPORTED_OPERATION", {
|
||||
return throwError("contract runner does not support sending transactions", "UNSUPPORTED_OPERATION", {
|
||||
operation: "sendTransaction"
|
||||
});
|
||||
}
|
||||
@ -235,7 +236,7 @@ class WrappedMethod<A extends Array<any> = Array<any>, R = any, D extends R | Co
|
||||
async estimateGas(...args: ContractMethodArgs<A>): Promise<bigint> {
|
||||
const runner = getRunner(this._contract.runner, "estimateGas");
|
||||
if (!canEstimate(runner)) {
|
||||
return logger.throwError("contract runner does not support gas estimation", "UNSUPPORTED_OPERATION", {
|
||||
return throwError("contract runner does not support gas estimation", "UNSUPPORTED_OPERATION", {
|
||||
operation: "estimateGas"
|
||||
});
|
||||
}
|
||||
@ -245,7 +246,7 @@ class WrappedMethod<A extends Array<any> = Array<any>, R = any, D extends R | Co
|
||||
async staticCallResult(...args: ContractMethodArgs<A>): Promise<Result> {
|
||||
const runner = getRunner(this._contract.runner, "call");
|
||||
if (!canCall(runner)) {
|
||||
return logger.throwError("contract runner does not support calling", "UNSUPPORTED_OPERATION", {
|
||||
return throwError("contract runner does not support calling", "UNSUPPORTED_OPERATION", {
|
||||
operation: "call"
|
||||
});
|
||||
}
|
||||
@ -397,7 +398,7 @@ async function getSub(contract: BaseContract, event: ContractEventName): Promise
|
||||
// Make sure our runner can actually subscribe to events
|
||||
const provider = getProvider(contract.runner);
|
||||
if (!provider) {
|
||||
return logger.throwError("contract runner does not support subscribing", "UNSUPPORTED_OPERATION", {
|
||||
return throwError("contract runner does not support subscribing", "UNSUPPORTED_OPERATION", {
|
||||
operation: "on"
|
||||
});
|
||||
}
|
||||
@ -504,7 +505,7 @@ export class BaseContract implements Addressable, EventEmitterable<ContractEvent
|
||||
} else {
|
||||
const resolver = getRunner(runner, "resolveName");
|
||||
if (!canResolve(resolver)) {
|
||||
throw logger.makeError("contract runner does not support name resolution", "UNSUPPORTED_OPERATION", {
|
||||
throw makeError("contract runner does not support name resolution", "UNSUPPORTED_OPERATION", {
|
||||
operation: "resolveName"
|
||||
});
|
||||
}
|
||||
@ -566,7 +567,7 @@ export class BaseContract implements Addressable, EventEmitterable<ContractEvent
|
||||
async getDeployedCode(): Promise<null | string> {
|
||||
const provider = getProvider(this.runner);
|
||||
if (!provider) {
|
||||
return logger.throwError("runner does not support .provider", "UNSUPPORTED_OPERATION", {
|
||||
return throwError("runner does not support .provider", "UNSUPPORTED_OPERATION", {
|
||||
operation: "getDeployedCode"
|
||||
});
|
||||
}
|
||||
@ -591,7 +592,7 @@ export class BaseContract implements Addressable, EventEmitterable<ContractEvent
|
||||
// Make sure we can subscribe to a provider event
|
||||
const provider = getProvider(this.runner);
|
||||
if (provider == null) {
|
||||
return logger.throwError("contract runner does not support .provider", "UNSUPPORTED_OPERATION", {
|
||||
return throwError("contract runner does not support .provider", "UNSUPPORTED_OPERATION", {
|
||||
operation: "waitForDeployment"
|
||||
});
|
||||
}
|
||||
@ -637,7 +638,7 @@ export class BaseContract implements Addressable, EventEmitterable<ContractEvent
|
||||
|
||||
const provider = getProvider(this.runner);
|
||||
if (!provider) {
|
||||
return logger.throwError("contract runner does not have a provider", "UNSUPPORTED_OPERATION", {
|
||||
return throwError("contract runner does not have a provider", "UNSUPPORTED_OPERATION", {
|
||||
operation: "queryFilter"
|
||||
});
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
|
||||
import { Interface } from "../abi/index.js";
|
||||
import { getCreateAddress } from "../address/index.js";
|
||||
import { concat, defineProperties, hexlify, logger } from "../utils/index.js";
|
||||
import {
|
||||
concat, defineProperties, getBytes, hexlify,
|
||||
throwArgumentError, throwError
|
||||
} from "../utils/index.js";
|
||||
|
||||
import { BaseContract, copyOverrides, resolveArgs } from "./contract.js";
|
||||
|
||||
@ -27,11 +30,11 @@ export class ContractFactory<A extends Array<any> = Array<any>, I = BaseContract
|
||||
|
||||
// Dereference Solidity bytecode objects and allow a missing `0x`-prefix
|
||||
if (bytecode instanceof Uint8Array) {
|
||||
bytecode = hexlify(logger.getBytes(bytecode));
|
||||
bytecode = hexlify(getBytes(bytecode));
|
||||
} else {
|
||||
if (typeof(bytecode) === "object") { bytecode = bytecode.object; }
|
||||
if (bytecode.substring(0, 2) !== "0x") { bytecode = "0x" + bytecode; }
|
||||
bytecode = hexlify(logger.getBytes(bytecode));
|
||||
bytecode = hexlify(getBytes(bytecode));
|
||||
}
|
||||
|
||||
defineProperties<ContractFactory>(this, {
|
||||
@ -62,7 +65,7 @@ export class ContractFactory<A extends Array<any> = Array<any>, I = BaseContract
|
||||
const tx = await this.getDeployTransaction(...args);
|
||||
|
||||
if (!this.runner || typeof(this.runner.sendTransaction) !== "function") {
|
||||
return logger.throwError("factory runner does not support sending transactions", "UNSUPPORTED_OPERATION", {
|
||||
return throwError("factory runner does not support sending transactions", "UNSUPPORTED_OPERATION", {
|
||||
operation: "sendTransaction"
|
||||
});
|
||||
}
|
||||
@ -78,7 +81,7 @@ export class ContractFactory<A extends Array<any> = Array<any>, I = BaseContract
|
||||
|
||||
static fromSolidity<A extends Array<any> = Array<any>, I = ContractInterface>(output: any, runner?: ContractRunner): ContractFactory<A, I> {
|
||||
if (output == null) {
|
||||
logger.throwArgumentError("bad compiler output", "output", output);
|
||||
throwArgumentError("bad compiler output", "output", output);
|
||||
}
|
||||
|
||||
if (typeof(output) === "string") { output = JSON.parse(output); }
|
||||
|
@ -5,7 +5,7 @@ import { pbkdf2 } from "@noble/hashes/pbkdf2";
|
||||
import { sha256 } from "@noble/hashes/sha256";
|
||||
import { sha512 } from "@noble/hashes/sha512";
|
||||
|
||||
import { logger } from "../utils/logger.js";
|
||||
import { throwArgumentError, throwError } from "../utils/index.js";
|
||||
|
||||
|
||||
declare global {
|
||||
@ -37,13 +37,13 @@ export function createHash(algo: string): CryptoHasher {
|
||||
case "sha256": return sha256.create();
|
||||
case "sha512": return sha512.create();
|
||||
}
|
||||
return logger.throwArgumentError("invalid hashing algorithm name", "algorithm", algo);
|
||||
return throwArgumentError("invalid hashing algorithm name", "algorithm", algo);
|
||||
}
|
||||
|
||||
export function createHmac(_algo: string, key: Uint8Array): CryptoHasher {
|
||||
const algo = ({ sha256, sha512 }[_algo]);
|
||||
if (algo == null) {
|
||||
return logger.throwArgumentError("invalid hmac algorithm", "algorithm", _algo);
|
||||
return throwArgumentError("invalid hmac algorithm", "algorithm", _algo);
|
||||
}
|
||||
return hmac.create(algo, key);
|
||||
}
|
||||
@ -51,20 +51,20 @@ export function createHmac(_algo: string, key: Uint8Array): CryptoHasher {
|
||||
export function pbkdf2Sync(password: Uint8Array, salt: Uint8Array, iterations: number, keylen: number, _algo: "sha256" | "sha512"): Uint8Array {
|
||||
const algo = ({ sha256, sha512 }[_algo]);
|
||||
if (algo == null) {
|
||||
return logger.throwArgumentError("invalid pbkdf2 algorithm", "algorithm", _algo);
|
||||
return throwArgumentError("invalid pbkdf2 algorithm", "algorithm", _algo);
|
||||
}
|
||||
return pbkdf2(algo, password, salt, { c: iterations, dkLen: keylen });
|
||||
}
|
||||
|
||||
export function randomBytes(length: number): Uint8Array {
|
||||
if (crypto == null) {
|
||||
return logger.throwError("platform does not support secure random numbers", "UNSUPPORTED_OPERATION", {
|
||||
return throwError("platform does not support secure random numbers", "UNSUPPORTED_OPERATION", {
|
||||
operation: "randomBytes"
|
||||
});
|
||||
}
|
||||
|
||||
if (!Number.isInteger(length) || length <= 0 || length > 1024) {
|
||||
logger.throwArgumentError("invalid length", "length", length);
|
||||
throwArgumentError("invalid length", "length", length);
|
||||
}
|
||||
|
||||
const result = new Uint8Array(length);
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { createHmac } from "./crypto.js";
|
||||
import { hexlify, logger } from "../utils/index.js";
|
||||
import { getBytes, hexlify } from "../utils/index.js";
|
||||
|
||||
import type { BytesLike } from "../utils/index.js";
|
||||
|
||||
@ -13,8 +13,8 @@ const _computeHmac = function(algorithm: "sha256" | "sha512", key: Uint8Array, d
|
||||
let __computeHmac = _computeHmac;
|
||||
|
||||
export function computeHmac(algorithm: "sha256" | "sha512", _key: BytesLike, _data: BytesLike): string {
|
||||
const key = logger.getBytes(_key, "key");
|
||||
const data = logger.getBytes(_data, "data");
|
||||
const key = getBytes(_key, "key");
|
||||
const data = getBytes(_data, "data");
|
||||
return hexlify(__computeHmac(algorithm, key, data));
|
||||
}
|
||||
computeHmac._ = _computeHmac;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { keccak_256 } from "@noble/hashes/sha3";
|
||||
|
||||
import { hexlify, logger } from "../utils/index.js";
|
||||
import { getBytes, hexlify } from "../utils/index.js";
|
||||
|
||||
import type { BytesLike } from "../utils/index.js";
|
||||
|
||||
@ -14,7 +14,7 @@ const _keccak256 = function(data: Uint8Array): Uint8Array {
|
||||
let __keccak256: (data: Uint8Array) => BytesLike = _keccak256;
|
||||
|
||||
export function keccak256(_data: BytesLike): string {
|
||||
const data = logger.getBytes(_data, "data");
|
||||
const data = getBytes(_data, "data");
|
||||
return hexlify(__keccak256(data));
|
||||
}
|
||||
keccak256._ = _keccak256;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { pbkdf2Sync } from "./crypto.js";
|
||||
|
||||
import { hexlify, logger } from "../utils/index.js";
|
||||
import { getBytes, hexlify } from "../utils/index.js";
|
||||
|
||||
import type { BytesLike } from "../utils/index.js";
|
||||
|
||||
@ -14,8 +14,8 @@ const _pbkdf2 = function(password: Uint8Array, salt: Uint8Array, iterations: num
|
||||
let __pbkdf2 = _pbkdf2;
|
||||
|
||||
export function pbkdf2(_password: BytesLike, _salt: BytesLike, iterations: number, keylen: number, algo: "sha256" | "sha512"): string {
|
||||
const password = logger.getBytes(_password, "password");
|
||||
const salt = logger.getBytes(_salt, "salt");
|
||||
const password = getBytes(_password, "password");
|
||||
const salt = getBytes(_salt, "salt");
|
||||
return hexlify(__pbkdf2(password, salt, iterations, keylen, algo));
|
||||
}
|
||||
pbkdf2._ = _pbkdf2;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { ripemd160 as noble_ripemd160 } from "@noble/hashes/ripemd160";
|
||||
|
||||
import { hexlify, logger } from "../utils/index.js";
|
||||
import { getBytes, hexlify } from "../utils/index.js";
|
||||
|
||||
import type { BytesLike } from "../utils/index.js";
|
||||
|
||||
@ -14,7 +14,7 @@ const _ripemd160 = function(data: Uint8Array): Uint8Array {
|
||||
let __ripemd160: (data: Uint8Array) => BytesLike = _ripemd160;
|
||||
|
||||
export function ripemd160(_data: BytesLike): string {
|
||||
const data = logger.getBytes(_data, "data");
|
||||
const data = getBytes(_data, "data");
|
||||
return hexlify(__ripemd160(data));
|
||||
}
|
||||
ripemd160._ = _ripemd160;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { scrypt as _nobleSync, scryptAsync as _nobleAsync } from "@noble/hashes/scrypt";
|
||||
|
||||
import { hexlify as H, logger } from "../utils/index.js";
|
||||
import { getBytes, hexlify as H } from "../utils/index.js";
|
||||
|
||||
import type { BytesLike } from "../utils/index.js";
|
||||
|
||||
@ -22,8 +22,8 @@ let __scryptSync: (passwd: Uint8Array, salt: Uint8Array, N: number, r: number, p
|
||||
|
||||
|
||||
export async function scrypt(_passwd: BytesLike, _salt: BytesLike, N: number, r: number, p: number, dkLen: number, progress?: ProgressCallback): Promise<string> {
|
||||
const passwd = logger.getBytes(_passwd, "passwd");
|
||||
const salt = logger.getBytes(_salt, "salt");
|
||||
const passwd = getBytes(_passwd, "passwd");
|
||||
const salt = getBytes(_salt, "salt");
|
||||
return H(await __scryptAsync(passwd, salt, N, r, p, dkLen, progress));
|
||||
}
|
||||
scrypt._ = _scryptAsync;
|
||||
@ -35,8 +35,8 @@ scrypt.register = function(func: (passwd: Uint8Array, salt: Uint8Array, N: numbe
|
||||
Object.freeze(scrypt);
|
||||
|
||||
export function scryptSync(_passwd: BytesLike, _salt: BytesLike, N: number, r: number, p: number, dkLen: number): string {
|
||||
const passwd = logger.getBytes(_passwd, "passwd");
|
||||
const salt = logger.getBytes(_salt, "salt");
|
||||
const passwd = getBytes(_passwd, "passwd");
|
||||
const salt = getBytes(_salt, "salt");
|
||||
return H(__scryptSync(passwd, salt, N, r, p, dkLen));
|
||||
}
|
||||
scryptSync._ = _scryptSync;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { createHash } from "./crypto.js";
|
||||
|
||||
import { hexlify, logger } from "../utils/index.js";
|
||||
import { getBytes, hexlify } from "../utils/index.js";
|
||||
|
||||
import type { BytesLike } from "../utils/index.js";
|
||||
|
||||
@ -20,7 +20,7 @@ let locked256 = false, locked512 = false;
|
||||
|
||||
|
||||
export function sha256(_data: BytesLike): string {
|
||||
const data = logger.getBytes(_data, "data");
|
||||
const data = getBytes(_data, "data");
|
||||
return hexlify(__sha256(data));
|
||||
}
|
||||
sha256._ = _sha256;
|
||||
@ -32,7 +32,7 @@ sha256.register = function(func: (data: Uint8Array) => BytesLike): void {
|
||||
Object.freeze(sha256);
|
||||
|
||||
export function sha512(_data: BytesLike): string {
|
||||
const data = logger.getBytes(_data, "data");
|
||||
const data = getBytes(_data, "data");
|
||||
return hexlify(__sha512(data));
|
||||
}
|
||||
sha512._ = _sha512;
|
||||
|
@ -1,9 +1,13 @@
|
||||
import { ZeroHash } from "../constants/index.js";
|
||||
import {
|
||||
concat, dataLength, getStore, hexlify, isHexString, logger, setStore
|
||||
concat, dataLength, getBigInt, getBytes, getNumber, getStore, hexlify,
|
||||
isHexString, setStore,
|
||||
assertPrivate, throwArgumentError
|
||||
} from "../utils/index.js";
|
||||
|
||||
import type { BigNumberish, BytesLike, Freezable, Frozen } from "../utils/index.js";
|
||||
import type {
|
||||
BigNumberish, BytesLike, Freezable, Frozen
|
||||
} from "../utils/index.js";
|
||||
|
||||
|
||||
// Constants
|
||||
@ -45,7 +49,7 @@ export class Signature implements Freezable<Signature> {
|
||||
get r(): string { return getStore(this.#props, "r"); }
|
||||
set r(value: BytesLike) {
|
||||
if (dataLength(value) !== 32) {
|
||||
logger.throwArgumentError("invalid r", "value", value);
|
||||
throwArgumentError("invalid r", "value", value);
|
||||
}
|
||||
setStore(this.#props, "r", hexlify(value));
|
||||
}
|
||||
@ -53,16 +57,16 @@ export class Signature implements Freezable<Signature> {
|
||||
get s(): string { return getStore(this.#props, "s"); }
|
||||
set s(value: BytesLike) {
|
||||
if (dataLength(value) !== 32) {
|
||||
logger.throwArgumentError("invalid r", "value", value);
|
||||
} else if (logger.getBytes(value)[0] & 0x80) {
|
||||
logger.throwArgumentError("non-canonical s", "value", value);
|
||||
throwArgumentError("invalid r", "value", value);
|
||||
} else if (getBytes(value)[0] & 0x80) {
|
||||
throwArgumentError("non-canonical s", "value", value);
|
||||
}
|
||||
setStore(this.#props, "s", hexlify(value));
|
||||
}
|
||||
|
||||
get v(): 27 | 28 { return getStore(this.#props, "v"); }
|
||||
set v(value: BigNumberish) {
|
||||
const v = logger.getNumber(value, "value");
|
||||
const v = getNumber(value, "value");
|
||||
if (v !== 27 && v !== 28) { throw new Error("@TODO"); }
|
||||
setStore(this.#props, "v", v);
|
||||
}
|
||||
@ -89,7 +93,7 @@ export class Signature implements Freezable<Signature> {
|
||||
|
||||
get yParityAndS(): string {
|
||||
// The EIP-2098 compact representation
|
||||
const yParityAndS = logger.getBytes(this.s);
|
||||
const yParityAndS = getBytes(this.s);
|
||||
if (this.yParity) { yParityAndS[0] |= 0x80; }
|
||||
return hexlify(yParityAndS);
|
||||
}
|
||||
@ -103,11 +107,11 @@ export class Signature implements Freezable<Signature> {
|
||||
}
|
||||
|
||||
constructor(guard: any, r: string, s: string, v: 27 | 28) {
|
||||
logger.assertPrivate(guard, _guard, "Signature");
|
||||
assertPrivate(guard, _guard, "Signature");
|
||||
this.#props = { r, s, v, networkV: null };
|
||||
}
|
||||
|
||||
[Symbol.for('nodejs.util.inspect.custom')]() {
|
||||
[Symbol.for('nodejs.util.inspect.custom')](): string {
|
||||
return `Signature { r: "${ this.r }", s: "${ this.s }", yParity: ${ this.yParity }, networkV: ${ this.networkV } }`;
|
||||
}
|
||||
|
||||
@ -141,25 +145,25 @@ export class Signature implements Freezable<Signature> {
|
||||
|
||||
// Get the chain ID from an EIP-155 v
|
||||
static getChainId(v: BigNumberish): bigint {
|
||||
const bv = logger.getBigInt(v, "v");
|
||||
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
|
||||
if (bv < BN_35) { logger.throwArgumentError("invalid EIP-155 v", "v", v); }
|
||||
if (bv < BN_35) { throwArgumentError("invalid EIP-155 v", "v", v); }
|
||||
|
||||
return (bv - BN_35) / BN_2;
|
||||
}
|
||||
|
||||
// Get the EIP-155 v transformed for a given chainId
|
||||
static getChainIdV(chainId: BigNumberish, v: 27 | 28): bigint {
|
||||
return (logger.getBigInt(chainId) * BN_2) + BigInt(35 + v - 27);
|
||||
return (getBigInt(chainId) * BN_2) + BigInt(35 + v - 27);
|
||||
}
|
||||
|
||||
// Convert an EIP-155 v into a normalized v
|
||||
static getNormalizedV(v: BigNumberish): 27 | 28 {
|
||||
const bv = logger.getBigInt(v);
|
||||
const bv = getBigInt(v);
|
||||
|
||||
if (bv == BN_0) { return 27; }
|
||||
if (bv == BN_1) { return 28; }
|
||||
@ -170,11 +174,11 @@ export class Signature implements Freezable<Signature> {
|
||||
|
||||
static from(sig: SignatureLike): Signature {
|
||||
const throwError = (message: string) => {
|
||||
return logger.throwArgumentError(message, "signature", sig);
|
||||
return throwArgumentError(message, "signature", sig);
|
||||
};
|
||||
|
||||
if (typeof(sig) === "string") {
|
||||
const bytes = logger.getBytes(sig, "signature");
|
||||
const bytes = getBytes(sig, "signature");
|
||||
if (bytes.length === 64) {
|
||||
const r = hexlify(bytes.slice(0, 32));
|
||||
const s = bytes.slice(32, 64);
|
||||
@ -210,19 +214,19 @@ export class Signature implements Freezable<Signature> {
|
||||
|
||||
if (yParityAndS != null) {
|
||||
if (!isHexString(yParityAndS, 32)) { throwError("invalid yParityAndS"); }
|
||||
const bytes = logger.getBytes(yParityAndS);
|
||||
const bytes = getBytes(yParityAndS);
|
||||
bytes[0] &= 0x7f;
|
||||
return hexlify(bytes);
|
||||
}
|
||||
|
||||
return throwError("missing s");
|
||||
})(sig.s, sig.yParityAndS);
|
||||
if (logger.getBytes(s)[0] & 0x80) { throwError("non-canonical s"); }
|
||||
if (getBytes(s)[0] & 0x80) { throwError("non-canonical s"); }
|
||||
|
||||
// Get v; by any means necessary (we check consistency below)
|
||||
const { networkV, v } = (function(_v?: BigNumberish, yParityAndS?: string, yParity?: number): { networkV?: bigint, v: 27 | 28 } {
|
||||
if (_v != null) {
|
||||
const v = logger.getBigInt(_v);
|
||||
const v = getBigInt(_v);
|
||||
return {
|
||||
networkV: ((v >= BN_35) ? v: undefined),
|
||||
v: Signature.getNormalizedV(v)
|
||||
@ -231,7 +235,7 @@ export class Signature implements Freezable<Signature> {
|
||||
|
||||
if (yParityAndS != null) {
|
||||
if (!isHexString(yParityAndS, 32)) { throwError("invalid yParityAndS"); }
|
||||
return { v: ((logger.getBytes(yParityAndS)[0] & 0x80) ? 28: 27) };
|
||||
return { v: ((getBytes(yParityAndS)[0] & 0x80) ? 28: 27) };
|
||||
}
|
||||
|
||||
if (yParity != null) {
|
||||
|
@ -1,7 +1,9 @@
|
||||
|
||||
import * as secp256k1 from "@noble/secp256k1";
|
||||
|
||||
import { concat, hexlify, toHex, logger } from "../utils/index.js";
|
||||
import {
|
||||
concat, getBytes, getBytesCopy, hexlify, toHex, throwArgumentError
|
||||
} from "../utils/index.js";
|
||||
|
||||
import { computeHmac } from "./hmac.js";
|
||||
import { Signature } from "./signature.js";
|
||||
@ -15,7 +17,7 @@ import type { SignatureLike } from "./index.js";
|
||||
|
||||
// Make noble-secp256k1 sync
|
||||
secp256k1.utils.hmacSha256Sync = function(key: Uint8Array, ...messages: Array<Uint8Array>): Uint8Array {
|
||||
return logger.getBytes(computeHmac("sha256", key, concat(messages)));
|
||||
return getBytes(computeHmac("sha256", key, concat(messages)));
|
||||
}
|
||||
|
||||
export class SigningKey {
|
||||
@ -40,7 +42,7 @@ export class SigningKey {
|
||||
logger.assertArgument(() => (dataLength(digest) === 32), "invalid digest length", "digest", digest);
|
||||
*/
|
||||
|
||||
const [ sigDer, recid ] = secp256k1.signSync(logger.getBytesCopy(digest), logger.getBytesCopy(this.#privateKey), {
|
||||
const [ sigDer, recid ] = secp256k1.signSync(getBytesCopy(digest), getBytesCopy(this.#privateKey), {
|
||||
recovered: true,
|
||||
canonical: true
|
||||
});
|
||||
@ -56,11 +58,11 @@ export class SigningKey {
|
||||
|
||||
computeShardSecret(other: BytesLike): string {
|
||||
const pubKey = SigningKey.computePublicKey(other);
|
||||
return hexlify(secp256k1.getSharedSecret(logger.getBytesCopy(this.#privateKey), pubKey));
|
||||
return hexlify(secp256k1.getSharedSecret(getBytesCopy(this.#privateKey), pubKey));
|
||||
}
|
||||
|
||||
static computePublicKey(key: BytesLike, compressed?: boolean): string {
|
||||
let bytes = logger.getBytes(key, "key");
|
||||
let bytes = getBytes(key, "key");
|
||||
|
||||
if (bytes.length === 32) {
|
||||
const pubKey = secp256k1.getPublicKey(bytes, !!compressed);
|
||||
@ -80,12 +82,12 @@ export class SigningKey {
|
||||
|
||||
static recoverPublicKey(digest: BytesLike, signature: SignatureLike): string {
|
||||
const sig = Signature.from(signature);
|
||||
const der = secp256k1.Signature.fromCompact(logger.getBytesCopy(concat([ sig.r, sig.s ]))).toDERRawBytes();
|
||||
const der = secp256k1.Signature.fromCompact(getBytesCopy(concat([ sig.r, sig.s ]))).toDERRawBytes();
|
||||
|
||||
const pubKey = secp256k1.recoverPublicKey(logger.getBytesCopy(digest), der, sig.yParity);
|
||||
const pubKey = secp256k1.recoverPublicKey(getBytesCopy(digest), der, sig.yParity);
|
||||
if (pubKey != null) { return hexlify(pubKey); }
|
||||
|
||||
return logger.throwArgumentError("invalid signautre for digest", "signature", signature);
|
||||
return throwArgumentError("invalid signautre for digest", "signature", signature);
|
||||
}
|
||||
|
||||
static _addPoints(p0: BytesLike, p1: BytesLike, compressed?: boolean): string {
|
||||
|
@ -22,7 +22,7 @@ export {
|
||||
|
||||
export {
|
||||
ZeroAddress,
|
||||
NegativeOne, Zero, One, Two, WeiPerEther, MaxUint256, MinInt256, MaxInt256,
|
||||
NegativeOne, Zero, One, Two, WeiPerEther, MaxUint256, MinInt256, MaxInt256, N,
|
||||
ZeroHash,
|
||||
EtherSymbol, MessagePrefix
|
||||
} from "./constants/index.js";
|
||||
@ -47,7 +47,7 @@ export {
|
||||
|
||||
export {
|
||||
id,
|
||||
//isValidName, namehash, dnsEncode
|
||||
isValidName, namehash, dnsEncode,
|
||||
hashMessage,
|
||||
solidityPacked, solidityPackedKeccak256, solidityPackedSha256,
|
||||
TypedDataEncoder
|
||||
@ -65,7 +65,7 @@ export {
|
||||
isCallException, isError,
|
||||
FetchRequest, FetchResponse,
|
||||
FixedFormat, FixedNumber, formatFixed, parseFixed,
|
||||
assertArgument, Logger, logger,
|
||||
assertArgument,
|
||||
fromTwos, toTwos, mask, toArray, toBigInt, toHex, toNumber,
|
||||
formatEther, parseEther, formatUnits, parseUnits,
|
||||
_toEscapedUtf8String, toUtf8Bytes, toUtf8CodePoints, toUtf8String,
|
||||
|
@ -1,6 +1,8 @@
|
||||
|
||||
import { keccak256 } from "../crypto/keccak.js";
|
||||
import { concat, hexlify, logger, toUtf8Bytes, toUtf8String } from "../utils/index.js";
|
||||
import {
|
||||
concat, hexlify, throwArgumentError, toUtf8Bytes, toUtf8String
|
||||
} from "../utils/index.js";
|
||||
|
||||
|
||||
//import { ens_normalize } from "./ens-normalize/lib";
|
||||
@ -55,7 +57,7 @@ export function isValidName(name: string): boolean {
|
||||
export function namehash(name: string): string {
|
||||
/* istanbul ignore if */
|
||||
if (typeof(name) !== "string") {
|
||||
logger.throwArgumentError("invalid ENS name; not a string", "name", name);
|
||||
throwArgumentError("invalid ENS name; not a string", "name", name);
|
||||
}
|
||||
|
||||
let result: string | Uint8Array = Zeros;
|
||||
|
@ -1,8 +1,10 @@
|
||||
import {
|
||||
concat, dataLength, hexlify, logger, toArray, toTwos, toUtf8Bytes, zeroPadBytes, zeroPadValue
|
||||
keccak256 as _keccak256, sha256 as _sha256
|
||||
} from "../crypto/index.js";
|
||||
import {
|
||||
concat, dataLength, getBytes, hexlify, toArray, toTwos, toUtf8Bytes, zeroPadBytes, zeroPadValue,
|
||||
throwArgumentError
|
||||
} from "../utils/index.js";
|
||||
import { keccak256 as _keccak256 } from "../crypto/keccak.js";
|
||||
import { sha256 as _sha256 } from "../crypto/sha2.js";
|
||||
|
||||
|
||||
const regexBytes = new RegExp("^bytes([0-9]+)$");
|
||||
@ -13,16 +15,16 @@ const regexArray = new RegExp("^(.*)\\[([0-9]*)\\]$");
|
||||
function _pack(type: string, value: any, isArray?: boolean): Uint8Array {
|
||||
switch(type) {
|
||||
case "address":
|
||||
if (isArray) { return logger.getBytes(zeroPadValue(value, 32)); }
|
||||
return logger.getBytes(value);
|
||||
if (isArray) { return getBytes(zeroPadValue(value, 32)); }
|
||||
return getBytes(value);
|
||||
case "string":
|
||||
return toUtf8Bytes(value);
|
||||
case "bytes":
|
||||
return logger.getBytes(value);
|
||||
return getBytes(value);
|
||||
case "bool":
|
||||
value = (!!value ? "0x01": "0x00");
|
||||
if (isArray) { return logger.getBytes(zeroPadValue(value, 32)); }
|
||||
return logger.getBytes(value);
|
||||
if (isArray) { return getBytes(zeroPadValue(value, 32)); }
|
||||
return getBytes(value);
|
||||
}
|
||||
|
||||
let match = type.match(regexNumber);
|
||||
@ -30,14 +32,14 @@ function _pack(type: string, value: any, isArray?: boolean): Uint8Array {
|
||||
let size = parseInt(match[2] || "256")
|
||||
|
||||
if ((match[2] && String(size) !== match[2]) || (size % 8 !== 0) || size === 0 || size > 256) {
|
||||
return logger.throwArgumentError("invalid number type", "type", type)
|
||||
return throwArgumentError("invalid number type", "type", type)
|
||||
}
|
||||
|
||||
if (isArray) { size = 256; }
|
||||
|
||||
value = toTwos(value, size);
|
||||
|
||||
return logger.getBytes(zeroPadValue(toArray(value), size / 8));
|
||||
return getBytes(zeroPadValue(toArray(value), size / 8));
|
||||
}
|
||||
|
||||
match = type.match(regexBytes);
|
||||
@ -45,12 +47,12 @@ function _pack(type: string, value: any, isArray?: boolean): Uint8Array {
|
||||
const size = parseInt(match[1]);
|
||||
|
||||
if (String(size) !== match[1] || size === 0 || size > 32) {
|
||||
return logger.throwArgumentError("invalid bytes type", "type", type)
|
||||
return throwArgumentError("invalid bytes type", "type", type)
|
||||
}
|
||||
if (dataLength(value) !== size) {
|
||||
return logger.throwArgumentError(`invalid value for ${ type }`, "value", value)
|
||||
return throwArgumentError(`invalid value for ${ type }`, "value", value)
|
||||
}
|
||||
if (isArray) { return logger.getBytes(zeroPadBytes(value, 32)); }
|
||||
if (isArray) { return getBytes(zeroPadBytes(value, 32)); }
|
||||
return value;
|
||||
}
|
||||
|
||||
@ -59,23 +61,23 @@ function _pack(type: string, value: any, isArray?: boolean): Uint8Array {
|
||||
const baseType = match[1];
|
||||
const count = parseInt(match[2] || String(value.length));
|
||||
if (count != value.length) {
|
||||
logger.throwArgumentError(`invalid array length for ${ type }`, "value", value)
|
||||
throwArgumentError(`invalid array length for ${ type }`, "value", value)
|
||||
}
|
||||
const result: Array<Uint8Array> = [];
|
||||
value.forEach(function(value) {
|
||||
result.push(_pack(baseType, value, true));
|
||||
});
|
||||
return logger.getBytes(concat(result));
|
||||
return getBytes(concat(result));
|
||||
}
|
||||
|
||||
return logger.throwArgumentError("invalid type", "type", type)
|
||||
return throwArgumentError("invalid type", "type", type)
|
||||
}
|
||||
|
||||
// @TODO: Array Enum
|
||||
|
||||
export function solidityPacked(types: ReadonlyArray<string>, values: ReadonlyArray<any>) {
|
||||
export function solidityPacked(types: ReadonlyArray<string>, values: ReadonlyArray<any>): string {
|
||||
if (types.length != values.length) {
|
||||
logger.throwArgumentError("wrong number of values; expected ${ types.length }", "values", values)
|
||||
throwArgumentError("wrong number of values; expected ${ types.length }", "values", values)
|
||||
}
|
||||
const tight: Array<Uint8Array> = [];
|
||||
types.forEach(function(type, index) {
|
||||
@ -98,7 +100,7 @@ export function solidityPacked(types: ReadonlyArray<string>, values: ReadonlyArr
|
||||
*
|
||||
* @see https://docs.soliditylang.org/en/v0.8.14/abi-spec.html#non-standard-packed-mode
|
||||
*/
|
||||
export function solidityPackedKeccak256(types: ReadonlyArray<string>, values: ReadonlyArray<any>) {
|
||||
export function solidityPackedKeccak256(types: ReadonlyArray<string>, values: ReadonlyArray<any>): string {
|
||||
return _keccak256(solidityPacked(types, values));
|
||||
}
|
||||
|
||||
@ -110,6 +112,6 @@ export function solidityPackedKeccak256(types: ReadonlyArray<string>, values: Re
|
||||
export function test(foo: number | string): void {
|
||||
}
|
||||
|
||||
export function solidityPackedSha256(types: ReadonlyArray<string>, values: ReadonlyArray<any>) {
|
||||
export function solidityPackedSha256(types: ReadonlyArray<string>, values: ReadonlyArray<any>): string {
|
||||
return _sha256(solidityPacked(types, values));
|
||||
}
|
||||
|
@ -2,11 +2,11 @@
|
||||
import { getAddress } from "../address/index.js";
|
||||
import { keccak256 } from "../crypto/index.js";
|
||||
import {
|
||||
concat, defineProperties, hexlify, isHexString, mask, toHex, toTwos, zeroPadValue
|
||||
concat, defineProperties, getBigInt, getBytes, hexlify, isHexString, mask, toHex, toTwos, zeroPadValue,
|
||||
throwArgumentError
|
||||
} from "../utils/index.js";
|
||||
|
||||
import { id } from "./id.js";
|
||||
import { logger } from "../utils/logger.js";
|
||||
|
||||
import type { BigNumberish, BytesLike } from "../utils/index.js";
|
||||
|
||||
@ -32,8 +32,8 @@ export interface TypedDataField {
|
||||
type: string;
|
||||
};
|
||||
|
||||
function hexPadRight(value: BytesLike) {
|
||||
const bytes = logger.getBytes(value);
|
||||
function hexPadRight(value: BytesLike): string {
|
||||
const bytes = getBytes(value);
|
||||
const padOffset = bytes.length % 32
|
||||
if (padOffset) {
|
||||
return concat([ bytes, padding.slice(padOffset) ]);
|
||||
@ -59,7 +59,7 @@ const domainFieldNames: Array<string> = [
|
||||
function checkString(key: string): (value: any) => string {
|
||||
return function (value: any){
|
||||
if (typeof(value) !== "string") {
|
||||
logger.throwArgumentError(`invalid domain value for ${ JSON.stringify(key) }`, `domain.${ key }`, value);
|
||||
throwArgumentError(`invalid domain value for ${ JSON.stringify(key) }`, `domain.${ key }`, value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@ -69,18 +69,18 @@ const domainChecks: Record<string, (value: any) => any> = {
|
||||
name: checkString("name"),
|
||||
version: checkString("version"),
|
||||
chainId: function(value: any) {
|
||||
return logger.getBigInt(value, "domain.chainId");
|
||||
return getBigInt(value, "domain.chainId");
|
||||
},
|
||||
verifyingContract: function(value: any) {
|
||||
try {
|
||||
return getAddress(value).toLowerCase();
|
||||
} catch (error) { }
|
||||
return logger.throwArgumentError(`invalid domain value "verifyingContract"`, "domain.verifyingContract", value);
|
||||
return throwArgumentError(`invalid domain value "verifyingContract"`, "domain.verifyingContract", value);
|
||||
},
|
||||
salt: function(value: any) {
|
||||
const bytes = logger.getBytes(value, "domain.salt");
|
||||
const bytes = getBytes(value, "domain.salt");
|
||||
if (bytes.length !== 32) {
|
||||
logger.throwArgumentError(`invalid domain value "salt"`, "domain.salt", value);
|
||||
throwArgumentError(`invalid domain value "salt"`, "domain.salt", value);
|
||||
}
|
||||
return hexlify(bytes);
|
||||
}
|
||||
@ -95,17 +95,17 @@ function getBaseEncoder(type: string): null | ((value: any) => string) {
|
||||
|
||||
const width = parseInt(match[2] || "256");
|
||||
if (width % 8 !== 0 || width > 256 || (match[2] && match[2] !== String(width))) {
|
||||
logger.throwArgumentError("invalid numeric width", "type", type);
|
||||
throwArgumentError("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 = logger.getBigInt(_value, "value");
|
||||
const value = getBigInt(_value, "value");
|
||||
|
||||
if (value < boundsLower || value > boundsUpper) {
|
||||
logger.throwArgumentError(`value out-of-bounds for ${ type }`, "value", value);
|
||||
throwArgumentError(`value out-of-bounds for ${ type }`, "value", value);
|
||||
}
|
||||
|
||||
return toHex(toTwos(value, 256), 32);
|
||||
@ -119,13 +119,13 @@ function getBaseEncoder(type: string): null | ((value: any) => string) {
|
||||
if (match) {
|
||||
const width = parseInt(match[1]);
|
||||
if (width === 0 || width > 32 || match[1] !== String(width)) {
|
||||
logger.throwArgumentError("invalid bytes width", "type", type);
|
||||
throwArgumentError("invalid bytes width", "type", type);
|
||||
}
|
||||
|
||||
return function(value: BytesLike) {
|
||||
const bytes = logger.getBytes(value);
|
||||
const bytes = getBytes(value);
|
||||
if (bytes.length !== width) {
|
||||
logger.throwArgumentError(`invalid length for ${ type }`, "value", value);
|
||||
throwArgumentError(`invalid length for ${ type }`, "value", value);
|
||||
}
|
||||
return hexPadRight(value);
|
||||
};
|
||||
@ -193,14 +193,14 @@ export class TypedDataEncoder {
|
||||
|
||||
// Check each field has a unique name
|
||||
if (uniqueNames.has(field.name)) {
|
||||
logger.throwArgumentError(`duplicate variable name ${ JSON.stringify(field.name) } in ${ JSON.stringify(name) }`, "types", types);
|
||||
throwArgumentError(`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 = (<any>(field.type.match(/^([^\x5b]*)(\x5b|$)/)))[1] || null;
|
||||
if (baseType === name) {
|
||||
logger.throwArgumentError(`circular type reference to ${ JSON.stringify(baseType) }`, "types", types);
|
||||
throwArgumentError(`circular type reference to ${ JSON.stringify(baseType) }`, "types", types);
|
||||
}
|
||||
|
||||
// Is this a base encoding type?
|
||||
@ -208,7 +208,7 @@ export class TypedDataEncoder {
|
||||
if (encoder) { continue; }
|
||||
|
||||
if (!parents.has(baseType)) {
|
||||
logger.throwArgumentError(`unknown type ${ JSON.stringify(baseType) }`, "types", types);
|
||||
throwArgumentError(`unknown type ${ JSON.stringify(baseType) }`, "types", types);
|
||||
}
|
||||
|
||||
// Add linkage
|
||||
@ -221,9 +221,9 @@ export class TypedDataEncoder {
|
||||
const primaryTypes = Array.from(parents.keys()).filter((n) => ((parents.get(n) as Array<string>).length === 0));
|
||||
|
||||
if (primaryTypes.length === 0) {
|
||||
logger.throwArgumentError("missing primary type", "types", types);
|
||||
throwArgumentError("missing primary type", "types", types);
|
||||
} else if (primaryTypes.length > 1) {
|
||||
logger.throwArgumentError(`ambiguous primary types or unused types: ${ primaryTypes.map((t) => (JSON.stringify(t))).join(", ") }`, "types", types);
|
||||
throwArgumentError(`ambiguous primary types or unused types: ${ primaryTypes.map((t) => (JSON.stringify(t))).join(", ") }`, "types", types);
|
||||
}
|
||||
|
||||
defineProperties<TypedDataEncoder>(this, { primaryType: primaryTypes[0] });
|
||||
@ -231,7 +231,7 @@ export class TypedDataEncoder {
|
||||
// Check for circular type references
|
||||
function checkCircular(type: string, found: Set<string>) {
|
||||
if (found.has(type)) {
|
||||
logger.throwArgumentError(`circular type reference to ${ JSON.stringify(type) }`, "types", types);
|
||||
throwArgumentError(`circular type reference to ${ JSON.stringify(type) }`, "types", types);
|
||||
}
|
||||
|
||||
found.add(type);
|
||||
@ -285,7 +285,7 @@ export class TypedDataEncoder {
|
||||
const length = parseInt(match[3]);
|
||||
return (value: Array<any>) => {
|
||||
if (length >= 0 && value.length !== length) {
|
||||
logger.throwArgumentError("array length mismatch; expected length ${ arrayLength }", "value", value);
|
||||
throwArgumentError("array length mismatch; expected length ${ arrayLength }", "value", value);
|
||||
}
|
||||
|
||||
let result = value.map(subEncoder);
|
||||
@ -312,13 +312,13 @@ export class TypedDataEncoder {
|
||||
}
|
||||
}
|
||||
|
||||
return logger.throwArgumentError(`unknown type: ${ type }`, "type", type);
|
||||
return throwArgumentError(`unknown type: ${ type }`, "type", type);
|
||||
}
|
||||
|
||||
encodeType(name: string): string {
|
||||
const result = this.#fullTypes.get(name);
|
||||
if (!result) {
|
||||
return logger.throwArgumentError(`unknown type: ${ JSON.stringify(name) }`, "name", name);
|
||||
return throwArgumentError(`unknown type: ${ JSON.stringify(name) }`, "name", name);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -352,7 +352,7 @@ export class TypedDataEncoder {
|
||||
const subtype = match[1];
|
||||
const length = parseInt(match[3]);
|
||||
if (length >= 0 && value.length !== length) {
|
||||
logger.throwArgumentError("array length mismatch; expected length ${ arrayLength }", "value", value);
|
||||
throwArgumentError("array length mismatch; expected length ${ arrayLength }", "value", value);
|
||||
}
|
||||
return value.map((v: any) => this._visit(subtype, v, callback));
|
||||
}
|
||||
@ -366,7 +366,7 @@ export class TypedDataEncoder {
|
||||
}, <Record<string, any>>{});
|
||||
}
|
||||
|
||||
return logger.throwArgumentError(`unknown type: ${ type }`, "type", type);
|
||||
return throwArgumentError(`unknown type: ${ type }`, "type", type);
|
||||
}
|
||||
|
||||
visit(value: Record<string, any>, callback: (type: string, data: any) => any): any {
|
||||
@ -390,7 +390,7 @@ export class TypedDataEncoder {
|
||||
for (const name in domain) {
|
||||
const type = domainFieldTypes[name];
|
||||
if (!type) {
|
||||
logger.throwArgumentError(`invalid typed-data domain key: ${ JSON.stringify(name) }`, "domain", domain);
|
||||
throwArgumentError(`invalid typed-data domain key: ${ JSON.stringify(name) }`, "domain", domain);
|
||||
}
|
||||
domainFields.push({ name, type });
|
||||
}
|
||||
@ -476,7 +476,7 @@ export class TypedDataEncoder {
|
||||
|
||||
const typesWithDomain = Object.assign({ }, types);
|
||||
if (typesWithDomain.EIP712Domain) {
|
||||
logger.throwArgumentError("types must not contain EIP712Domain type", "types.EIP712Domain", types);
|
||||
throwArgumentError("types must not contain EIP712Domain type", "types.EIP712Domain", types);
|
||||
} else {
|
||||
typesWithDomain.EIP712Domain = domainTypes;
|
||||
}
|
||||
@ -492,12 +492,12 @@ export class TypedDataEncoder {
|
||||
|
||||
// bytes
|
||||
if (type.match(/^bytes(\d*)/)) {
|
||||
return hexlify(logger.getBytes(value));
|
||||
return hexlify(getBytes(value));
|
||||
}
|
||||
|
||||
// uint or int
|
||||
if (type.match(/^u?int/)) {
|
||||
return logger.getBigInt(value).toString();
|
||||
return getBigInt(value).toString();
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
@ -507,12 +507,12 @@ export class TypedDataEncoder {
|
||||
return !!value;
|
||||
case "string":
|
||||
if (typeof(value) !== "string") {
|
||||
logger.throwArgumentError(`invalid string`, "value", value);
|
||||
throwArgumentError(`invalid string`, "value", value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
return logger.throwArgumentError("unsupported type", "type", type);
|
||||
return throwArgumentError("unsupported type", "type", type);
|
||||
})
|
||||
};
|
||||
}
|
||||
|
@ -7,14 +7,15 @@
|
||||
// of Signer/ENS name to address so we can sync respond to listenerCount.
|
||||
|
||||
import { resolveAddress } from "../address/index.js";
|
||||
import { concat, dataLength, dataSlice, hexlify, isHexString } from "../utils/data.js";
|
||||
import { isCallException } from "../utils/errors.js";
|
||||
import { FetchRequest } from "../utils/fetch.js";
|
||||
import { toArray, toQuantity } from "../utils/maths.js";
|
||||
import { defineProperties, EventPayload, resolveProperties } from "../utils/index.js";
|
||||
import { toUtf8String } from "../utils/index.js";;
|
||||
|
||||
import { logger } from "../utils/logger.js";
|
||||
import {
|
||||
concat, dataLength, dataSlice, hexlify, isHexString,
|
||||
getBigInt, getBytes, getNumber,
|
||||
isCallException, makeError, throwError, throwArgumentError,
|
||||
FetchRequest,
|
||||
toArray, toQuantity,
|
||||
defineProperties, EventPayload, resolveProperties,
|
||||
toUtf8String
|
||||
} from "../utils/index.js";
|
||||
|
||||
import { EnsResolver } from "./ens-resolver.js";
|
||||
import { Network } from "./network.js";
|
||||
@ -193,7 +194,7 @@ async function getSubscription(_event: ProviderEvent, provider: AbstractProvider
|
||||
return { filter, tag: getTag("event", filter), type: "event" };
|
||||
}
|
||||
|
||||
return logger.throwArgumentError("unknown ProviderEvent", "event", _event);
|
||||
return throwArgumentError("unknown ProviderEvent", "event", _event);
|
||||
}
|
||||
|
||||
function getTime(): number { return (new Date()).getTime(); }
|
||||
@ -428,7 +429,7 @@ export class AbstractProvider implements Provider {
|
||||
|
||||
// 4xx indicates the result is not present; stop
|
||||
if (resp.statusCode >= 400 && resp.statusCode < 500) {
|
||||
return logger.throwError(`response not found during CCIP fetch: ${ errorMessage }`, "OFFCHAIN_FAULT", {
|
||||
return throwError(`response not found during CCIP fetch: ${ errorMessage }`, "OFFCHAIN_FAULT", {
|
||||
reason: "404_MISSING_RESOURCE",
|
||||
transaction: tx, info: { url, errorMessage }
|
||||
});
|
||||
@ -438,7 +439,7 @@ export class AbstractProvider implements Provider {
|
||||
errorMessages.push(errorMessage);
|
||||
}
|
||||
|
||||
return logger.throwError(`error encountered during CCIP fetch: ${ errorMessages.map((m) => JSON.stringify(m)).join(", ") }`, "OFFCHAIN_FAULT", {
|
||||
return throwError(`error encountered during CCIP fetch: ${ errorMessages.map((m) => JSON.stringify(m)).join(", ") }`, "OFFCHAIN_FAULT", {
|
||||
reason: "500_SERVER_ERROR",
|
||||
transaction: tx, info: { urls, errorMessages }
|
||||
});
|
||||
@ -449,7 +450,7 @@ export class AbstractProvider implements Provider {
|
||||
}
|
||||
|
||||
_detectNetwork(): Promise<Frozen<Network>> {
|
||||
return logger.throwError("sub-classes must implement this", "UNSUPPORTED_OPERATION", {
|
||||
return throwError("sub-classes must implement this", "UNSUPPORTED_OPERATION", {
|
||||
operation: "_detectNetwork"
|
||||
});
|
||||
}
|
||||
@ -457,7 +458,7 @@ export class AbstractProvider implements Provider {
|
||||
// Sub-classes should override this and handle PerformActionRequest requests, calling
|
||||
// the super for any unhandled actions.
|
||||
async _perform<T = any>(req: PerformActionRequest): Promise<T> {
|
||||
return logger.throwError(`unsupported method: ${ req.method }`, "UNSUPPORTED_OPERATION", {
|
||||
return throwError(`unsupported method: ${ req.method }`, "UNSUPPORTED_OPERATION", {
|
||||
operation: req.method,
|
||||
info: req
|
||||
});
|
||||
@ -465,7 +466,7 @@ export class AbstractProvider implements Provider {
|
||||
|
||||
// State
|
||||
async getBlockNumber(): Promise<number> {
|
||||
return logger.getNumber(await this.#perform({ method: "getBlockNumber" }), "%response");
|
||||
return getNumber(await this.#perform({ method: "getBlockNumber" }), "%response");
|
||||
}
|
||||
|
||||
// @TODO: Make this string | Promsie<string> so no await needed if sync is possible
|
||||
@ -502,7 +503,7 @@ export class AbstractProvider implements Provider {
|
||||
return this.getBlockNumber().then((b) => toQuantity(b + blockTag));
|
||||
}
|
||||
|
||||
return logger.throwArgumentError("invalid blockTag", "blockTag", blockTag);
|
||||
return throwArgumentError("invalid blockTag", "blockTag", blockTag);
|
||||
}
|
||||
|
||||
async getNetwork(): Promise<Frozen<Network>> {
|
||||
@ -544,7 +545,7 @@ export class AbstractProvider implements Provider {
|
||||
}
|
||||
} else {
|
||||
// Otherwise, we do not allow changes to the underlying network
|
||||
logger.throwError(`network changed: ${ expected.chainId } => ${ actual.chainId } `, "NETWORK_ERROR", {
|
||||
throwError(`network changed: ${ expected.chainId } => ${ actual.chainId } `, "NETWORK_ERROR", {
|
||||
event: "changed"
|
||||
});
|
||||
}
|
||||
@ -559,7 +560,7 @@ export class AbstractProvider implements Provider {
|
||||
gasPrice: ((async () => {
|
||||
try {
|
||||
const gasPrice = await this.#perform({ method: "getGasPrice" });
|
||||
return logger.getBigInt(gasPrice, "%response");
|
||||
return getBigInt(gasPrice, "%response");
|
||||
} catch (error) { }
|
||||
return null
|
||||
})())
|
||||
@ -598,14 +599,14 @@ export class AbstractProvider implements Provider {
|
||||
|
||||
async estimateGas(_tx: TransactionRequest) {
|
||||
const transaction = await this._getTransaction(_tx);
|
||||
return logger.getBigInt(await this.#perform({
|
||||
return getBigInt(await this.#perform({
|
||||
method: "estimateGas", transaction
|
||||
}), "%response");
|
||||
}
|
||||
|
||||
async #call(tx: PerformActionTransaction, blockTag: string, attempt: number): Promise<string> {
|
||||
if (attempt >= MAX_CCIP_REDIRECTS) {
|
||||
logger.throwError("CCIP read exceeded maximum redirections", "OFFCHAIN_FAULT", {
|
||||
throwError("CCIP read exceeded maximum redirections", "OFFCHAIN_FAULT", {
|
||||
reason: "TOO_MANY_REDIRECTS",
|
||||
transaction: Object.assign({ }, tx, { blockTag, enableCcipRead: true })
|
||||
});
|
||||
@ -628,7 +629,7 @@ export class AbstractProvider implements Provider {
|
||||
try {
|
||||
ccipArgs = parseOffchainLookup(dataSlice(error.data, 4));
|
||||
} catch (error: any) {
|
||||
return logger.throwError(error.message, "OFFCHAIN_FAULT", {
|
||||
return throwError(error.message, "OFFCHAIN_FAULT", {
|
||||
reason: "BAD_DATA",
|
||||
transaction, info: { data }
|
||||
});
|
||||
@ -636,7 +637,7 @@ export class AbstractProvider implements Provider {
|
||||
|
||||
// Check the sender of the OffchainLookup matches the transaction
|
||||
if (ccipArgs.sender.toLowerCase() !== txSender.toLowerCase()) {
|
||||
return logger.throwError("CCIP Read sender mismatch", "CALL_EXCEPTION", {
|
||||
return throwError("CCIP Read sender mismatch", "CALL_EXCEPTION", {
|
||||
data, transaction,
|
||||
errorSignature: "OffchainLookup(address,string[],bytes,bytes4,bytes)",
|
||||
errorName: "OffchainLookup",
|
||||
@ -646,7 +647,7 @@ export class AbstractProvider implements Provider {
|
||||
|
||||
const ccipResult = await this.ccipReadFetch(transaction, ccipArgs.calldata, ccipArgs.urls);
|
||||
if (ccipResult == null) {
|
||||
return logger.throwError("CCIP Read failed to fetch data", "OFFCHAIN_FAULT", {
|
||||
return throwError("CCIP Read failed to fetch data", "OFFCHAIN_FAULT", {
|
||||
reason: "FETCH_FAILED",
|
||||
transaction, info: { data: error.data, errorArgs: ccipArgs.errorArgs }
|
||||
});
|
||||
@ -684,11 +685,11 @@ export class AbstractProvider implements Provider {
|
||||
}
|
||||
|
||||
async getBalance(address: AddressLike, blockTag?: BlockTag) {
|
||||
return logger.getBigInt(await this.#getAccountValue({ method: "getBalance" }, address, blockTag), "%response");
|
||||
return getBigInt(await this.#getAccountValue({ method: "getBalance" }, address, blockTag), "%response");
|
||||
}
|
||||
|
||||
async getTransactionCount(address: AddressLike, blockTag?: BlockTag) {
|
||||
return logger.getNumber(await this.#getAccountValue({ method: "getTransactionCount" }, address, blockTag), "%response");
|
||||
return getNumber(await this.#getAccountValue({ method: "getTransactionCount" }, address, blockTag), "%response");
|
||||
}
|
||||
|
||||
async getCode(address: AddressLike, blockTag?: BlockTag) {
|
||||
@ -696,7 +697,7 @@ export class AbstractProvider implements Provider {
|
||||
}
|
||||
|
||||
async getStorageAt(address: AddressLike, _position: BigNumberish, blockTag?: BlockTag) {
|
||||
const position = logger.getBigInt(_position, "position");
|
||||
const position = getBigInt(_position, "position");
|
||||
return hexlify(await this.#getAccountValue({ method: "getStorageAt", position }, address, blockTag));
|
||||
}
|
||||
|
||||
@ -852,7 +853,7 @@ export class AbstractProvider implements Provider {
|
||||
|
||||
// ENS
|
||||
_getProvider(chainId: number): AbstractProvider {
|
||||
return logger.throwError("provider cannot connect to target network", "UNSUPPORTED_OPERATION", {
|
||||
return throwError("provider cannot connect to target network", "UNSUPPORTED_OPERATION", {
|
||||
operation: "_getProvider()"
|
||||
});
|
||||
}
|
||||
@ -919,7 +920,7 @@ export class AbstractProvider implements Provider {
|
||||
if (timer == null) { return; }
|
||||
timer = null;
|
||||
this.off("block", listener);
|
||||
reject(logger.makeError("timeout", "TIMEOUT", { reason: "timeout" }));
|
||||
reject(makeError("timeout", "TIMEOUT", { reason: "timeout" }));
|
||||
}, timeout);
|
||||
}
|
||||
|
||||
@ -1153,7 +1154,7 @@ export class AbstractProvider implements Provider {
|
||||
pause(dropWhilePaused?: boolean): void {
|
||||
if (this.#pausedState != null) {
|
||||
if (this.#pausedState == !!dropWhilePaused) { return; }
|
||||
return logger.throwError("cannot change pause type; resume first", "UNSUPPORTED_OPERATION", {
|
||||
return throwError("cannot change pause type; resume first", "UNSUPPORTED_OPERATION", {
|
||||
operation: "pause"
|
||||
});
|
||||
}
|
||||
@ -1201,8 +1202,8 @@ function _parseString(result: string, start: number): null | string {
|
||||
function _parseBytes(result: string, start: number): null | string {
|
||||
if (result === "0x") { return null; }
|
||||
try {
|
||||
const offset = logger.getNumber(dataSlice(result, start, start + 32));
|
||||
const length = logger.getNumber(dataSlice(result, offset, offset + 32));
|
||||
const offset = getNumber(dataSlice(result, start, start + 32));
|
||||
const length = getNumber(dataSlice(result, offset, offset + 32));
|
||||
|
||||
return dataSlice(result, offset + 32, offset + 32 + length);
|
||||
} catch (error) { }
|
||||
@ -1241,7 +1242,7 @@ function encodeBytes(datas: Array<BytesLike>) {
|
||||
}
|
||||
|
||||
for (let i = 0; i < datas.length; i++) {
|
||||
const data = logger.getBytes(datas[i]);
|
||||
const data = getBytes(datas[i]);
|
||||
|
||||
// Update the bytes offset
|
||||
result[i] = numPad(byteCount);
|
||||
@ -1274,8 +1275,8 @@ function parseOffchainLookup(data: string): CcipArgs {
|
||||
// Read the URLs from the response
|
||||
try {
|
||||
const urls: Array<string> = [];
|
||||
const urlsOffset = logger.getNumber(dataSlice(data, 32, 64));
|
||||
const urlsLength = logger.getNumber(dataSlice(data, urlsOffset, urlsOffset + 32));
|
||||
const urlsOffset = getNumber(dataSlice(data, 32, 64));
|
||||
const urlsLength = getNumber(dataSlice(data, urlsOffset, urlsOffset + 32));
|
||||
const urlsData = dataSlice(data, urlsOffset + 32);
|
||||
for (let u = 0; u < urlsLength; u++) {
|
||||
const url = _parseString(urlsData, u * 32);
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { logger } from "../utils/logger.js";
|
||||
import { Transaction } from "../transaction/index.js";
|
||||
import { defineProperties, resolveProperties } from "../utils/index.js";
|
||||
import {
|
||||
defineProperties, resolveProperties,
|
||||
throwArgumentError, throwError
|
||||
} from "../utils/index.js";
|
||||
|
||||
import type { TypedDataDomain, TypedDataField } from "../hash/index.js";
|
||||
import type { TransactionLike } from "../transaction/index.js";
|
||||
@ -23,7 +25,7 @@ export abstract class AbstractSigner<P extends null | Provider = null | Provider
|
||||
|
||||
#checkProvider(operation: string): Provider {
|
||||
if (this.provider) { return this.provider; }
|
||||
return logger.throwError("missing provider", "UNSUPPORTED_OPERATION", { operation });
|
||||
return throwError("missing provider", "UNSUPPORTED_OPERATION", { operation });
|
||||
}
|
||||
|
||||
async getNonce(blockTag?: BlockTag): Promise<number> {
|
||||
@ -39,7 +41,7 @@ export abstract class AbstractSigner<P extends null | Provider = null | Provider
|
||||
if (pop.to != null) {
|
||||
pop.to = provider.resolveName(pop.to).then((to) => {
|
||||
if (to == null) {
|
||||
return logger.throwArgumentError("transaction to ENS name not configured", "tx.to", pop.to);
|
||||
return throwArgumentError("transaction to ENS name not configured", "tx.to", pop.to);
|
||||
}
|
||||
return to;
|
||||
});
|
||||
@ -52,7 +54,7 @@ export abstract class AbstractSigner<P extends null | Provider = null | Provider
|
||||
this.resolveName(from)
|
||||
]).then(([ address, from ]) => {
|
||||
if (!from || address.toLowerCase() !== from.toLowerCase()) {
|
||||
return logger.throwArgumentError("transaction from mismatch", "tx.from", from);
|
||||
return throwArgumentError("transaction from mismatch", "tx.from", from);
|
||||
}
|
||||
return address;
|
||||
});
|
||||
@ -123,7 +125,7 @@ export class VoidSigner extends AbstractSigner {
|
||||
}
|
||||
|
||||
#throwUnsupported(suffix: string, operation: string): never {
|
||||
return logger.throwError(`VoidSigner cannot sign ${ suffix }`, "UNSUPPORTED_OPERATION", {
|
||||
return throwError(`VoidSigner cannot sign ${ suffix }`, "UNSUPPORTED_OPERATION", {
|
||||
operation
|
||||
});
|
||||
}
|
||||
|
@ -1,11 +1,12 @@
|
||||
import { ZeroHash } from "../constants/hashes.js";
|
||||
import { dnsEncode, namehash } from "../hash/index.js";
|
||||
import {
|
||||
defineProperties, encodeBase58, toArray, toNumber, toUtf8Bytes, toUtf8String
|
||||
concat, dataSlice, getBytes, hexlify, zeroPadValue,
|
||||
defineProperties, encodeBase58, getBigInt, toArray,
|
||||
toNumber, toUtf8Bytes, toUtf8String,
|
||||
throwArgumentError, throwError,
|
||||
FetchRequest
|
||||
} from "../utils/index.js";
|
||||
import { concat, dataSlice, hexlify, zeroPadValue } from "../utils/data.js";
|
||||
import { FetchRequest } from "../utils/fetch.js";
|
||||
import { logger } from "../utils/logger.js";
|
||||
|
||||
import type { BigNumberish, BytesLike, EthersError } from "../utils/index.js";
|
||||
|
||||
@ -64,7 +65,7 @@ function encodeBytes(datas: Array<BytesLike>) {
|
||||
}
|
||||
|
||||
for (let i = 0; i < datas.length; i++) {
|
||||
const data = logger.getBytes(datas[i]);
|
||||
const data = getBytes(datas[i]);
|
||||
|
||||
// Update the bytes offset
|
||||
result[i] = numPad(byteCount);
|
||||
@ -86,7 +87,7 @@ function getIpfsLink(link: string): string {
|
||||
} else if (link.match(/^ipfs:\/\//i)) {
|
||||
link = link.substring(7);
|
||||
} else {
|
||||
logger.throwArgumentError("unsupported IPFS format", "link", link);
|
||||
throwArgumentError("unsupported IPFS format", "link", link);
|
||||
}
|
||||
|
||||
return `https:/\/gateway.ipfs.io/ipfs/${ link }`;
|
||||
@ -170,7 +171,7 @@ export class EnsResolver {
|
||||
to: this.address,
|
||||
data: "0x01ffc9a79061b92300000000000000000000000000000000000000000000000000000000"
|
||||
}).then((result) => {
|
||||
return (logger.getBigInt(result) === BN_1);
|
||||
return (getBigInt(result) === BN_1);
|
||||
}).catch((error) => {
|
||||
if (error.code === "CALL_EXCEPTION") { return false; }
|
||||
// Rethrow the error: link is down, etc. Let future attempts retry.
|
||||
@ -203,8 +204,8 @@ export class EnsResolver {
|
||||
|
||||
try {
|
||||
let data = await this.provider.call(tx);
|
||||
if ((logger.getBytes(data).length % 32) === 4) {
|
||||
return logger.throwError("resolver threw error", "CALL_EXCEPTION", {
|
||||
if ((getBytes(data).length % 32) === 4) {
|
||||
return throwError("resolver threw error", "CALL_EXCEPTION", {
|
||||
transaction: tx, data
|
||||
});
|
||||
}
|
||||
@ -256,7 +257,7 @@ export class EnsResolver {
|
||||
|
||||
if (address != null) { return address; }
|
||||
|
||||
return logger.throwError(`invalid coin data`, "UNSUPPORTED_OPERATION", {
|
||||
return throwError(`invalid coin data`, "UNSUPPORTED_OPERATION", {
|
||||
operation: `getAddress(${ coinType })`,
|
||||
info: { coinType, data }
|
||||
});
|
||||
@ -268,7 +269,7 @@ export class EnsResolver {
|
||||
|
||||
// The nodehash consumes the first slot, so the string pointer targets
|
||||
// offset 64, with the length at offset 64 and data starting at offset 96
|
||||
const calldata = logger.getBytes(concat([ numPad(64), numPad(keyBytes.length), keyBytes ]));
|
||||
const calldata = getBytes(concat([ numPad(64), numPad(keyBytes.length), keyBytes ]));
|
||||
|
||||
const hexBytes = parseBytes((await this._fetch("0x59d1d43c", bytesPad(calldata))) || "0x", 0);
|
||||
if (hexBytes == null || hexBytes === "0x") { return null; }
|
||||
@ -299,7 +300,7 @@ export class EnsResolver {
|
||||
return `bzz:/\/${ swarm[1] }`;
|
||||
}
|
||||
|
||||
return logger.throwError(`invalid or unsupported content hash data`, "UNSUPPORTED_OPERATION", {
|
||||
return throwError(`invalid or unsupported content hash data`, "UNSUPPORTED_OPERATION", {
|
||||
operation: "getContentHash()",
|
||||
info: { data: hexBytes }
|
||||
});
|
||||
@ -377,7 +378,7 @@ export class EnsResolver {
|
||||
|
||||
} else if (scheme === "erc1155") {
|
||||
// balanceOf(address owner, uint256 tokenId)
|
||||
const balance = logger.getBigInt(await this.provider.call({
|
||||
const balance = getBigInt(await this.provider.call({
|
||||
to: addr, data: concat([ "0x00fdd58e", zeroPadValue(owner, 32), tokenId ])
|
||||
}));
|
||||
if (!balance) {
|
||||
@ -479,7 +480,7 @@ export class EnsResolver {
|
||||
|
||||
// No ENS...
|
||||
if (!ensPlugin) {
|
||||
return logger.throwError("network does not support ENS", "UNSUPPORTED_OPERATION", {
|
||||
return throwError("network does not support ENS", "UNSUPPORTED_OPERATION", {
|
||||
operation: "getResolver", info: { network: network.name }
|
||||
});
|
||||
}
|
||||
|
@ -16,9 +16,10 @@
|
||||
*/
|
||||
|
||||
import { getAddress, getCreateAddress } from "../address/index.js";
|
||||
import { dataLength, dataSlice, isHexString } from "../utils/data.js";
|
||||
import { toQuantity } from "../utils/maths.js";
|
||||
import { logger } from "../utils/logger.js";
|
||||
import {
|
||||
dataLength, dataSlice, getBigInt, getNumber, isHexString, toQuantity,
|
||||
throwArgumentError, throwError
|
||||
} from "../utils/index.js";
|
||||
import { Signature } from "../crypto/signature.js";
|
||||
import { accessListify } from "../transaction/index.js";
|
||||
|
||||
@ -168,7 +169,7 @@ export class Formatter {
|
||||
// An address from a call result; may be zero-padded
|
||||
callAddress(value: any): string {
|
||||
if (dataLength(value) !== 32 || dataSlice(value, 0, 12) !== "0x000000000000000000000000") {
|
||||
logger.throwArgumentError("invalid call address", "value", value);
|
||||
throwArgumentError("invalid call address", "value", value);
|
||||
}
|
||||
return this.address(dataSlice(value, 12));
|
||||
}
|
||||
@ -177,7 +178,7 @@ export class Formatter {
|
||||
contractAddress(value: any): string {
|
||||
return getCreateAddress({
|
||||
from: this.address(value.from),
|
||||
nonce: logger.getNumber(value.nonce, "value.nonce")
|
||||
nonce: getNumber(value.nonce, "value.nonce")
|
||||
});
|
||||
}
|
||||
|
||||
@ -196,7 +197,7 @@ export class Formatter {
|
||||
return toQuantity(value);
|
||||
}
|
||||
|
||||
return logger.throwArgumentError("invalid blockTag", "value", value);
|
||||
return throwArgumentError("invalid blockTag", "value", value);
|
||||
}
|
||||
|
||||
// Block objects
|
||||
@ -279,20 +280,20 @@ export class Formatter {
|
||||
if (value === 0 || value === 1) {
|
||||
// Make sure if both are specified, they match
|
||||
if (receipt.status != null && receipt.status !== value) {
|
||||
return logger.throwError("alt-root-status/status mismatch", "BAD_DATA", {
|
||||
return throwError("alt-root-status/status mismatch", "BAD_DATA", {
|
||||
value: { root: receipt.root, status: receipt.status }
|
||||
});
|
||||
}
|
||||
receipt.status = value;
|
||||
delete receipt.root;
|
||||
} else {
|
||||
return logger.throwError("invalid alt-root-status", "BAD_DATA", {
|
||||
return throwError("invalid alt-root-status", "BAD_DATA", {
|
||||
value: receipt.root
|
||||
});
|
||||
}
|
||||
} else if (!isHexString(receipt.root, 32)) {
|
||||
// Must be a valid bytes32
|
||||
return logger.throwError("invalid receipt root hash", "BAD_DATA", {
|
||||
return throwError("invalid receipt root hash", "BAD_DATA", {
|
||||
value: receipt.root
|
||||
});
|
||||
}
|
||||
@ -356,13 +357,13 @@ export class Formatter {
|
||||
|
||||
// Requires a value which is a value BigNumber
|
||||
bigNumber(value: any): bigint {
|
||||
return logger.getBigInt(value, "value");
|
||||
return getBigInt(value, "value");
|
||||
}
|
||||
|
||||
uint256(value: any): bigint {
|
||||
const result = this.bigNumber(value);
|
||||
if (result < 0 || result > BN_MAX_UINT256) {
|
||||
logger.throwArgumentError("invalid uint256", "value", value);
|
||||
throwArgumentError("invalid uint256", "value", value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -375,7 +376,7 @@ export class Formatter {
|
||||
case false: case "false":
|
||||
return false;
|
||||
}
|
||||
return logger.throwArgumentError(`invalid boolean; ${ JSON.stringify(value) }`, "value", value);
|
||||
return throwArgumentError(`invalid boolean; ${ JSON.stringify(value) }`, "value", value);
|
||||
}
|
||||
|
||||
// Requires a value which is a valid hexstring. If dataOrLength is true,
|
||||
@ -393,7 +394,7 @@ export class Formatter {
|
||||
|
||||
data(value: string): string {
|
||||
if (dataLength(value) == null) {
|
||||
logger.throwArgumentError("", "value", value);
|
||||
throwArgumentError("", "value", value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@ -401,14 +402,14 @@ export class Formatter {
|
||||
// Requires a network-native hash
|
||||
hash(value: any): string {
|
||||
if (dataLength(value) !== 32) {
|
||||
logger.throwArgumentError("", "value", value);
|
||||
throwArgumentError("", "value", value);
|
||||
}
|
||||
return this.#format.data(value);
|
||||
}
|
||||
|
||||
// Requires a valid number, within the IEEE 754 safe range
|
||||
number(value: any): number {
|
||||
return logger.getNumber(value);
|
||||
return getNumber(value);
|
||||
}
|
||||
|
||||
// Requires an object which matches a fleet of other formatters
|
||||
@ -433,7 +434,7 @@ export class Formatter {
|
||||
if (nv !== undefined) { result[key] = nv; }
|
||||
} catch (error) {
|
||||
const message = (error instanceof Error) ? error.message: "not-an-error";
|
||||
logger.throwError(`invalid value for value.${ key } (${ message })`, "BAD_DATA", { value })
|
||||
throwError(`invalid value for value.${ key } (${ message })`, "BAD_DATA", { value })
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { logger } from "../utils/logger.js";
|
||||
import { getStore, setStore } from "../utils/storage.js";
|
||||
import {
|
||||
getStore, getBigInt, setStore, throwArgumentError
|
||||
} from "../utils/index.js";
|
||||
|
||||
import { Formatter } from "./formatter.js";
|
||||
import { EnsPlugin, GasCostPlugin } from "./plugins-network.js";
|
||||
@ -96,7 +97,7 @@ export class Network implements Freezable<Network> {
|
||||
};
|
||||
|
||||
constructor(name: string, _chainId: BigNumberish, formatter?: Formatter) {
|
||||
const chainId = logger.getBigInt(_chainId);
|
||||
const chainId = getBigInt(_chainId);
|
||||
if (formatter == null) { formatter = defaultFormatter; }
|
||||
const plugins = new Map();
|
||||
this.#props = { name, chainId, formatter, plugins };
|
||||
@ -110,7 +111,7 @@ export class Network implements Freezable<Network> {
|
||||
set name(value: string) { setStore(this.#props, "name", value); }
|
||||
|
||||
get chainId(): bigint { return getStore(this.#props, "chainId"); }
|
||||
set chainId(value: BigNumberish) { setStore(this.#props, "chainId", logger.getBigInt(value, "chainId")); }
|
||||
set chainId(value: BigNumberish) { setStore(this.#props, "chainId", getBigInt(value, "chainId")); }
|
||||
|
||||
get formatter(): Formatter { return getStore(this.#props, "formatter"); }
|
||||
set formatter(value: Formatter) { setStore(this.#props, "formatter", value); }
|
||||
@ -192,7 +193,7 @@ export class Network implements Freezable<Network> {
|
||||
return new Network("unknown", network);
|
||||
}
|
||||
|
||||
logger.throwArgumentError("unknown network", "network", network);
|
||||
throwArgumentError("unknown network", "network", network);
|
||||
}
|
||||
|
||||
// Clonable with network-like abilities
|
||||
@ -206,7 +207,7 @@ export class Network implements Freezable<Network> {
|
||||
// Networkish
|
||||
if (typeof(network) === "object") {
|
||||
if (typeof(network.name) !== "string" || typeof(network.chainId) !== "number") {
|
||||
logger.throwArgumentError("invalid network object name or chainId", "network", network);
|
||||
throwArgumentError("invalid network object name or chainId", "network", network);
|
||||
}
|
||||
|
||||
const custom = new Network(<string>(network.name), <number>(network.chainId));
|
||||
@ -222,14 +223,14 @@ export class Network implements Freezable<Network> {
|
||||
return custom;
|
||||
}
|
||||
|
||||
return logger.throwArgumentError("invalid network", "network", network);
|
||||
return throwArgumentError("invalid network", "network", network);
|
||||
}
|
||||
|
||||
static register(nameOrChainId: string | number | bigint, networkFunc: () => Network): void {
|
||||
if (typeof(nameOrChainId) === "number") { nameOrChainId = BigInt(nameOrChainId); }
|
||||
const existing = Networks.get(nameOrChainId);
|
||||
if (existing) {
|
||||
logger.throwArgumentError(`conflicting network for ${ JSON.stringify(existing.name) }`, "nameOrChainId", nameOrChainId);
|
||||
throwArgumentError(`conflicting network for ${ JSON.stringify(existing.name) }`, "nameOrChainId", nameOrChainId);
|
||||
}
|
||||
Networks.set(nameOrChainId, networkFunc);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { defineProperties } from "../utils/properties.js";
|
||||
|
||||
import { logger } from "../utils/logger.js";
|
||||
import { throwArgumentError } from "../utils/index.js";
|
||||
|
||||
//import { BigNumberish } from "../math/index.js";
|
||||
|
||||
@ -56,7 +56,7 @@ export class GasCostPlugin extends NetworkPlugin {
|
||||
let value = (costs || { })[name];
|
||||
if (value == null) { value = nullish; }
|
||||
if (typeof(value) !== "number") {
|
||||
logger.throwArgumentError(`invalud value for ${ name }`, "costs", costs);
|
||||
throwArgumentError(`invalud value for ${ name }`, "costs", costs);
|
||||
}
|
||||
props[name] = value;
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
|
||||
import { defineProperties } from "../utils/properties.js";
|
||||
import { FetchRequest } from "../utils/fetch.js";
|
||||
import {
|
||||
defineProperties, FetchRequest, throwArgumentError, throwError
|
||||
} from "../utils/index.js";
|
||||
|
||||
import { showThrottleMessage } from "./community.js";
|
||||
import { logger } from "../utils/logger.js";
|
||||
import { Network } from "./network.js";
|
||||
import { JsonRpcProvider } from "./provider-jsonrpc.js";
|
||||
|
||||
@ -40,7 +40,7 @@ function getHost(name: string): string {
|
||||
return "opt-kovan.g.alchemy.com";
|
||||
}
|
||||
|
||||
return logger.throwArgumentError("unsupported network", "network", name);
|
||||
return throwArgumentError("unsupported network", "network", name);
|
||||
}
|
||||
|
||||
export class AlchemyProvider extends JsonRpcProvider implements CommunityResourcable {
|
||||
@ -79,14 +79,14 @@ export class AlchemyProvider extends JsonRpcProvider implements CommunityResourc
|
||||
|
||||
if (data) {
|
||||
if (error) {
|
||||
logger.throwError("an error occurred during transaction executions", "CALL_EXCEPTION", {
|
||||
throwError("an error occurred during transaction executions", "CALL_EXCEPTION", {
|
||||
data
|
||||
});
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
return logger.throwError("could not parse trace result", "BAD_DATA", { value: trace });
|
||||
return throwError("could not parse trace result", "BAD_DATA", { value: trace });
|
||||
}
|
||||
|
||||
return await super._perform(req);
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { defineProperties } from "../utils/properties.js";
|
||||
import { FetchRequest } from "../utils/fetch.js";
|
||||
import {
|
||||
defineProperties, FetchRequest, throwArgumentError
|
||||
} from "../utils/index.js";
|
||||
|
||||
import { AbstractProvider } from "./abstract-provider.js";
|
||||
import { showThrottleMessage } from "./community.js";
|
||||
import { logger } from "../utils/logger.js";
|
||||
import { Network } from "./network.js";
|
||||
import { JsonRpcProvider } from "./provider-jsonrpc.js";
|
||||
|
||||
@ -28,7 +28,7 @@ function getHost(name: string): string {
|
||||
case "arbitrum":
|
||||
return "rpc.ankr.com/arbitrum";
|
||||
}
|
||||
return logger.throwArgumentError("unsupported network", "network", name);
|
||||
return throwArgumentError("unsupported network", "network", name);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { throwArgumentError } from "../utils/index.js";
|
||||
|
||||
import { logger } from "../utils/logger.js";
|
||||
import { Network } from "./network.js";
|
||||
import { JsonRpcProvider } from "./provider-jsonrpc.js";
|
||||
|
||||
@ -10,7 +10,7 @@ export class CloudflareProvider extends JsonRpcProvider {
|
||||
constructor(_network: Networkish = "homestead") {
|
||||
const network = Network.from(_network);
|
||||
if (network.name !== "homestead") {
|
||||
return logger.throwArgumentError("unsupported network", "network", _network);
|
||||
return throwArgumentError("unsupported network", "network", _network);
|
||||
}
|
||||
super("https:/\/cloudflare-eth.com/", network, { staticNetwork: network });
|
||||
}
|
||||
|
@ -1,11 +1,10 @@
|
||||
import { hexlify, isHexString } from "../utils/data.js";
|
||||
import { toQuantity } from "../utils/maths.js";
|
||||
import { isError } from "../utils/errors.js";
|
||||
import { defineProperties } from "../utils/properties.js";
|
||||
import { toUtf8String } from "../utils/utf8.js";
|
||||
import { FetchRequest } from "../utils/fetch.js";
|
||||
|
||||
if (false) { console.log(isHexString, isError); } // @TODO
|
||||
import {
|
||||
defineProperties,
|
||||
hexlify, toQuantity,
|
||||
FetchRequest,
|
||||
throwArgumentError, throwError,
|
||||
toUtf8String
|
||||
} from "../utils/index.js";
|
||||
|
||||
import { AbstractProvider } from "./abstract-provider.js";
|
||||
import { Network } from "./network.js";
|
||||
@ -17,8 +16,6 @@ import type { Networkish } from "./network.js";
|
||||
//import type { } from "./pagination";
|
||||
import type { TransactionRequest } from "./provider.js";
|
||||
|
||||
import { logger } from "../utils/logger.js";
|
||||
|
||||
|
||||
const defaultApiKey = "9D13ZE7XSBTJ94N9BNJ2MA33VMAY2YPIRB";
|
||||
|
||||
@ -82,7 +79,7 @@ export class EtherscanProvider extends AbstractProvider {
|
||||
default:
|
||||
}
|
||||
|
||||
return logger.throwArgumentError("unsupported network", "network", this.network);
|
||||
return throwArgumentError("unsupported network", "network", this.network);
|
||||
}
|
||||
|
||||
getUrl(module: string, params: Record<string, string>): string {
|
||||
@ -358,7 +355,7 @@ export class EtherscanProvider extends AbstractProvider {
|
||||
});
|
||||
}
|
||||
|
||||
return logger.throwError("getBlock by blockHash not supported by Etherscan", "UNSUPPORTED_OPERATION", {
|
||||
return throwError("getBlock by blockHash not supported by Etherscan", "UNSUPPORTED_OPERATION", {
|
||||
operation: "getBlock(blockHash)"
|
||||
});
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
|
||||
import { hexlify } from "../utils/data.js";
|
||||
import {
|
||||
getBigInt, getNumber, hexlify, throwError, throwArgumentError
|
||||
} from "../utils/index.js";
|
||||
|
||||
import { AbstractProvider } from "./abstract-provider.js";
|
||||
import { logger } from "../utils/logger.js";
|
||||
import { Network } from "./network.js"
|
||||
|
||||
import type { Frozen } from "../utils/index.js";
|
||||
@ -23,7 +24,7 @@ function shuffle<T = any>(array: Array<T>): void {
|
||||
}
|
||||
}
|
||||
|
||||
function stall(duration: number) {
|
||||
function stall(duration: number): Promise<void> {
|
||||
return new Promise((resolve) => { setTimeout(resolve, duration); });
|
||||
}
|
||||
|
||||
@ -134,15 +135,15 @@ type RunningState = {
|
||||
function normalize(network: Frozen<Network>, value: any, req: PerformActionRequest): string {
|
||||
switch (req.method) {
|
||||
case "chainId":
|
||||
return logger.getBigInt(value).toString();
|
||||
return getBigInt(value).toString();
|
||||
case "getBlockNumber":
|
||||
return logger.getNumber(value).toString();
|
||||
return getNumber(value).toString();
|
||||
case "getGasPrice":
|
||||
return logger.getBigInt(value).toString();
|
||||
return getBigInt(value).toString();
|
||||
case "getBalance":
|
||||
return logger.getBigInt(value).toString();
|
||||
return getBigInt(value).toString();
|
||||
case "getTransactionCount":
|
||||
return logger.getNumber(value).toString();
|
||||
return getNumber(value).toString();
|
||||
case "getCode":
|
||||
return hexlify(value);
|
||||
case "getStorageAt":
|
||||
@ -159,12 +160,12 @@ function normalize(network: Frozen<Network>, value: any, req: PerformActionReque
|
||||
case "call":
|
||||
return hexlify(value);
|
||||
case "estimateGas":
|
||||
return logger.getBigInt(value).toString();
|
||||
return getBigInt(value).toString();
|
||||
case "getLogs":
|
||||
return JSON.stringify(value.map((v: any) => network.formatter.log(v)));
|
||||
}
|
||||
|
||||
return logger.throwError("unsupported method", "UNSUPPORTED_OPERATION", {
|
||||
return throwError("unsupported method", "UNSUPPORTED_OPERATION", {
|
||||
operation: `_perform(${ JSON.stringify(req.method) })`
|
||||
});
|
||||
}
|
||||
@ -220,7 +221,7 @@ function getMedian(results: Array<TallyResult>): bigint {
|
||||
}
|
||||
|
||||
function getFuzzyMode(quorum: number, results: Array<TallyResult>): undefined | number {
|
||||
if (quorum === 1) { return logger.getNumber(getMedian(results), "%internal"); }
|
||||
if (quorum === 1) { return getNumber(getMedian(results), "%internal"); }
|
||||
|
||||
const tally: Map<number, { result: number, weight: number }> = new Map();
|
||||
const add = (result: number, weight: number) => {
|
||||
@ -230,7 +231,7 @@ function getFuzzyMode(quorum: number, results: Array<TallyResult>): undefined |
|
||||
};
|
||||
|
||||
for (const { weight, result } of results) {
|
||||
const r = logger.getNumber(result);
|
||||
const r = getNumber(result);
|
||||
add(r - 1, weight);
|
||||
add(r, weight);
|
||||
add(r + 1, weight);
|
||||
@ -282,7 +283,7 @@ export class FallbackProvider extends AbstractProvider {
|
||||
this.eventWorkers = 1;
|
||||
|
||||
if (this.quorum > this.#configs.reduce((a, c) => (a + c.weight), 0)) {
|
||||
logger.throwArgumentError("quorum exceed provider wieght", "quorum", this.quorum);
|
||||
throwArgumentError("quorum exceed provider wieght", "quorum", this.quorum);
|
||||
}
|
||||
}
|
||||
|
||||
@ -291,8 +292,8 @@ export class FallbackProvider extends AbstractProvider {
|
||||
return this.#configs.slice();
|
||||
}
|
||||
|
||||
async _detectNetwork() {
|
||||
return Network.from(logger.getBigInt(await this._perform({ method: "chainId" }))).freeze();
|
||||
async _detectNetwork(): Promise<Frozen<Network>> {
|
||||
return Network.from(getBigInt(await this._perform({ method: "chainId" }))).freeze();
|
||||
}
|
||||
|
||||
// @TODO: Add support to select providers to be the event subscriber
|
||||
@ -382,7 +383,7 @@ export class FallbackProvider extends AbstractProvider {
|
||||
if (chainId == null) {
|
||||
chainId = network.chainId;
|
||||
} else if (network.chainId !== chainId) {
|
||||
logger.throwError("cannot mix providers on different networks", "UNSUPPORTED_OPERATION", {
|
||||
throwError("cannot mix providers on different networks", "UNSUPPORTED_OPERATION", {
|
||||
operation: "new FallbackProvider"
|
||||
});
|
||||
}
|
||||
@ -417,9 +418,9 @@ export class FallbackProvider extends AbstractProvider {
|
||||
case "getBlockNumber": {
|
||||
// We need to get the bootstrap block height
|
||||
if (this.#height === -2) {
|
||||
const height = Math.ceil(logger.getNumber(getMedian(this.#configs.map((c) => ({
|
||||
const height = Math.ceil(getNumber(getMedian(this.#configs.map((c) => ({
|
||||
result: c.blockNumber,
|
||||
normal: logger.getNumber(c.blockNumber).toString(),
|
||||
normal: getNumber(c.blockNumber).toString(),
|
||||
weight: c.weight
|
||||
}))), "%internal"));
|
||||
this.#height = height;
|
||||
@ -461,7 +462,7 @@ export class FallbackProvider extends AbstractProvider {
|
||||
throw new Error("TODO");
|
||||
}
|
||||
|
||||
return logger.throwError("unsupported method", "UNSUPPORTED_OPERATION", {
|
||||
return throwError("unsupported method", "UNSUPPORTED_OPERATION", {
|
||||
operation: `_perform(${ JSON.stringify((<any>req).method) })`
|
||||
});
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { defineProperties } from "../utils/properties.js";
|
||||
import { FetchRequest } from "../utils/fetch.js";
|
||||
import {
|
||||
defineProperties, FetchRequest, throwArgumentError
|
||||
} from "../utils/index.js";
|
||||
|
||||
import { showThrottleMessage } from "./community.js";
|
||||
import { logger } from "../utils/logger.js";
|
||||
import { Network } from "./network.js";
|
||||
import { JsonRpcProvider } from "./provider-jsonrpc.js";
|
||||
|
||||
@ -39,7 +39,7 @@ function getHost(name: string): string {
|
||||
return "arbitrum-rinkeby.infura.io";
|
||||
}
|
||||
|
||||
return logger.throwArgumentError("unsupported network", "network", name);
|
||||
return throwArgumentError("unsupported network", "network", name);
|
||||
}
|
||||
|
||||
|
||||
|
@ -4,13 +4,13 @@
|
||||
// https://playground.open-rpc.org/?schemaUrl=https://raw.githubusercontent.com/ethereum/eth1.0-apis/assembled-spec/openrpc.json&uiSchema%5BappBar%5D%5Bui:splitView%5D=true&uiSchema%5BappBar%5D%5Bui:input%5D=false&uiSchema%5BappBar%5D%5Bui:examplesDropdown%5D=false
|
||||
|
||||
import { resolveAddress } from "../address/index.js";
|
||||
import { hexlify } from "../utils/data.js";
|
||||
import { FetchRequest } from "../utils/fetch.js";
|
||||
import { toQuantity } from "../utils/maths.js";
|
||||
import { defineProperties } from "../utils/properties.js";
|
||||
import { TypedDataEncoder } from "../hash/typed-data.js";
|
||||
import { toUtf8Bytes } from "../utils/utf8.js";
|
||||
import { accessListify } from "../transaction/index.js";
|
||||
import {
|
||||
defineProperties, getBigInt, hexlify, toQuantity, toUtf8Bytes,
|
||||
throwArgumentError, throwError,
|
||||
FetchRequest
|
||||
} from "../utils/index.js";
|
||||
|
||||
import { AbstractProvider, UnmanagedSubscriber } from "./abstract-provider.js";
|
||||
import { AbstractSigner } from "./abstract-signer.js";
|
||||
@ -25,8 +25,6 @@ import type { Networkish } from "./network.js";
|
||||
import type { Provider, TransactionRequest, TransactionResponse } from "./provider.js";
|
||||
import type { Signer } from "./signer.js";
|
||||
|
||||
import { logger } from "../utils/logger.js";
|
||||
|
||||
|
||||
//function copy<T = any>(value: T): T {
|
||||
// return JSON.parse(JSON.stringify(value));
|
||||
@ -149,7 +147,7 @@ export class JsonRpcSigner extends AbstractSigner<JsonRpcApiProvider> {
|
||||
}
|
||||
|
||||
connect(provider: null | Provider): Signer {
|
||||
return logger.throwError("cannot reconnect JsonRpcSigner", "UNSUPPORTED_OPERATION", {
|
||||
return throwError("cannot reconnect JsonRpcSigner", "UNSUPPORTED_OPERATION", {
|
||||
operation: "signer.connect"
|
||||
});
|
||||
}
|
||||
@ -196,7 +194,7 @@ export class JsonRpcSigner extends AbstractSigner<JsonRpcApiProvider> {
|
||||
promises.push((async () => {
|
||||
const from = await resolveAddress(_from, this.provider);
|
||||
if (from == null || from.toLowerCase() !== this.address.toLowerCase()) {
|
||||
logger.throwArgumentError("from address mismatch", "transaction", _tx);
|
||||
throwArgumentError("from address mismatch", "transaction", _tx);
|
||||
}
|
||||
tx.from = from;
|
||||
})());
|
||||
@ -263,7 +261,7 @@ export class JsonRpcSigner extends AbstractSigner<JsonRpcApiProvider> {
|
||||
if (tx.from) {
|
||||
const from = await resolveAddress(tx.from, this.provider);
|
||||
if (from == null || from.toLowerCase() !== this.address.toLowerCase()) {
|
||||
return logger.throwArgumentError("from address mismatch", "transaction", _tx);
|
||||
return throwArgumentError("from address mismatch", "transaction", _tx);
|
||||
}
|
||||
tx.from = from;
|
||||
} else {
|
||||
@ -288,7 +286,7 @@ export class JsonRpcSigner extends AbstractSigner<JsonRpcApiProvider> {
|
||||
const populated = await TypedDataEncoder.resolveNames(domain, types, value, async (value: string) => {
|
||||
const address = await resolveAddress(value);
|
||||
if (address == null) {
|
||||
return logger.throwArgumentError("TypedData does not support null address", "value", value);
|
||||
return throwArgumentError("TypedData does not support null address", "value", value);
|
||||
}
|
||||
return address;
|
||||
});
|
||||
@ -337,7 +335,7 @@ export class JsonRpcApiProvider extends AbstractProvider {
|
||||
// This could be relaxed in the future to just check equivalent networks
|
||||
const staticNetwork = this._getOption("staticNetwork");
|
||||
if (staticNetwork && staticNetwork !== network) {
|
||||
logger.throwArgumentError("staticNetwork MUST match network object", "options", options);
|
||||
throwArgumentError("staticNetwork MUST match network object", "options", options);
|
||||
}
|
||||
}
|
||||
|
||||
@ -445,7 +443,7 @@ export class JsonRpcApiProvider extends AbstractProvider {
|
||||
|
||||
// Sub-classes MUST override this
|
||||
_send(payload: JsonRpcPayload | Array<JsonRpcPayload>): Promise<Array<JsonRpcResult | JsonRpcError>> {
|
||||
return logger.throwError("sub-classes must override _send", "UNSUPPORTED_OPERATION", {
|
||||
return throwError("sub-classes must override _send", "UNSUPPORTED_OPERATION", {
|
||||
operation: "jsonRpcApiProvider._send"
|
||||
});
|
||||
}
|
||||
@ -481,7 +479,7 @@ export class JsonRpcApiProvider extends AbstractProvider {
|
||||
const network = this._getOption("staticNetwork");
|
||||
if (network) { return network; }
|
||||
|
||||
return Network.from(logger.getBigInt(await this._perform({ method: "chainId" })));
|
||||
return Network.from(getBigInt(await this._perform({ method: "chainId" })));
|
||||
}
|
||||
|
||||
_getSubscriber(sub: Subscription): Subscriber {
|
||||
@ -510,7 +508,7 @@ export class JsonRpcApiProvider extends AbstractProvider {
|
||||
if ((<any>tx)[key] == null) { return; }
|
||||
let dstKey = key;
|
||||
if (key === "gasLimit") { dstKey = "gas"; }
|
||||
(<any>result)[dstKey] = toQuantity(logger.getBigInt((<any>tx)[key], `tx.${ key }`));
|
||||
(<any>result)[dstKey] = toQuantity(getBigInt((<any>tx)[key], `tx.${ key }`));
|
||||
});
|
||||
|
||||
// Make sure addresses and data are lowercase
|
||||
@ -693,7 +691,7 @@ export class JsonRpcApiProvider extends AbstractProvider {
|
||||
// is fair), so we delete type if it is 0 and a non-EIP-1559 network
|
||||
if (req.method === "call" || req.method === "estimateGas") {
|
||||
let tx = req.transaction;
|
||||
if (tx && tx.type != null && logger.getBigInt(tx.type)) {
|
||||
if (tx && tx.type != null && getBigInt(tx.type)) {
|
||||
// If there are no EIP-1559 properties, it might be non-EIP-a559
|
||||
if (tx.maxFeePerGas == null && tx.maxPriorityFeePerGas == null) {
|
||||
const feeData = await this.getFeeData();
|
||||
|
@ -10,7 +10,7 @@
|
||||
*/
|
||||
|
||||
import { UnmanagedSubscriber } from "./abstract-provider.js";
|
||||
import { assertArgument, logger } from "../utils/logger.js";
|
||||
import { assertArgument, makeError, throwError } from "../utils/index.js";
|
||||
import { JsonRpcApiProvider } from "./provider-jsonrpc.js";
|
||||
|
||||
import type { Subscriber, Subscription } from "./abstract-provider.js";
|
||||
@ -65,7 +65,7 @@ export class SocketSubscriber implements Subscriber {
|
||||
// and resume
|
||||
pause(dropWhilePaused?: boolean): void {
|
||||
if (!dropWhilePaused) {
|
||||
logger.throwError("preserve logs while paused not supported by SocketSubscriber yet", "UNSUPPORTED_OPERATION", {
|
||||
throwError("preserve logs while paused not supported by SocketSubscriber yet", "UNSUPPORTED_OPERATION", {
|
||||
operation: "pause(false)"
|
||||
});
|
||||
}
|
||||
@ -228,7 +228,7 @@ export class SocketProvider extends JsonRpcApiProvider {
|
||||
|
||||
if ("error" in result) {
|
||||
const { message, code, data } = result.error;
|
||||
const error = logger.makeError(message || "unkonwn error", "SERVER_ERROR", {
|
||||
const error = makeError(message || "unkonwn error", "SERVER_ERROR", {
|
||||
request: `ws:${ JSON.stringify(callback.payload) }`,
|
||||
info: { code, data }
|
||||
});
|
||||
|
@ -1,10 +1,9 @@
|
||||
//import { resolveAddress } from "@ethersproject/address";
|
||||
import { hexlify } from "../utils/data.js";
|
||||
import { logger } from "../utils/logger.js";
|
||||
import { defineProperties } from "../utils/properties.js";
|
||||
import {
|
||||
defineProperties, getBigInt, getNumber, hexlify, throwError
|
||||
} from "../utils/index.js";
|
||||
import { accessListify } from "../transaction/index.js";
|
||||
|
||||
|
||||
import type { AddressLike, NameResolver } from "../address/index.js";
|
||||
import type { BigNumberish, EventEmitterable, Frozen, Listener } from "../utils/index.js";
|
||||
import type { Signature } from "../crypto/index.js";
|
||||
@ -127,13 +126,13 @@ export function copyRequest(req: CallRequest): PreparedRequest {
|
||||
const bigIntKeys = "chainId,gasLimit,gasPrice,maxFeePerGas, maxPriorityFeePerGas,value".split(/,/);
|
||||
for (const key in bigIntKeys) {
|
||||
if (!(key in req) || (<any>req)[key] == null) { continue; }
|
||||
result[key] = logger.getBigInt((<any>req)[key], `request.${ key }`);
|
||||
result[key] = getBigInt((<any>req)[key], `request.${ key }`);
|
||||
}
|
||||
|
||||
const numberKeys = "type,nonce".split(/,/);
|
||||
for (const key in numberKeys) {
|
||||
if (!(key in req) || (<any>req)[key] == null) { continue; }
|
||||
result[key] = logger.getNumber((<any>req)[key], `request.${ key }`);
|
||||
result[key] = getNumber((<any>req)[key], `request.${ key }`);
|
||||
}
|
||||
|
||||
if (req.accessList) {
|
||||
@ -585,7 +584,7 @@ export class TransactionReceipt implements TransactionReceiptParams, Iterable<Lo
|
||||
|
||||
reorderedEvent(other?: TransactionResponse): OrphanFilter {
|
||||
if (other && !other.isMined()) {
|
||||
return logger.throwError("unmined 'other' transction cannot be orphaned", "UNSUPPORTED_OPERATION", {
|
||||
return throwError("unmined 'other' transction cannot be orphaned", "UNSUPPORTED_OPERATION", {
|
||||
operation: "reorderedEvent(other)" });
|
||||
}
|
||||
return createReorderedTransactionFilter(this, other);
|
||||
@ -775,7 +774,7 @@ export class TransactionResponse implements TransactionLike<string>, Transaction
|
||||
|
||||
removedEvent(): OrphanFilter {
|
||||
if (!this.isMined()) {
|
||||
return logger.throwError("unmined transaction canot be orphaned", "UNSUPPORTED_OPERATION", {
|
||||
return throwError("unmined transaction canot be orphaned", "UNSUPPORTED_OPERATION", {
|
||||
operation: "removeEvent()" });
|
||||
}
|
||||
return createRemovedTransactionFilter(this);
|
||||
@ -783,11 +782,11 @@ export class TransactionResponse implements TransactionLike<string>, Transaction
|
||||
|
||||
reorderedEvent(other?: TransactionResponse): OrphanFilter {
|
||||
if (!this.isMined()) {
|
||||
return logger.throwError("unmined transaction canot be orphaned", "UNSUPPORTED_OPERATION", {
|
||||
return throwError("unmined transaction canot be orphaned", "UNSUPPORTED_OPERATION", {
|
||||
operation: "removeEvent()" });
|
||||
}
|
||||
if (other && !other.isMined()) {
|
||||
return logger.throwError("unmined 'other' transaction canot be orphaned", "UNSUPPORTED_OPERATION", {
|
||||
return throwError("unmined 'other' transaction canot be orphaned", "UNSUPPORTED_OPERATION", {
|
||||
operation: "removeEvent()" });
|
||||
}
|
||||
return createReorderedTransactionFilter(this, other);
|
||||
@ -1006,7 +1005,7 @@ export interface Provider extends ContractRunner, EventEmitterable<ProviderEvent
|
||||
waitForBlock(blockTag?: BlockTag): Promise<Block<string>>;
|
||||
}
|
||||
|
||||
|
||||
// @TODO: I think I can drop T
|
||||
function fail<T>(): T {
|
||||
throw new Error("this provider should not be used");
|
||||
}
|
||||
@ -1014,64 +1013,64 @@ function fail<T>(): T {
|
||||
class DummyProvider implements Provider {
|
||||
get provider(): this { return this; }
|
||||
|
||||
async getNetwork() { return fail<Frozen<Network>>(); }
|
||||
async getFeeData() { return fail<FeeData>(); }
|
||||
async getNetwork(): Promise<Frozen<Network>> { return fail<Frozen<Network>>(); }
|
||||
async getFeeData(): Promise<FeeData> { return fail<FeeData>(); }
|
||||
|
||||
async estimateGas(tx: TransactionRequest) { return fail<bigint>(); }
|
||||
async call(tx: CallRequest) { return fail<string>(); }
|
||||
async estimateGas(tx: TransactionRequest): Promise<bigint> { return fail<bigint>(); }
|
||||
async call(tx: CallRequest): Promise<string> { return fail<string>(); }
|
||||
|
||||
async resolveName(name: string) { return fail<null | string>(); }
|
||||
async resolveName(name: string): Promise<null | string> { return fail<null | string>(); }
|
||||
|
||||
// State
|
||||
async getBlockNumber() { return fail<number>(); }
|
||||
async getBlockNumber(): Promise<number> { return fail<number>(); }
|
||||
|
||||
// Account
|
||||
async getBalance(address: AddressLike, blockTag?: BlockTag) {
|
||||
async getBalance(address: AddressLike, blockTag?: BlockTag): Promise<bigint> {
|
||||
return fail<bigint>();
|
||||
}
|
||||
async getTransactionCount(address: AddressLike, blockTag?: BlockTag) {
|
||||
async getTransactionCount(address: AddressLike, blockTag?: BlockTag): Promise<number> {
|
||||
return fail<number>();
|
||||
}
|
||||
|
||||
async getCode(address: AddressLike, blockTag?: BlockTag) {
|
||||
async getCode(address: AddressLike, blockTag?: BlockTag): Promise<string> {
|
||||
return fail<string>();
|
||||
}
|
||||
async getStorageAt(address: AddressLike, position: BigNumberish, blockTag?: BlockTag) {
|
||||
async getStorageAt(address: AddressLike, position: BigNumberish, blockTag?: BlockTag): Promise<string> {
|
||||
return fail<string>();
|
||||
}
|
||||
|
||||
// Write
|
||||
async broadcastTransaction(signedTx: string) { return fail<TransactionResponse>(); }
|
||||
async broadcastTransaction(signedTx: string): Promise<TransactionResponse> { return fail<TransactionResponse>(); }
|
||||
|
||||
// Queries
|
||||
async getBlock(blockHashOrBlockTag: BlockTag | string){
|
||||
async getBlock(blockHashOrBlockTag: BlockTag | string): Promise<null | Block<string>>{
|
||||
return fail<null | Block<string>>();
|
||||
}
|
||||
async getBlockWithTransactions(blockHashOrBlockTag: BlockTag | string) {
|
||||
async getBlockWithTransactions(blockHashOrBlockTag: BlockTag | string): Promise<null | Block<TransactionResponse>> {
|
||||
return fail<null | Block<TransactionResponse>>();
|
||||
}
|
||||
async getTransaction(hash: string) {
|
||||
async getTransaction(hash: string): Promise<null | TransactionResponse> {
|
||||
return fail<null | TransactionResponse>();
|
||||
}
|
||||
async getTransactionReceipt(hash: string) {
|
||||
async getTransactionReceipt(hash: string): Promise<null | TransactionReceipt> {
|
||||
return fail<null | TransactionReceipt>();
|
||||
}
|
||||
|
||||
// Bloom-filter Queries
|
||||
async getLogs(filter: Filter | FilterByBlockHash) {
|
||||
async getLogs(filter: Filter | FilterByBlockHash): Promise<Array<Log>> {
|
||||
return fail<Array<Log>>();
|
||||
}
|
||||
|
||||
// ENS
|
||||
async lookupAddress(address: string) {
|
||||
async lookupAddress(address: string): Promise<null | string> {
|
||||
return fail<null | string>();
|
||||
}
|
||||
|
||||
async waitForTransaction(hash: string, confirms?: number, timeout?: number) {
|
||||
async waitForTransaction(hash: string, confirms?: number, timeout?: number): Promise<null | TransactionReceipt> {
|
||||
return fail<null | TransactionReceipt>();
|
||||
}
|
||||
|
||||
async waitForBlock(blockTag?: BlockTag) {
|
||||
async waitForBlock(blockTag?: BlockTag): Promise<Block<string>> {
|
||||
return fail<Block<string>>();
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
|
||||
import { getNumber } from "../utils/index.js";
|
||||
|
||||
import type { Subscriber } from "./abstract-provider.js";
|
||||
import { logger } from "../utils/logger.js";
|
||||
|
||||
|
||||
//#TODO: Temp
|
||||
@ -25,7 +26,7 @@ export class BlockConnectionSubscriber implements Subscriber {
|
||||
|
||||
start(): void {
|
||||
this.#filterId = this.#provider._subscribe([ "newHeads" ], (result: any) => {
|
||||
const blockNumber = logger.getNumber(result.number);
|
||||
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);
|
||||
|
@ -2,7 +2,7 @@ import { isHexString } from "../utils/data.js";
|
||||
|
||||
import type { AbstractProvider, Subscriber } from "./abstract-provider.js";
|
||||
import type { EventFilter, OrphanFilter, ProviderEvent } from "./provider.js";
|
||||
import { logger } from "../utils/logger.js";
|
||||
import { throwError } from "../utils/index.js";
|
||||
|
||||
function copy(obj: any): any {
|
||||
return JSON.parse(JSON.stringify(obj));
|
||||
@ -12,7 +12,7 @@ export function getPollingSubscriber(provider: AbstractProvider, event: Provider
|
||||
if (event === "block") { return new PollingBlockSubscriber(provider); }
|
||||
if (isHexString(event, 32)) { return new PollingTransactionSubscriber(provider, event); }
|
||||
|
||||
return logger.throwError("unsupported polling event", "UNSUPPORTED_OPERATION", {
|
||||
return throwError("unsupported polling event", "UNSUPPORTED_OPERATION", {
|
||||
operation: "getPollingSubscriber", info: { event }
|
||||
});
|
||||
}
|
||||
|
@ -2,7 +2,8 @@
|
||||
import { getAddress } from "../address/index.js";
|
||||
import { keccak256, Signature } from "../crypto/index.js";
|
||||
import {
|
||||
concat, decodeRlp, encodeRlp, getStore, hexlify, logger, setStore, toArray, zeroPadValue
|
||||
concat, decodeRlp, encodeRlp, getBytes, getStore, getBigInt, getNumber, hexlify,
|
||||
setStore, throwArgumentError, toArray, zeroPadValue
|
||||
} from "../utils/index.js";
|
||||
|
||||
import { accessListify } from "./accesslist.js";
|
||||
@ -55,7 +56,7 @@ function handleData(value: string, param: string): string {
|
||||
try {
|
||||
return hexlify(value);
|
||||
} catch (error) {
|
||||
return logger.throwArgumentError("invalid data", param, value);
|
||||
return throwArgumentError("invalid data", param, value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,27 +64,27 @@ function handleAccessList(value: any, param: string): AccessList {
|
||||
try {
|
||||
return accessListify(value);
|
||||
} catch (error) {
|
||||
return logger.throwArgumentError("invalid accessList", param, value);
|
||||
return throwArgumentError("invalid accessList", param, value);
|
||||
}
|
||||
}
|
||||
|
||||
function handleNumber(_value: string, param: string): number {
|
||||
if (_value === "0x") { return 0; }
|
||||
return logger.getNumber(_value, param);
|
||||
return getNumber(_value, param);
|
||||
}
|
||||
|
||||
function handleUint(_value: string, param: string): bigint {
|
||||
if (_value === "0x") { return BN_0; }
|
||||
const value = logger.getBigInt(_value, param);
|
||||
if (value > BN_MAX_UINT) { logger.throwArgumentError("value exceeds uint size", param, value); }
|
||||
const value = getBigInt(_value, param);
|
||||
if (value > BN_MAX_UINT) { throwArgumentError("value exceeds uint size", param, value); }
|
||||
return value;
|
||||
}
|
||||
|
||||
function formatNumber(_value: BigNumberish, name: string): Uint8Array {
|
||||
const value = logger.getBigInt(_value, "value");
|
||||
const value = getBigInt(_value, "value");
|
||||
const result = toArray(value);
|
||||
if (result.length > 32) {
|
||||
logger.throwArgumentError(`value too large`, `tx.${ name }`, value);
|
||||
throwArgumentError(`value too large`, `tx.${ name }`, value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -96,7 +97,7 @@ function _parseLegacy(data: Uint8Array): TransactionLike {
|
||||
const fields: any = decodeRlp(data);
|
||||
|
||||
if (!Array.isArray(fields) || (fields.length !== 9 && fields.length !== 6)) {
|
||||
return logger.throwArgumentError("invalid field count for legacy transaction", "data", data);
|
||||
return throwArgumentError("invalid field count for legacy transaction", "data", data);
|
||||
}
|
||||
|
||||
const tx: TransactionLike = {
|
||||
@ -130,7 +131,7 @@ function _parseLegacy(data: Uint8Array): TransactionLike {
|
||||
|
||||
// Signed Legacy Transaction
|
||||
if (chainId === BN_0 && (v < BN_27 || v > BN_28)) {
|
||||
logger.throwArgumentError("non-canonical legacy v", "v", fields[6]);
|
||||
throwArgumentError("non-canonical legacy v", "v", fields[6]);
|
||||
}
|
||||
|
||||
tx.signature = Signature.from({
|
||||
@ -158,12 +159,12 @@ function _serializeLegacy(tx: Transaction, sig?: Signature): string {
|
||||
let chainId = BN_0;
|
||||
if (tx.chainId != null) {
|
||||
// A chainId was provided; if non-zero we'll use EIP-155
|
||||
chainId = logger.getBigInt(tx.chainId, "tx.chainId");
|
||||
chainId = getBigInt(tx.chainId, "tx.chainId");
|
||||
|
||||
// We have a chainId in the tx and an EIP-155 v in the signature,
|
||||
// make sure they agree with each other
|
||||
if (sig && sig.networkV != null && sig.legacyChainId !== chainId) {
|
||||
logger.throwArgumentError("tx.chainId/sig.v mismatch", "sig", sig);
|
||||
throwArgumentError("tx.chainId/sig.v mismatch", "sig", sig);
|
||||
}
|
||||
|
||||
} else if (sig) {
|
||||
@ -189,7 +190,7 @@ function _serializeLegacy(tx: Transaction, sig?: Signature): string {
|
||||
if (chainId !== BN_0) {
|
||||
v = Signature.getChainIdV(chainId, sig.v);
|
||||
} else if (BigInt(sig.v) !== v) {
|
||||
logger.throwArgumentError("tx.chainId/sig.v mismatch", "sig", sig);
|
||||
throwArgumentError("tx.chainId/sig.v mismatch", "sig", sig);
|
||||
}
|
||||
|
||||
fields.push(toArray(v));
|
||||
@ -205,7 +206,7 @@ function _parseEipSignature(tx: TransactionLike, fields: Array<string>, serializ
|
||||
yParity = handleNumber(fields[0], "yParity");
|
||||
if (yParity !== 0 && yParity !== 1) { throw new Error("bad yParity"); }
|
||||
} catch (error) {
|
||||
return logger.throwArgumentError("invalid yParity", "yParity", fields[0]);
|
||||
return throwArgumentError("invalid yParity", "yParity", fields[0]);
|
||||
}
|
||||
|
||||
const r = zeroPadValue(fields[1], 32);
|
||||
@ -216,10 +217,10 @@ function _parseEipSignature(tx: TransactionLike, fields: Array<string>, serializ
|
||||
}
|
||||
|
||||
function _parseEip1559(data: Uint8Array): TransactionLike {
|
||||
const fields: any = decodeRlp(logger.getBytes(data).slice(1));
|
||||
const fields: any = decodeRlp(getBytes(data).slice(1));
|
||||
|
||||
if (!Array.isArray(fields) || (fields.length !== 9 && fields.length !== 12)) {
|
||||
logger.throwArgumentError("invalid field count for transaction type: 2", "data", hexlify(data));
|
||||
throwArgumentError("invalid field count for transaction type: 2", "data", hexlify(data));
|
||||
}
|
||||
|
||||
const maxPriorityFeePerGas = handleUint(fields[2], "maxPriorityFeePerGas");
|
||||
@ -271,10 +272,10 @@ function _serializeEip1559(tx: TransactionLike, sig?: Signature): string {
|
||||
}
|
||||
|
||||
function _parseEip2930(data: Uint8Array): TransactionLike {
|
||||
const fields: any = decodeRlp(logger.getBytes(data).slice(1));
|
||||
const fields: any = decodeRlp(getBytes(data).slice(1));
|
||||
|
||||
if (!Array.isArray(fields) || (fields.length !== 8 && fields.length !== 11)) {
|
||||
logger.throwArgumentError("invalid field count for transaction type: 1", "data", hexlify(data));
|
||||
throwArgumentError("invalid field count for transaction type: 1", "data", hexlify(data));
|
||||
}
|
||||
|
||||
const tx: TransactionLike = {
|
||||
@ -397,10 +398,10 @@ export class Transaction implements Freezable<Transaction>, TransactionLike<stri
|
||||
}
|
||||
|
||||
get nonce(): number { return getStore(this.#props, "nonce"); }
|
||||
set nonce(value: BigNumberish) { setStore(this.#props, "nonce", logger.getNumber(value, "value")); }
|
||||
set nonce(value: BigNumberish) { setStore(this.#props, "nonce", getNumber(value, "value")); }
|
||||
|
||||
get gasLimit(): bigint { return getStore(this.#props, "gasLimit"); }
|
||||
set gasLimit(value: BigNumberish) { setStore(this.#props, "gasLimit", logger.getBigInt(value)); }
|
||||
set gasLimit(value: BigNumberish) { setStore(this.#props, "gasLimit", getBigInt(value)); }
|
||||
|
||||
get gasPrice(): null | bigint {
|
||||
const value = getStore(this.#props, "gasPrice");
|
||||
@ -408,7 +409,7 @@ export class Transaction implements Freezable<Transaction>, TransactionLike<stri
|
||||
return value;
|
||||
}
|
||||
set gasPrice(value: null | BigNumberish) {
|
||||
setStore(this.#props, "gasPrice", (value == null) ? null: logger.getBigInt(value, "gasPrice"));
|
||||
setStore(this.#props, "gasPrice", (value == null) ? null: getBigInt(value, "gasPrice"));
|
||||
}
|
||||
|
||||
get maxPriorityFeePerGas(): null | bigint {
|
||||
@ -417,7 +418,7 @@ export class Transaction implements Freezable<Transaction>, TransactionLike<stri
|
||||
return value;
|
||||
}
|
||||
set maxPriorityFeePerGas(value: null | BigNumberish) {
|
||||
setStore(this.#props, "maxPriorityFeePerGas", (value == null) ? null: logger.getBigInt(value, "maxPriorityFeePerGas"));
|
||||
setStore(this.#props, "maxPriorityFeePerGas", (value == null) ? null: getBigInt(value, "maxPriorityFeePerGas"));
|
||||
}
|
||||
|
||||
get maxFeePerGas(): null | bigint {
|
||||
@ -426,7 +427,7 @@ export class Transaction implements Freezable<Transaction>, TransactionLike<stri
|
||||
return value;
|
||||
}
|
||||
set maxFeePerGas(value: null | BigNumberish) {
|
||||
setStore(this.#props, "maxFeePerGas", (value == null) ? null: logger.getBigInt(value, "maxFeePerGas"));
|
||||
setStore(this.#props, "maxFeePerGas", (value == null) ? null: getBigInt(value, "maxFeePerGas"));
|
||||
}
|
||||
|
||||
get data(): string { return getStore(this.#props, "data"); }
|
||||
@ -434,11 +435,11 @@ export class Transaction implements Freezable<Transaction>, TransactionLike<stri
|
||||
|
||||
get value(): bigint { return getStore(this.#props, "value"); }
|
||||
set value(value: BigNumberish) {
|
||||
setStore(this.#props, "value", logger.getBigInt(value, "value"));
|
||||
setStore(this.#props, "value", getBigInt(value, "value"));
|
||||
}
|
||||
|
||||
get chainId(): bigint { return getStore(this.#props, "chainId"); }
|
||||
set chainId(value: BigNumberish) { setStore(this.#props, "chainId", logger.getBigInt(value)); }
|
||||
set chainId(value: BigNumberish) { setStore(this.#props, "chainId", getBigInt(value)); }
|
||||
|
||||
get signature(): null | Signature { return getStore(this.#props, "sig") || null; }
|
||||
set signature(value: null | SignatureLike) {
|
||||
@ -624,7 +625,7 @@ export class Transaction implements Freezable<Transaction>, TransactionLike<stri
|
||||
|
||||
static from(tx: string | TransactionLike<string>): Transaction {
|
||||
if (typeof(tx) === "string") {
|
||||
const payload = logger.getBytes(tx);
|
||||
const payload = getBytes(tx);
|
||||
|
||||
if (payload[0] >= 0x7f) { // @TODO: > vs >= ??
|
||||
return Transaction.from(_parseLegacy(payload));
|
||||
|
@ -1,5 +1,6 @@
|
||||
|
||||
import { logger } from "./logger.js";
|
||||
import { getBytes } from "./data.js";
|
||||
import { throwArgumentError } from "./errors.js";
|
||||
import { toBigInt, toHex } from "./maths.js";
|
||||
|
||||
import type { BytesLike } from "./index.js";
|
||||
@ -17,7 +18,7 @@ function getAlpha(letter: string): bigint {
|
||||
}
|
||||
const result = Lookup[letter];
|
||||
if (result == null) {
|
||||
logger.throwArgumentError(`invalid base58 value`, "letter", letter);
|
||||
throwArgumentError(`invalid base58 value`, "letter", letter);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -30,7 +31,7 @@ const BN_58 = BigInt(58);
|
||||
* Encode %%value%% as Base58-encoded data.
|
||||
*/
|
||||
export function encodeBase58(_value: BytesLike): string {
|
||||
let value = toBigInt(logger.getBytes(_value));
|
||||
let value = toBigInt(getBytes(_value));
|
||||
let result = "";
|
||||
while (value) {
|
||||
result = Alphabet[Number(value % BN_58)] + result;
|
||||
@ -42,11 +43,11 @@ export function encodeBase58(_value: BytesLike): string {
|
||||
/**
|
||||
* Decode the Base58-encoded %%value%%.
|
||||
*/
|
||||
export function decodeBase58(value: string): string {
|
||||
export function decodeBase58(value: string): Uint8Array {
|
||||
let result = BN_0;
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
result *= BN_58;
|
||||
result += getAlpha(value[i]);
|
||||
}
|
||||
return toHex(result);
|
||||
return getBytes(toHex(result));
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
// utils/base64-browser
|
||||
|
||||
import { logger } from "./logger.js";
|
||||
import { getBytes } from "./data.js";
|
||||
|
||||
import type { BytesLike } from "./data.js";
|
||||
|
||||
@ -12,11 +12,11 @@ export function decodeBase64(textData: string): Uint8Array {
|
||||
for (let i = 0; i < textData.length; i++) {
|
||||
data[i] = textData.charCodeAt(i);
|
||||
}
|
||||
return logger.getBytes(data);
|
||||
return getBytes(data);
|
||||
}
|
||||
|
||||
export function encodeBase64(_data: BytesLike): string {
|
||||
const data = logger.getBytes(_data);
|
||||
const data = getBytes(_data);
|
||||
let textData = "";
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
textData += String.fromCharCode(data[i]);
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { logger } from "./logger.js";
|
||||
import { getBytes, getBytesCopy } from "./data.js";
|
||||
|
||||
import type { BytesLike } from "./data.js";
|
||||
|
||||
|
||||
export function decodeBase64(textData: string): Uint8Array {
|
||||
return logger.getBytesCopy(Buffer.from(textData, "base64"));
|
||||
return getBytesCopy(Buffer.from(textData, "base64"));
|
||||
};
|
||||
|
||||
export function encodeBase64(data: BytesLike): string {
|
||||
return Buffer.from(logger.getBytes(data)).toString("base64");
|
||||
return Buffer.from(getBytes(data)).toString("base64");
|
||||
}
|
||||
|
@ -1,9 +1,37 @@
|
||||
import { logger } from "./logger.js";
|
||||
import { throwArgumentError, throwError } from "./errors.js";
|
||||
|
||||
|
||||
export type BytesLike = string | Uint8Array;
|
||||
|
||||
function _getBytes(value: BytesLike, name?: string, copy?: boolean): Uint8Array {
|
||||
if (value instanceof Uint8Array) {
|
||||
if (copy) { return new Uint8Array(value); }
|
||||
return value;
|
||||
}
|
||||
|
||||
export function isHexString(value: any, length?: number | boolean): value is string {
|
||||
if (typeof(value) === "string" && value.match(/^0x([0-9a-f][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;
|
||||
}
|
||||
|
||||
return throwArgumentError("invalid BytesLike value", name || "value", value);
|
||||
}
|
||||
|
||||
export function getBytes(value: BytesLike, name?: string): Uint8Array {
|
||||
return _getBytes(value, name, false);
|
||||
}
|
||||
|
||||
export function getBytesCopy(value: BytesLike, name?: string): Uint8Array {
|
||||
return _getBytes(value, name, true);
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
}
|
||||
@ -20,7 +48,7 @@ export function isBytesLike(value: any): value is BytesLike {
|
||||
|
||||
const HexCharacters: string = "0123456789abcdef";
|
||||
export function hexlify(data: BytesLike): string {
|
||||
const bytes = logger.getBytes(data);
|
||||
const bytes = getBytes(data);
|
||||
|
||||
let result = "0x";
|
||||
for (let i = 0; i < bytes.length; i++) {
|
||||
@ -36,12 +64,12 @@ export function concat(datas: ReadonlyArray<BytesLike>): string {
|
||||
|
||||
export function dataLength(data: BytesLike): number {
|
||||
if (isHexString(data, true)) { return (data.length - 2) / 2; }
|
||||
return logger.getBytes(data).length;
|
||||
return getBytes(data).length;
|
||||
}
|
||||
|
||||
export function dataSlice(data: BytesLike, start?: number, end?: number): string {
|
||||
const bytes = logger.getBytes(data);
|
||||
if (end != null && end > bytes.length) { logger.throwError("cannot slice beyond data bounds", "BUFFER_OVERRUN", {
|
||||
const bytes = getBytes(data);
|
||||
if (end != null && end > bytes.length) { throwError("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));
|
||||
@ -55,9 +83,9 @@ export function stripZerosLeft(data: BytesLike): string {
|
||||
|
||||
|
||||
function zeroPad(data: BytesLike, length: number, left: boolean): string {
|
||||
const bytes = logger.getBytes(data);
|
||||
const bytes = getBytes(data);
|
||||
if (length < bytes.length) {
|
||||
logger.throwError("padding exceeds data length", "BUFFER_OVERRUN", {
|
||||
throwError("padding exceeds data length", "BUFFER_OVERRUN", {
|
||||
buffer: new Uint8Array(bytes),
|
||||
length: length,
|
||||
offset: length + 1
|
||||
|
@ -1,5 +1,8 @@
|
||||
//export type TransactionReceipt {
|
||||
//}
|
||||
import { version } from "../_version.js";
|
||||
|
||||
import { defineReadOnly } from "./properties.js";
|
||||
|
||||
export type ErrorSignature = {
|
||||
r: string;
|
||||
@ -10,6 +13,13 @@ export type ErrorSignature = {
|
||||
|
||||
export type ErrorAccessList = Array<{ address: string, storageKeys: Array<string> }>;
|
||||
|
||||
export type ErrorInfo<T> = Omit<T, "code" | "name" | "message">;
|
||||
|
||||
// The type of error to use for various error codes
|
||||
const ErrorConstructors: Record<string, { new (...args: Array<any>): Error }> = { };
|
||||
ErrorConstructors.INVALID_ARGUMENT = TypeError;
|
||||
ErrorConstructors.NUMERIC_FAULT = RangeError;
|
||||
ErrorConstructors.BUFFER_OVERRUN = RangeError;
|
||||
/*
|
||||
export interface ErrorTransaction {
|
||||
type?: number;
|
||||
@ -237,6 +247,12 @@ export interface ActionRejectedError extends EthersError<"ACTION_REJECTED"> {
|
||||
|
||||
// Coding; converts an ErrorCode its Typed Error
|
||||
|
||||
/**
|
||||
* A conditional type that transforms the [[ErrorCode]] T into
|
||||
* its EthersError type.
|
||||
*
|
||||
* @flatworm-skip-docs
|
||||
*/
|
||||
export type CodedEthersError<T> =
|
||||
T extends "UNKNOWN_ERROR" ? UnknownError:
|
||||
T extends "NOT_IMPLEMENTED" ? NotImplementedError:
|
||||
@ -267,6 +283,8 @@ export type CodedEthersError<T> =
|
||||
|
||||
never;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* try {
|
||||
* // code....
|
||||
@ -283,3 +301,111 @@ export function isError<K extends ErrorCode, T extends CodedEthersError<K>>(erro
|
||||
export function isCallException(error: any): error is CallExceptionError {
|
||||
return isError(error, "CALL_EXCEPTION");
|
||||
}
|
||||
|
||||
export function makeError<K extends ErrorCode, T extends CodedEthersError<K>>(message: string, code: K, info?: ErrorInfo<T>): T {
|
||||
{
|
||||
const details: Array<string> = [];
|
||||
if (info) {
|
||||
for (const key in info) {
|
||||
const value = <any>(info[<keyof ErrorInfo<T>>key]);
|
||||
try {
|
||||
details.push(key + "=" + JSON.stringify(value));
|
||||
} catch (error) {
|
||||
details.push(key + "=[could not serialize object]");
|
||||
}
|
||||
}
|
||||
}
|
||||
details.push(`code=${ code }`);
|
||||
details.push(`version=${ version }`);
|
||||
|
||||
if (details.length) {
|
||||
message += " (" + details.join(", ") + ")";
|
||||
}
|
||||
}
|
||||
|
||||
const create = ErrorConstructors[code] || Error;
|
||||
const error = <T>(new create(message));
|
||||
defineReadOnly(error, "code", code);
|
||||
if (info) {
|
||||
for (const key in info) {
|
||||
defineReadOnly(error, <keyof T>key, <any>(info[<keyof ErrorInfo<T>>key]));
|
||||
}
|
||||
}
|
||||
return <T>error;
|
||||
}
|
||||
|
||||
export function throwError<K extends ErrorCode, T extends CodedEthersError<K>>(message: string, code: K, info?: ErrorInfo<T>): never {
|
||||
throw makeError(message, code, info);
|
||||
}
|
||||
|
||||
export function throwArgumentError(message: string, name: string, value: any): never {
|
||||
return throwError(message, "INVALID_ARGUMENT", {
|
||||
argument: name,
|
||||
value: value
|
||||
});
|
||||
}
|
||||
|
||||
export function assertArgument(check: unknown, message: string, name: string, value: unknown): asserts check {
|
||||
if (!check) { throwArgumentError(message, name, value); }
|
||||
}
|
||||
|
||||
|
||||
export function assertArgumentCount(count: number, expectedCount: number, message: string = ""): void {
|
||||
if (message) { message = ": " + message; }
|
||||
|
||||
if (count < expectedCount) {
|
||||
throwError("missing arguemnt" + message, "MISSING_ARGUMENT", {
|
||||
count: count,
|
||||
expectedCount: expectedCount
|
||||
});
|
||||
}
|
||||
|
||||
if (count > expectedCount) {
|
||||
throwError("too many arguemnts" + message, "UNEXPECTED_ARGUMENT", {
|
||||
count: count,
|
||||
expectedCount: expectedCount
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const _normalizeForms = ["NFD", "NFC", "NFKD", "NFKC"].reduce((accum, form) => {
|
||||
try {
|
||||
// General test for normalize
|
||||
/* c8 ignore start */
|
||||
if ("test".normalize(form) !== "test") { throw new Error("bad"); };
|
||||
/* c8 ignore stop */
|
||||
|
||||
if (form === "NFD") {
|
||||
const check = String.fromCharCode(0xe9).normalize("NFD");
|
||||
const expected = String.fromCharCode(0x65, 0x0301)
|
||||
/* c8 ignore start */
|
||||
if (check !== expected) { throw new Error("broken") }
|
||||
/* c8 ignore stop */
|
||||
}
|
||||
|
||||
accum.push(form);
|
||||
} catch(error) { }
|
||||
|
||||
return accum;
|
||||
}, <Array<string>>[]);
|
||||
|
||||
export function assertNormalize(form: string): void {
|
||||
if (_normalizeForms.indexOf(form) === -1) {
|
||||
throwError("platform missing String.prototype.normalize", "UNSUPPORTED_OPERATION", {
|
||||
operation: "String.prototype.normalize", info: { form }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function assertPrivate(givenGuard: any, guard: any, className: string = ""): void {
|
||||
if (givenGuard !== guard) {
|
||||
let method = className, operation = "new";
|
||||
if (className) {
|
||||
method += ".";
|
||||
operation += " " + className;
|
||||
}
|
||||
throwError(`private constructor; use ${ method }from* methods`, "UNSUPPORTED_OPERATION", {
|
||||
operation
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { decodeBase64, encodeBase64 } from "./base64.js";
|
||||
import { hexlify } from "./data.js";
|
||||
import { assertArgument, logger } from "./logger.js";
|
||||
import { assertArgument, throwArgumentError, throwError } from "./errors.js";
|
||||
import { defineProperties } from "./properties.js";
|
||||
import { toUtf8Bytes, toUtf8String } from "./utf8.js"
|
||||
|
||||
@ -114,7 +114,7 @@ export class FetchCancelSignal {
|
||||
|
||||
addListener(listener: () => void): void {
|
||||
if (this.#cancelled) {
|
||||
logger.throwError("singal already cancelled", "UNSUPPORTED_OPERATION", {
|
||||
throwError("singal already cancelled", "UNSUPPORTED_OPERATION", {
|
||||
operation: "fetchCancelSignal.addCancelListener"
|
||||
});
|
||||
}
|
||||
@ -125,7 +125,7 @@ export class FetchCancelSignal {
|
||||
|
||||
checkSignal(): void {
|
||||
if (!this.cancelled) { return; }
|
||||
logger.throwError("cancelled", "CANCELLED", { });
|
||||
throwError("cancelled", "CANCELLED", { });
|
||||
}
|
||||
}
|
||||
|
||||
@ -251,7 +251,7 @@ export class FetchRequest implements Iterable<[ key: string, value: string ]> {
|
||||
}
|
||||
setCredentials(username: string, password: string): void {
|
||||
if (username.match(/:/)) {
|
||||
logger.throwArgumentError("invalid basic authentication username", "username", "[REDACTED]");
|
||||
throwArgumentError("invalid basic authentication username", "username", "[REDACTED]");
|
||||
}
|
||||
this.#creds = `${ username }:${ password }`;
|
||||
}
|
||||
@ -319,7 +319,7 @@ export class FetchRequest implements Iterable<[ key: string, value: string ]> {
|
||||
}
|
||||
|
||||
if (getTime() > expires) {
|
||||
return logger.throwError("timeout", "TIMEOUT", {
|
||||
return throwError("timeout", "TIMEOUT", {
|
||||
operation: "request.send", reason: "timeout", request: _request
|
||||
});
|
||||
}
|
||||
@ -409,7 +409,7 @@ export class FetchRequest implements Iterable<[ key: string, value: string ]> {
|
||||
|
||||
send(): Promise<FetchResponse> {
|
||||
if (this.#signal != null) {
|
||||
return logger.throwError("request already sent", "UNSUPPORTED_OPERATION", { operation: "fetchRequest.send" });
|
||||
return throwError("request already sent", "UNSUPPORTED_OPERATION", { operation: "fetchRequest.send" });
|
||||
}
|
||||
this.#signal = new FetchCancelSignal(this);
|
||||
return this.#send(0, getTime() + this.timeout, 0, this, new FetchResponse(0, "", { }, null, this));
|
||||
@ -417,7 +417,7 @@ export class FetchRequest implements Iterable<[ key: string, value: string ]> {
|
||||
|
||||
cancel(): void {
|
||||
if (this.#signal == null) {
|
||||
return logger.throwError("request has not been sent", "UNSUPPORTED_OPERATION", { operation: "fetchRequest.cancel" });
|
||||
return throwError("request has not been sent", "UNSUPPORTED_OPERATION", { operation: "fetchRequest.cancel" });
|
||||
}
|
||||
const signal = fetchSignals.get(this);
|
||||
if (!signal) { throw new Error("missing signal; should not happen"); }
|
||||
@ -438,7 +438,7 @@ export class FetchRequest implements Iterable<[ key: string, value: string ]> {
|
||||
// - downgrading the security (e.g. https => http)
|
||||
// - to non-HTTP (or non-HTTPS) protocols [this could be relaxed?]
|
||||
if (this.method !== "GET" || (current === "https" && target === "http") || !location.match(/^https?:/)) {
|
||||
return logger.throwError(`unsupported redirect`, "UNSUPPORTED_OPERATION", {
|
||||
return throwError(`unsupported redirect`, "UNSUPPORTED_OPERATION", {
|
||||
operation: `redirect(${ this.method } ${ JSON.stringify(this.url) } => ${ JSON.stringify(location) })`
|
||||
});
|
||||
}
|
||||
@ -536,7 +536,7 @@ export class FetchResponse implements Iterable<[ key: string, value: string ]> {
|
||||
|
||||
get statusCode(): number { return this.#statusCode; }
|
||||
get statusMessage(): string { return this.#statusMessage; }
|
||||
get headers() { return this.#headers; }
|
||||
get headers(): Record<string, string> { return this.#headers; }
|
||||
get body(): null | Readonly<Uint8Array> {
|
||||
return (this.#body == null) ? null: new Uint8Array(this.#body);
|
||||
}
|
||||
@ -544,7 +544,7 @@ export class FetchResponse implements Iterable<[ key: string, value: string ]> {
|
||||
try {
|
||||
return (this.#body == null) ? "": toUtf8String(this.#body);
|
||||
} catch (error) {
|
||||
return logger.throwError("response body is not valid UTF-8 data", "UNSUPPORTED_OPERATION", {
|
||||
return throwError("response body is not valid UTF-8 data", "UNSUPPORTED_OPERATION", {
|
||||
operation: "bodyText", info: { response: this }
|
||||
});
|
||||
}
|
||||
@ -553,7 +553,7 @@ export class FetchResponse implements Iterable<[ key: string, value: string ]> {
|
||||
try {
|
||||
return JSON.parse(this.bodyText);
|
||||
} catch (error) {
|
||||
return logger.throwError("response body is not valid JSON", "UNSUPPORTED_OPERATION", {
|
||||
return throwError("response body is not valid JSON", "UNSUPPORTED_OPERATION", {
|
||||
operation: "bodyJson", info: { response: this }
|
||||
});
|
||||
}
|
||||
@ -607,7 +607,7 @@ export class FetchResponse implements Iterable<[ key: string, value: string ]> {
|
||||
if (stall == null) {
|
||||
stall = -1;
|
||||
} else if (typeof(stall) !== "number" || !Number.isInteger(stall) || stall < 0) {
|
||||
return logger.throwArgumentError("invalid stall timeout", "stall", stall);
|
||||
return throwArgumentError("invalid stall timeout", "stall", stall);
|
||||
}
|
||||
|
||||
const error = new Error(message || "throttling requests");
|
||||
@ -637,7 +637,7 @@ export class FetchResponse implements Iterable<[ key: string, value: string ]> {
|
||||
if (message === "") {
|
||||
message = `server response ${ this.statusCode } ${ this.statusMessage }`;
|
||||
}
|
||||
logger.throwError(message, "SERVER_ERROR", {
|
||||
throwError(message, "SERVER_ERROR", {
|
||||
request: (this.request || "unknown request"), response: this, error
|
||||
});
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { logger } from "./logger.js";
|
||||
import { fromTwos, toBigInt, toHex, toTwos } from "./maths.js";
|
||||
import { getBytes } from "./data.js";
|
||||
import { throwArgumentError, throwError } from "./errors.js";
|
||||
import { getBigInt, getNumber, fromTwos, toBigInt, toHex, toTwos } from "./maths.js";
|
||||
|
||||
import type { BigNumberish, BytesLike, Numeric } from "./index.js";
|
||||
|
||||
@ -11,7 +12,7 @@ const NegativeOne = BigInt(-1);
|
||||
function throwFault(message: string, fault: string, operation: string, value?: any): never {
|
||||
const params: any = { fault: fault, operation: operation };
|
||||
if (value !== undefined) { params.value = value; }
|
||||
return logger.throwError(message, "NUMERIC_FAULT", params);
|
||||
return throwError(message, "NUMERIC_FAULT", params);
|
||||
}
|
||||
|
||||
// Constant to pull zeros from for multipliers
|
||||
@ -22,7 +23,7 @@ while (zeros.length < 256) { zeros += zeros; }
|
||||
function getMultiplier(decimals: number): bigint {
|
||||
|
||||
if (typeof(decimals) !== "number" || decimals < 0 || decimals > 256 || decimals % 1 ) {
|
||||
logger.throwArgumentError("invalid decimal length", "decimals", decimals);
|
||||
throwArgumentError("invalid decimal length", "decimals", decimals);
|
||||
}
|
||||
|
||||
return BigInt("1" + zeros.substring(0, decimals));
|
||||
@ -31,8 +32,8 @@ function getMultiplier(decimals: number): bigint {
|
||||
export function formatFixed(_value: BigNumberish, _decimals?: Numeric): string {
|
||||
if (_decimals == null) { _decimals = 18; }
|
||||
|
||||
let value = logger.getBigInt(_value, "value");
|
||||
const decimals = logger.getNumber(_decimals, "decimals");
|
||||
let value = getBigInt(_value, "value");
|
||||
const decimals = getNumber(_decimals, "decimals");
|
||||
|
||||
const multiplier = getMultiplier(decimals);
|
||||
const multiplierStr = String(multiplier);
|
||||
@ -60,12 +61,12 @@ export function formatFixed(_value: BigNumberish, _decimals?: Numeric): string {
|
||||
|
||||
export function parseFixed(value: string, _decimals: Numeric): bigint {
|
||||
if (_decimals == null) { _decimals = 18; }
|
||||
const decimals = logger.getNumber(_decimals, "decimals");
|
||||
const decimals = getNumber(_decimals, "decimals");
|
||||
|
||||
const multiplier = getMultiplier(decimals);
|
||||
|
||||
if (typeof(value) !== "string" || !value.match(/^-?[0-9.]+$/)) {
|
||||
logger.throwArgumentError("invalid decimal value", "value", value);
|
||||
throwArgumentError("invalid decimal value", "value", value);
|
||||
}
|
||||
|
||||
// Is it negative?
|
||||
@ -73,13 +74,13 @@ export function parseFixed(value: string, _decimals: Numeric): bigint {
|
||||
if (negative) { value = value.substring(1); }
|
||||
|
||||
if (value === ".") {
|
||||
logger.throwArgumentError("missing value", "value", value);
|
||||
throwArgumentError("missing value", "value", value);
|
||||
}
|
||||
|
||||
// Split it into a whole and fractional part
|
||||
const comps = value.split(".");
|
||||
if (comps.length > 2) {
|
||||
logger.throwArgumentError("too many decimal points", "value", value);
|
||||
throwArgumentError("too many decimal points", "value", value);
|
||||
}
|
||||
|
||||
let whole = (comps[0] || "0"), fraction = (comps[1] || "0");
|
||||
@ -110,7 +111,6 @@ export function parseFixed(value: string, _decimals: Numeric): bigint {
|
||||
return wei;
|
||||
}
|
||||
|
||||
|
||||
export class FixedFormat {
|
||||
readonly signed: boolean;
|
||||
readonly width: number;
|
||||
@ -121,7 +121,7 @@ export class FixedFormat {
|
||||
|
||||
constructor(constructorGuard: any, signed: boolean, width: number, decimals: number) {
|
||||
if (constructorGuard !== _constructorGuard) {
|
||||
logger.throwError("cannot use FixedFormat constructor; use FixedFormat.from", "UNSUPPORTED_OPERATION", {
|
||||
throwError("cannot use FixedFormat constructor; use FixedFormat.from", "UNSUPPORTED_OPERATION", {
|
||||
operation: "new FixedFormat"
|
||||
});
|
||||
}
|
||||
@ -156,7 +156,7 @@ export class FixedFormat {
|
||||
} else {
|
||||
const match = value.match(/^(u?)fixed([0-9]+)x([0-9]+)$/);
|
||||
if (!match) {
|
||||
return logger.throwArgumentError("invalid fixed format", "format", value);
|
||||
return throwArgumentError("invalid fixed format", "format", value);
|
||||
}
|
||||
signed = (match[1] !== "u");
|
||||
width = parseInt(match[2]);
|
||||
@ -166,7 +166,7 @@ export class FixedFormat {
|
||||
const check = (key: string, type: string, defaultValue: any): any => {
|
||||
if (value[key] == null) { return defaultValue; }
|
||||
if (typeof(value[key]) !== type) {
|
||||
logger.throwArgumentError("invalid fixed format (" + key + " not " + type +")", "format." + key, value[key]);
|
||||
throwArgumentError("invalid fixed format (" + key + " not " + type +")", "format." + key, value[key]);
|
||||
}
|
||||
return value[key];
|
||||
}
|
||||
@ -176,17 +176,20 @@ export class FixedFormat {
|
||||
}
|
||||
|
||||
if (width % 8) {
|
||||
logger.throwArgumentError("invalid fixed format width (not byte aligned)", "format.width", width);
|
||||
throwArgumentError("invalid fixed format width (not byte aligned)", "format.width", width);
|
||||
}
|
||||
|
||||
if (decimals > 80) {
|
||||
logger.throwArgumentError("invalid fixed format (decimals too large)", "format.decimals", decimals);
|
||||
throwArgumentError("invalid fixed format (decimals too large)", "format.decimals", decimals);
|
||||
}
|
||||
|
||||
return new FixedFormat(_constructorGuard, signed, width, decimals);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixed Number class
|
||||
*/
|
||||
export class FixedNumber {
|
||||
readonly format: FixedFormat;
|
||||
|
||||
@ -197,7 +200,7 @@ export class FixedNumber {
|
||||
|
||||
constructor(constructorGuard: any, hex: string, value: string, format?: FixedFormat) {
|
||||
if (constructorGuard !== _constructorGuard) {
|
||||
logger.throwError("cannot use FixedNumber constructor; use FixedNumber.from", "UNSUPPORTED_OPERATION", {
|
||||
throwError("cannot use FixedNumber constructor; use FixedNumber.from", "UNSUPPORTED_OPERATION", {
|
||||
operation: "new FixedFormat"
|
||||
});
|
||||
}
|
||||
@ -213,10 +216,14 @@ export class FixedNumber {
|
||||
|
||||
#checkFormat(other: FixedNumber): void {
|
||||
if (this.format.name !== other.format.name) {
|
||||
logger.throwArgumentError("incompatible format; use fixedNumber.toFormat", "other", other);
|
||||
throwArgumentError("incompatible format; use fixedNumber.toFormat", "other", other);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new [[FixedNumber]] with the result of this added
|
||||
* to %%other%%.
|
||||
*/
|
||||
addUnsafe(other: FixedNumber): FixedNumber {
|
||||
this.#checkFormat(other);
|
||||
const a = parseFixed(this.#value, this.format.decimals);
|
||||
@ -282,7 +289,7 @@ export class FixedNumber {
|
||||
if (comps.length === 1) { comps.push("0"); }
|
||||
|
||||
if (decimals < 0 || decimals > 80 || (decimals % 1)) {
|
||||
logger.throwArgumentError("invalid decimal count", "decimals", decimals);
|
||||
throwArgumentError("invalid decimal count", "decimals", decimals);
|
||||
}
|
||||
|
||||
if (comps[1].length <= decimals) { return this; }
|
||||
@ -324,7 +331,7 @@ export class FixedNumber {
|
||||
}
|
||||
|
||||
|
||||
static fromValue(value: BigNumberish, decimals = 0, format: FixedFormat | string | number = "fixed"): FixedNumber {
|
||||
static fromValue(value: BigNumberish, decimals: number = 0, format: FixedFormat | string | number = "fixed"): FixedNumber {
|
||||
return FixedNumber.fromString(formatFixed(value, decimals), FixedFormat.from(format));
|
||||
}
|
||||
|
||||
@ -350,7 +357,7 @@ export class FixedNumber {
|
||||
}
|
||||
|
||||
static fromBytes(_value: BytesLike, format: FixedFormat | string | number = "fixed"): FixedNumber {
|
||||
const value = logger.getBytes(_value, "value");
|
||||
const value = getBytes(_value, "value");
|
||||
const fixedFormat = FixedFormat.from(format);
|
||||
|
||||
if (value.length > fixedFormat.width / 8) {
|
||||
@ -366,7 +373,7 @@ export class FixedNumber {
|
||||
return new FixedNumber(_constructorGuard, hex, decimal, fixedFormat);
|
||||
}
|
||||
|
||||
static from(value: any, format?: FixedFormat | string | number) {
|
||||
static from(value: any, format?: FixedFormat | string | number): FixedNumber {
|
||||
if (typeof(value) === "string") {
|
||||
return FixedNumber.fromString(value, format);
|
||||
}
|
||||
@ -384,7 +391,7 @@ export class FixedNumber {
|
||||
}
|
||||
}
|
||||
|
||||
return logger.throwArgumentError("invalid FixedNumber value", "value", value);
|
||||
return throwArgumentError("invalid FixedNumber value", "value", value);
|
||||
}
|
||||
|
||||
static isFixedNumber(value: any): value is FixedNumber {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { logger } from "./logger.js";
|
||||
import { throwError } from "./errors.js";
|
||||
|
||||
import type { FetchRequest, FetchCancelSignal, GetUrlResponse } from "./fetch.js";
|
||||
|
||||
@ -31,14 +31,14 @@ export async function getUrl(req: FetchRequest, _signal?: FetchCancelSignal): Pr
|
||||
const protocol = req.url.split(":")[0].toLowerCase();
|
||||
|
||||
if (protocol !== "http" && protocol !== "https") {
|
||||
logger.throwError(`unsupported protocol ${ protocol }`, "UNSUPPORTED_OPERATION", {
|
||||
throwError(`unsupported protocol ${ protocol }`, "UNSUPPORTED_OPERATION", {
|
||||
info: { protocol },
|
||||
operation: "request"
|
||||
});
|
||||
}
|
||||
|
||||
if (req.credentials && !req.allowInsecureAuthentication) {
|
||||
logger.throwError("insecure authorized connections unsupported", "UNSUPPORTED_OPERATION", {
|
||||
throwError("insecure authorized connections unsupported", "UNSUPPORTED_OPERATION", {
|
||||
operation: "request"
|
||||
});
|
||||
}
|
||||
|
@ -2,7 +2,8 @@ import http from "http";
|
||||
import https from "https";
|
||||
import { gunzipSync } from "zlib";
|
||||
|
||||
import { logger } from "./logger.js";
|
||||
import { throwError } from "./errors.js";
|
||||
import { getBytes } from "./data.js";
|
||||
|
||||
import type { FetchRequest, FetchCancelSignal, GetUrlResponse } from "./fetch.js";
|
||||
|
||||
@ -12,14 +13,14 @@ export async function getUrl(req: FetchRequest, signal?: FetchCancelSignal): Pro
|
||||
const protocol = req.url.split(":")[0].toLowerCase();
|
||||
|
||||
if (protocol !== "http" && protocol !== "https") {
|
||||
logger.throwError(`unsupported protocol ${ protocol }`, "UNSUPPORTED_OPERATION", {
|
||||
throwError(`unsupported protocol ${ protocol }`, "UNSUPPORTED_OPERATION", {
|
||||
info: { protocol },
|
||||
operation: "request"
|
||||
});
|
||||
}
|
||||
|
||||
if (req.credentials && !req.allowInsecureAuthentication) {
|
||||
logger.throwError("insecure authorized connections unsupported", "UNSUPPORTED_OPERATION", {
|
||||
throwError("insecure authorized connections unsupported", "UNSUPPORTED_OPERATION", {
|
||||
operation: "request"
|
||||
});
|
||||
}
|
||||
@ -78,7 +79,7 @@ export async function getUrl(req: FetchRequest, signal?: FetchCancelSignal): Pro
|
||||
|
||||
resp.on("end", () => {
|
||||
if (headers["content-encoding"] === "gzip" && body) {
|
||||
body = logger.getBytes(gunzipSync(body));
|
||||
body = getBytes(gunzipSync(body));
|
||||
}
|
||||
|
||||
resolve({ statusCode, statusMessage, headers, body });
|
||||
|
@ -19,11 +19,15 @@ export { decodeBase58, encodeBase58 } from "./base58.js";
|
||||
export { decodeBase64, encodeBase64 } from "./base64.js";
|
||||
|
||||
export {
|
||||
isHexString, isBytesLike, hexlify, concat, dataLength, dataSlice,
|
||||
getBytes, getBytesCopy, isHexString, isBytesLike, hexlify, concat, dataLength, dataSlice,
|
||||
stripZerosLeft, zeroPadValue, zeroPadBytes
|
||||
} from "./data.js";
|
||||
|
||||
export { isCallException, isError } from "./errors.js"
|
||||
export {
|
||||
isCallException, isError,
|
||||
makeError, throwError, throwArgumentError,
|
||||
assertArgument, assertArgumentCount, assertPrivate, assertNormalize
|
||||
} from "./errors.js"
|
||||
|
||||
export { EventPayload } from "./events.js";
|
||||
|
||||
@ -31,11 +35,9 @@ export { FetchRequest, FetchResponse } from "./fetch.js";
|
||||
|
||||
export { FixedFormat, FixedNumber, formatFixed, parseFixed } from "./fixednumber.js"
|
||||
|
||||
export { assertArgument, Logger, logger } from "./logger.js";
|
||||
|
||||
export {
|
||||
fromTwos, toTwos, mask,
|
||||
toBigInt, toNumber, toHex, toArray, toQuantity
|
||||
getBigInt, getNumber, toBigInt, toNumber, toHex, toArray, toQuantity
|
||||
} from "./maths.js";
|
||||
|
||||
export { resolveProperties, defineReadOnly, defineProperties} from "./properties.js";
|
||||
|
@ -1,36 +1,13 @@
|
||||
/*
|
||||
import { version } from "../_version.js";
|
||||
|
||||
import type { BigNumberish, BytesLike } from "./index.js";
|
||||
import { throwArgumentError } from "./errors.js";
|
||||
|
||||
import type { CodedEthersError, ErrorCode } from "./errors.js";
|
||||
|
||||
|
||||
export type ErrorInfo<T> = Omit<T, "code" | "name" | "message">;
|
||||
|
||||
export type LogLevel = "debug" | "info" | "warning" | "error" | "off";
|
||||
|
||||
const LogLevels: Array<LogLevel> = [ "debug", "info", "warning", "error", "off" ];
|
||||
|
||||
const _normalizeForms = ["NFD", "NFC", "NFKD", "NFKC"].reduce((accum, form) => {
|
||||
try {
|
||||
// General test for normalize
|
||||
/* c8 ignore start */
|
||||
if ("test".normalize(form) !== "test") { throw new Error("bad"); };
|
||||
/* c8 ignore stop */
|
||||
|
||||
if (form === "NFD") {
|
||||
const check = String.fromCharCode(0xe9).normalize("NFD");
|
||||
const expected = String.fromCharCode(0x65, 0x0301)
|
||||
/* c8 ignore start */
|
||||
if (check !== expected) { throw new Error("broken") }
|
||||
/* c8 ignore stop */
|
||||
}
|
||||
|
||||
accum.push(form);
|
||||
} catch(error) { }
|
||||
|
||||
return accum;
|
||||
}, <Array<string>>[]);
|
||||
|
||||
function defineReadOnly<T, P extends keyof T>(object: T, name: P, value: T[P]): void {
|
||||
Object.defineProperty(object, name, {
|
||||
@ -38,15 +15,6 @@ function defineReadOnly<T, P extends keyof T>(object: T, name: P, value: T[P]):
|
||||
});
|
||||
}
|
||||
|
||||
// IEEE 754 support 53-bits of mantissa
|
||||
const maxValue = 0x1fffffffffffff;
|
||||
|
||||
// The type of error to use for various error codes
|
||||
const ErrorConstructors: Record<string, { new (...args: Array<any>): Error }> = { };
|
||||
ErrorConstructors.INVALID_ARGUMENT = TypeError;
|
||||
ErrorConstructors.NUMERIC_FAULT = RangeError;
|
||||
ErrorConstructors.BUFFER_OVERRUN = RangeError;
|
||||
|
||||
export type AssertFunc<T> = () => (undefined | T);
|
||||
|
||||
export class Logger {
|
||||
@ -66,168 +34,15 @@ export class Logger {
|
||||
set logLevel(value: LogLevel) {
|
||||
const logLevel = LogLevels.indexOf(value);
|
||||
if (logLevel == null) {
|
||||
this.throwArgumentError("invalid logLevel", "logLevel", value);
|
||||
throwArgumentError("invalid logLevel", "logLevel", value);
|
||||
}
|
||||
this.#logLevel = logLevel;
|
||||
}
|
||||
|
||||
makeError<K extends ErrorCode, T extends CodedEthersError<K>>(message: string, code: K, info?: ErrorInfo<T>): T {
|
||||
{
|
||||
const details: Array<string> = [];
|
||||
if (info) {
|
||||
for (const key in info) {
|
||||
const value = <any>(info[<keyof ErrorInfo<T>>key]);
|
||||
try {
|
||||
details.push(key + "=" + JSON.stringify(value));
|
||||
} catch (error) {
|
||||
details.push(key + "=[could not serialize object]");
|
||||
}
|
||||
}
|
||||
}
|
||||
details.push(`code=${ code }`);
|
||||
details.push(`version=${ this.version }`);
|
||||
|
||||
if (details.length) {
|
||||
message += " (" + details.join(", ") + ")";
|
||||
}
|
||||
}
|
||||
|
||||
const create = ErrorConstructors[code] || Error;
|
||||
const error = <T>(new create(message));
|
||||
defineReadOnly(error, "code", code);
|
||||
if (info) {
|
||||
for (const key in info) {
|
||||
defineReadOnly(error, <keyof T>key, <any>(info[<keyof ErrorInfo<T>>key]));
|
||||
}
|
||||
}
|
||||
return <T>error;
|
||||
}
|
||||
|
||||
throwError<K extends ErrorCode, T extends CodedEthersError<K>>(message: string, code: K, info?: ErrorInfo<T>): never {
|
||||
throw this.makeError(message, code, info);
|
||||
}
|
||||
|
||||
throwArgumentError(message: string, name: string, value: any): never {
|
||||
return this.throwError(message, "INVALID_ARGUMENT", {
|
||||
argument: name,
|
||||
value: value
|
||||
});
|
||||
}
|
||||
|
||||
assertNormalize(form: string): void {
|
||||
if (_normalizeForms.indexOf(form) === -1) {
|
||||
this.throwError("platform missing String.prototype.normalize", "UNSUPPORTED_OPERATION", {
|
||||
operation: "String.prototype.normalize", info: { form }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
assertPrivate(givenGuard: any, guard: any, className = ""): void {
|
||||
if (givenGuard !== guard) {
|
||||
let method = className, operation = "new";
|
||||
if (className) {
|
||||
method += ".";
|
||||
operation += " " + className;
|
||||
}
|
||||
this.throwError(`private constructor; use ${ method }from* methods`, "UNSUPPORTED_OPERATION", {
|
||||
operation
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
assertArgumentCount(count: number, expectedCount: number, message: string = ""): void {
|
||||
if (message) { message = ": " + message; }
|
||||
|
||||
if (count < expectedCount) {
|
||||
this.throwError("missing arguemnt" + message, "MISSING_ARGUMENT", {
|
||||
count: count,
|
||||
expectedCount: expectedCount
|
||||
});
|
||||
}
|
||||
|
||||
if (count > expectedCount) {
|
||||
this.throwError("too many arguemnts" + message, "UNEXPECTED_ARGUMENT", {
|
||||
count: count,
|
||||
expectedCount: expectedCount
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#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.match(/^0x([0-9a-f][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;
|
||||
}
|
||||
|
||||
return this.throwArgumentError("invalid BytesLike value", name || "value", value);
|
||||
}
|
||||
|
||||
getBytes(value: BytesLike, name?: string): Uint8Array {
|
||||
return this.#getBytes(value, name, false);
|
||||
}
|
||||
|
||||
getBytesCopy(value: BytesLike, name?: string): Uint8Array {
|
||||
return this.#getBytes(value, name, true);
|
||||
}
|
||||
|
||||
getNumber(value: BigNumberish, name?: string): number {
|
||||
switch (typeof(value)) {
|
||||
case "bigint":
|
||||
if (value < -maxValue || value > maxValue) {
|
||||
this.throwArgumentError("overflow", name || "value", value);
|
||||
}
|
||||
return Number(value);
|
||||
case "number":
|
||||
if (!Number.isInteger(value)) {
|
||||
this.throwArgumentError("underflow", name || "value", value);
|
||||
} else if (value < -maxValue || value > maxValue) {
|
||||
this.throwArgumentError("overflow", name || "value", value);
|
||||
}
|
||||
return value;
|
||||
case "string":
|
||||
try {
|
||||
return this.getNumber(BigInt(value), name);
|
||||
} catch(e: any) {
|
||||
this.throwArgumentError(`invalid numeric string: ${ e.message }`, name || "value", value);
|
||||
}
|
||||
}
|
||||
return this.throwArgumentError("invalid numeric value", name || "value", value);
|
||||
}
|
||||
|
||||
getBigInt(value: BigNumberish, name?: string): bigint {
|
||||
switch (typeof(value)) {
|
||||
case "bigint": return value;
|
||||
case "number":
|
||||
if (!Number.isInteger(value)) {
|
||||
this.throwArgumentError("underflow", name || "value", value);
|
||||
} else if (value < -maxValue || value > maxValue) {
|
||||
this.throwArgumentError("overflow", name || "value", value);
|
||||
}
|
||||
return BigInt(value);
|
||||
case "string":
|
||||
try {
|
||||
return BigInt(value);
|
||||
} catch(e: any) {
|
||||
this.throwArgumentError(`invalid BigNumberish string: ${ e.message }`, name || "value", value);
|
||||
}
|
||||
}
|
||||
return this.throwArgumentError("invalid BigNumberish value", name || "value", value);
|
||||
}
|
||||
|
||||
#log(_logLevel: LogLevel, args: Array<any>): void {
|
||||
const logLevel = LogLevels.indexOf(_logLevel);
|
||||
if (logLevel === -1) {
|
||||
this.throwArgumentError("invalid log level name", "logLevel", _logLevel);
|
||||
throwArgumentError("invalid log level name", "logLevel", _logLevel);
|
||||
}
|
||||
if (this.#logLevel > logLevel) { return; }
|
||||
console.log.apply(console, args);
|
||||
@ -248,7 +63,5 @@ export class Logger {
|
||||
|
||||
export const logger = new Logger(version);
|
||||
|
||||
export function assertArgument(check: unknown, message: string, name: string, value: unknown): asserts check {
|
||||
if (!check) { logger.throwArgumentError(message, name, value); }
|
||||
}
|
||||
|
||||
*/
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { hexlify, isBytesLike } from "./data.js";
|
||||
import { logger } from "./logger.js";
|
||||
import { throwArgumentError } from "./errors.js";
|
||||
|
||||
import type { BytesLike } from "./data.js";
|
||||
|
||||
@ -11,12 +11,15 @@ export type BigNumberish = string | Numeric;
|
||||
const BN_0 = BigInt(0);
|
||||
const BN_1 = BigInt(1);
|
||||
|
||||
// IEEE 754 support 53-bits of mantissa
|
||||
const maxValue = 0x1fffffffffffff;
|
||||
|
||||
/**
|
||||
* Convert %%value%% from a twos-compliment value of %%width%% bits.
|
||||
*/
|
||||
export function fromTwos(_value: BigNumberish, _width: Numeric): bigint {
|
||||
const value = logger.getBigInt(_value, "value");
|
||||
const width = BigInt(logger.getNumber(_width, "width"));
|
||||
const value = getBigInt(_value, "value");
|
||||
const width = BigInt(getNumber(_width, "width"));
|
||||
|
||||
// Top bit set; treat as a negative value
|
||||
if (value >> (width - BN_1)) {
|
||||
@ -31,8 +34,8 @@ export function fromTwos(_value: BigNumberish, _width: Numeric): bigint {
|
||||
* Convert %%value%% to a twos-compliment value of %%width%% bits.
|
||||
*/
|
||||
export function toTwos(_value: BigNumberish, _width: Numeric): bigint {
|
||||
const value = logger.getBigInt(_value, "value");
|
||||
const width = BigInt(logger.getNumber(_width, "width"));
|
||||
const value = getBigInt(_value, "value");
|
||||
const width = BigInt(getNumber(_width, "width"));
|
||||
|
||||
if (value < BN_0) {
|
||||
const mask = (BN_1 << width) - BN_1;
|
||||
@ -46,11 +49,30 @@ export function toTwos(_value: BigNumberish, _width: Numeric): bigint {
|
||||
* Mask %%value%% with a bitmask of %%bits%% ones.
|
||||
*/
|
||||
export function mask(_value: BigNumberish, _bits: Numeric): bigint {
|
||||
const value = logger.getBigInt(_value, "value");
|
||||
const bits = BigInt(logger.getNumber(_bits, "bits"));
|
||||
const value = getBigInt(_value, "value");
|
||||
const bits = BigInt(getNumber(_bits, "bits"));
|
||||
return value & ((BN_1 << bits) - BN_1);
|
||||
}
|
||||
|
||||
export function getBigInt(value: BigNumberish, name?: string): bigint {
|
||||
switch (typeof(value)) {
|
||||
case "bigint": return value;
|
||||
case "number":
|
||||
if (!Number.isInteger(value)) {
|
||||
throwArgumentError("underflow", name || "value", value);
|
||||
} else if (value < -maxValue || value > maxValue) {
|
||||
throwArgumentError("overflow", name || "value", value);
|
||||
}
|
||||
return BigInt(value);
|
||||
case "string":
|
||||
try {
|
||||
return BigInt(value);
|
||||
} catch(e: any) {
|
||||
throwArgumentError(`invalid BigNumberish string: ${ e.message }`, name || "value", value);
|
||||
}
|
||||
}
|
||||
return throwArgumentError("invalid BigNumberish value", name || "value", value);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@ -68,15 +90,40 @@ export function toBigInt(value: BigNumberish | Uint8Array): bigint {
|
||||
return BigInt(result);
|
||||
}
|
||||
|
||||
return logger.getBigInt(value);
|
||||
return getBigInt(value);
|
||||
}
|
||||
|
||||
export function getNumber(value: BigNumberish, name?: string): number {
|
||||
switch (typeof(value)) {
|
||||
case "bigint":
|
||||
if (value < -maxValue || value > maxValue) {
|
||||
throwArgumentError("overflow", name || "value", value);
|
||||
}
|
||||
return Number(value);
|
||||
case "number":
|
||||
if (!Number.isInteger(value)) {
|
||||
throwArgumentError("underflow", name || "value", value);
|
||||
} else if (value < -maxValue || value > maxValue) {
|
||||
throwArgumentError("overflow", name || "value", value);
|
||||
}
|
||||
return value;
|
||||
case "string":
|
||||
try {
|
||||
return getNumber(BigInt(value), name);
|
||||
} catch(e: any) {
|
||||
throwArgumentError(`invalid numeric string: ${ e.message }`, name || "value", value);
|
||||
}
|
||||
}
|
||||
return throwArgumentError("invalid numeric value", name || "value", value);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Converts %%value%% to a number. If %%value%% is a Uint8Array, it
|
||||
* is treated as Big Endian data. Throws if the value is not safe.
|
||||
*/
|
||||
export function toNumber(value: BigNumberish | Uint8Array): number {
|
||||
return logger.getNumber(toBigInt(value));
|
||||
return getNumber(toBigInt(value));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -85,7 +132,7 @@ export function toNumber(value: BigNumberish | Uint8Array): number {
|
||||
*/
|
||||
// Converts value to hex, optionally padding on the left to width bytes
|
||||
export function toHex(_value: BigNumberish, _width?: Numeric): string {
|
||||
const value = logger.getBigInt(_value, "value");
|
||||
const value = getBigInt(_value, "value");
|
||||
if (value < 0) { throw new Error("cannot convert negative value to hex"); }
|
||||
|
||||
let result = value.toString(16);
|
||||
@ -94,7 +141,7 @@ export function toHex(_value: BigNumberish, _width?: Numeric): string {
|
||||
// Ensure the value is of even length
|
||||
if (result.length % 2) { result = "0" + result; }
|
||||
} else {
|
||||
const width = logger.getNumber(_width, "width");
|
||||
const width = getNumber(_width, "width");
|
||||
if (width * 2 < result.length) { throw new Error(`value ${ value } exceeds width ${ width }`); }
|
||||
|
||||
// Pad the value to the required width
|
||||
@ -109,7 +156,7 @@ export function toHex(_value: BigNumberish, _width?: Numeric): string {
|
||||
* Converts %%value%% to a Big Endian Uint8Array.
|
||||
*/
|
||||
export function toArray(_value: BigNumberish): Uint8Array {
|
||||
const value = logger.getBigInt(_value, "value");
|
||||
const value = getBigInt(_value, "value");
|
||||
if (value < 0) { throw new Error("cannot convert negative value to hex"); }
|
||||
|
||||
if (value === BN_0) { return new Uint8Array([ ]); }
|
||||
|
@ -1,7 +1,8 @@
|
||||
//See: https://github.com/ethereum/wiki/wiki/RLP
|
||||
|
||||
import { hexlify } from "./data.js";
|
||||
import { logger } from "./logger.js";
|
||||
import { throwArgumentError, throwError } from "./errors.js";
|
||||
import { getBytes } from "./data.js";
|
||||
|
||||
import type { BytesLike, RlpStructuredData } from "./index.js";
|
||||
|
||||
@ -35,7 +36,7 @@ function _decodeChildren(data: Uint8Array, offset: number, childOffset: number,
|
||||
|
||||
childOffset += decoded.consumed;
|
||||
if (childOffset > offset + 1 + length) {
|
||||
logger.throwError("child data too short", "BUFFER_OVERRUN", {
|
||||
throwError("child data too short", "BUFFER_OVERRUN", {
|
||||
buffer: data, length, offset
|
||||
});
|
||||
}
|
||||
@ -47,14 +48,14 @@ function _decodeChildren(data: Uint8Array, offset: number, childOffset: number,
|
||||
// returns { consumed: number, result: Object }
|
||||
function _decode(data: Uint8Array, offset: number): { consumed: number, result: any } {
|
||||
if (data.length === 0) {
|
||||
logger.throwError("data too short", "BUFFER_OVERRUN", {
|
||||
throwError("data too short", "BUFFER_OVERRUN", {
|
||||
buffer: data, length: 0, offset: 1
|
||||
});
|
||||
}
|
||||
|
||||
const checkOffset = (offset: number) => {
|
||||
if (offset > data.length) {
|
||||
logger.throwError("data short segment too short", "BUFFER_OVERRUN", {
|
||||
throwError("data short segment too short", "BUFFER_OVERRUN", {
|
||||
buffer: data, length: data.length, offset
|
||||
});
|
||||
}
|
||||
@ -98,10 +99,10 @@ function _decode(data: Uint8Array, offset: number): { consumed: number, result:
|
||||
}
|
||||
|
||||
export function decodeRlp(_data: BytesLike): RlpStructuredData {
|
||||
const data = logger.getBytes(_data, "data");
|
||||
const data = getBytes(_data, "data");
|
||||
const decoded = _decode(data, 0);
|
||||
if (decoded.consumed !== data.length) {
|
||||
logger.throwArgumentError("unexpected junk after rlp payload", "data", _data);
|
||||
throwArgumentError("unexpected junk after rlp payload", "data", _data);
|
||||
}
|
||||
return decoded.result;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
//See: https://github.com/ethereum/wiki/wiki/RLP
|
||||
|
||||
import { logger } from "./logger.js";
|
||||
import { getBytes } from "./data.js";
|
||||
|
||||
import type { RlpStructuredData } from "./rlp.js";
|
||||
|
||||
@ -33,7 +33,7 @@ function _encode(object: Array<any> | string): Array<number> {
|
||||
|
||||
}
|
||||
|
||||
const data: Array<number> = Array.prototype.slice.call(logger.getBytes(object, "object"));
|
||||
const data: Array<number> = Array.prototype.slice.call(getBytes(object, "object"));
|
||||
|
||||
if (data.length === 1 && data[0] <= 0x7f) {
|
||||
return data;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { formatFixed, parseFixed } from "./fixednumber.js";
|
||||
import { logger } from "./logger.js";
|
||||
import { throwArgumentError } from "./errors.js";
|
||||
|
||||
import type { BigNumberish, Numeric } from "../utils/index.js";
|
||||
|
||||
@ -23,7 +23,7 @@ const names = [
|
||||
export function formatUnits(value: BigNumberish, unit?: string | Numeric): string {
|
||||
if (typeof(unit) === "string") {
|
||||
const index = names.indexOf(unit);
|
||||
if (index === -1) { logger.throwArgumentError("invalid unit", "unit", unit); }
|
||||
if (index === -1) { throwArgumentError("invalid unit", "unit", unit); }
|
||||
unit = 3 * index;
|
||||
}
|
||||
return formatFixed(value, (unit != null) ? unit: 18);
|
||||
@ -36,12 +36,12 @@ export function formatUnits(value: BigNumberish, unit?: string | Numeric): strin
|
||||
*/
|
||||
export function parseUnits(value: string, unit?: string | Numeric): bigint {
|
||||
if (typeof(value) !== "string") {
|
||||
logger.throwArgumentError("value must be a string", "value", value);
|
||||
throwArgumentError("value must be a string", "value", value);
|
||||
}
|
||||
|
||||
if (typeof(unit) === "string") {
|
||||
const index = names.indexOf(unit);
|
||||
if (index === -1) { logger.throwArgumentError("invalid unit", "unit", unit); }
|
||||
if (index === -1) { throwArgumentError("invalid unit", "unit", unit); }
|
||||
unit = 3 * index;
|
||||
}
|
||||
return parseFixed(value, (unit != null) ? unit: 18);
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { logger } from "./logger.js";
|
||||
import { getBytes } from "./data.js";
|
||||
import { assertNormalize, throwArgumentError } from "./errors.js";
|
||||
|
||||
import type { BytesLike } from "./index.js";
|
||||
|
||||
@ -42,8 +43,11 @@ export type Utf8ErrorReason =
|
||||
|
||||
export type Utf8ErrorFunc = (reason: Utf8ErrorReason, offset: number, bytes: ArrayLike<number>, output: Array<number>, badCodepoint?: number) => number;
|
||||
|
||||
|
||||
|
||||
|
||||
function errorFunc(reason: Utf8ErrorReason, offset: number, bytes: ArrayLike<number>, output: Array<number>, badCodepoint?: number): number {
|
||||
return logger.throwArgumentError(`invalid codepoint at offset ${ offset }; ${ reason }`, "bytes", bytes);
|
||||
return throwArgumentError(`invalid codepoint at offset ${ offset }; ${ reason }`, "bytes", bytes);
|
||||
}
|
||||
|
||||
function ignoreFunc(reason: Utf8ErrorReason, offset: number, bytes: ArrayLike<number>, output: Array<number>, badCodepoint?: number): number {
|
||||
@ -94,7 +98,7 @@ export const Utf8ErrorFuncs: Readonly<Record<"error" | "ignore" | "replace", Utf
|
||||
function getUtf8CodePoints(_bytes: BytesLike, onError?: Utf8ErrorFunc): Array<number> {
|
||||
if (onError == null) { onError = Utf8ErrorFuncs.error; }
|
||||
|
||||
const bytes = logger.getBytes(_bytes, "bytes");
|
||||
const bytes = getBytes(_bytes, "bytes");
|
||||
|
||||
const result: Array<number> = [];
|
||||
let i = 0;
|
||||
@ -192,7 +196,7 @@ function getUtf8CodePoints(_bytes: BytesLike, onError?: Utf8ErrorFunc): Array<nu
|
||||
export function toUtf8Bytes(str: string, form?: UnicodeNormalizationForm): Uint8Array {
|
||||
|
||||
if (form != null) {
|
||||
logger.assertNormalize(form);
|
||||
assertNormalize(form);
|
||||
str = str.normalize(form);
|
||||
}
|
||||
|
||||
@ -232,7 +236,7 @@ export function toUtf8Bytes(str: string, form?: UnicodeNormalizationForm): Uint8
|
||||
return new Uint8Array(result);
|
||||
};
|
||||
|
||||
function escapeChar(value: number) {
|
||||
function escapeChar(value: number): string {
|
||||
const hex = ("0000" + value.toString(16));
|
||||
return "\\u" + hex.substring(hex.length - 4);
|
||||
}
|
||||
@ -283,3 +287,4 @@ export function toUtf8String(bytes: BytesLike, onError?: Utf8ErrorFunc): string
|
||||
export function toUtf8CodePoints(str: string, form?: UnicodeNormalizationForm): Array<number> {
|
||||
return getUtf8CodePoints(toUtf8Bytes(str, form));
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,9 @@ import { getAddress, resolveAddress } from "../address/index.js";
|
||||
import { hashMessage, TypedDataEncoder } from "../hash/index.js";
|
||||
import { AbstractSigner } from "../providers/index.js";
|
||||
import { computeAddress, Transaction } from "../transaction/index.js";
|
||||
import { defineProperties, logger, resolveProperties } from "../utils/index.js";
|
||||
import {
|
||||
defineProperties, resolveProperties, throwArgumentError, throwError
|
||||
} from "../utils/index.js";
|
||||
|
||||
import type { SigningKey } from "../crypto/index.js";
|
||||
import type { TypedDataDomain, TypedDataField } from "../hash/index.js";
|
||||
@ -42,7 +44,7 @@ export class BaseWallet extends AbstractSigner {
|
||||
|
||||
if (tx.from != null) {
|
||||
if (getAddress(tx.from) !== this.address) {
|
||||
logger.throwArgumentError("transaction from address mismatch", "tx.from", _tx.from);
|
||||
throwArgumentError("transaction from address mismatch", "tx.from", _tx.from);
|
||||
}
|
||||
delete tx.from;
|
||||
}
|
||||
@ -63,7 +65,7 @@ export class BaseWallet extends AbstractSigner {
|
||||
// Populate any ENS names
|
||||
const populated = await TypedDataEncoder.resolveNames(domain, types, value, async (name: string) => {
|
||||
if (this.provider == null) {
|
||||
return logger.throwError("cannot resolve ENS names without a provider", "UNSUPPORTED_OPERATION", {
|
||||
return throwError("cannot resolve ENS names without a provider", "UNSUPPORTED_OPERATION", {
|
||||
operation: "resolveName",
|
||||
info: { name }
|
||||
});
|
||||
@ -71,7 +73,7 @@ export class BaseWallet extends AbstractSigner {
|
||||
|
||||
const address = await this.provider.resolveName(name);
|
||||
if (address == null) {
|
||||
return logger.throwError("unconfigured ENS name", "UNCONFIGURED_NAME", {
|
||||
return throwError("unconfigured ENS name", "UNCONFIGURED_NAME", {
|
||||
value: name
|
||||
});
|
||||
}
|
||||
|
@ -2,7 +2,10 @@ import { computeHmac, randomBytes, ripemd160, SigningKey, sha256 } from "../cryp
|
||||
import { VoidSigner } from "../providers/index.js";
|
||||
import { computeAddress } from "../transaction/index.js";
|
||||
import {
|
||||
concat, dataSlice, decodeBase58, defineProperties, encodeBase58, hexlify, logger, toBigInt, toHex
|
||||
concat, dataSlice, decodeBase58, defineProperties, encodeBase58,
|
||||
getBytes, hexlify,
|
||||
getNumber, toBigInt, toHex,
|
||||
assertPrivate, throwArgumentError, throwError
|
||||
} from "../utils/index.js";
|
||||
import { langEn } from "../wordlists/lang-en.js";
|
||||
|
||||
@ -36,7 +39,7 @@ function zpad(value: number, length: number): string {
|
||||
}
|
||||
|
||||
function encodeBase58Check(_value: BytesLike): string {
|
||||
const value = logger.getBytes(_value);
|
||||
const value = getBytes(_value);
|
||||
const check = dataSlice(sha256(sha256(value)), 0, 4);
|
||||
const bytes = concat([ value, check ]);
|
||||
return encodeBase58(bytes);
|
||||
@ -49,22 +52,22 @@ function ser_I(index: number, chainCode: string, publicKey: string, privateKey:
|
||||
|
||||
if (index & HardenedBit) {
|
||||
if (privateKey == null) {
|
||||
return logger.throwError("cannot derive child of neutered node", "UNSUPPORTED_OPERATION", {
|
||||
return throwError("cannot derive child of neutered node", "UNSUPPORTED_OPERATION", {
|
||||
operation: "deriveChild"
|
||||
});
|
||||
}
|
||||
|
||||
// Data = 0x00 || ser_256(k_par)
|
||||
data.set(logger.getBytes(privateKey), 1);
|
||||
data.set(getBytes(privateKey), 1);
|
||||
|
||||
} else {
|
||||
// Data = ser_p(point(k_par))
|
||||
data.set(logger.getBytes(publicKey));
|
||||
data.set(getBytes(publicKey));
|
||||
}
|
||||
|
||||
// Data += ser_32(i)
|
||||
for (let i = 24; i >= 0; i -= 8) { data[33 + (i >> 3)] = ((index >> (24 - i)) & 0xff); }
|
||||
const I = logger.getBytes(computeHmac("sha512", chainCode, data));
|
||||
const I = getBytes(computeHmac("sha512", chainCode, data));
|
||||
|
||||
return { IL: I.slice(0, 32), IR: I.slice(32) };
|
||||
}
|
||||
@ -122,7 +125,7 @@ export class HDNodeWallet extends BaseWallet {
|
||||
|
||||
constructor(guard: any, signingKey: SigningKey, parentFingerprint: string, chainCode: string, path: null | string, index: number, depth: number, mnemonic: null | Mnemonic, provider: null | Provider) {
|
||||
super(signingKey, provider);
|
||||
logger.assertPrivate(guard, _guard, "HDNodeWallet");
|
||||
assertPrivate(guard, _guard, "HDNodeWallet");
|
||||
|
||||
defineProperties<HDNodeWallet>(this, { publicKey: signingKey.compressedPublicKey });
|
||||
|
||||
@ -165,7 +168,7 @@ export class HDNodeWallet extends BaseWallet {
|
||||
}
|
||||
|
||||
deriveChild(_index: Numeric): HDNodeWallet {
|
||||
const index = logger.getNumber(_index, "index");
|
||||
const index = getNumber(_index, "index");
|
||||
if (index > 0xffffffff) { throw new Error("invalid index - " + String(index)); }
|
||||
|
||||
// Base path
|
||||
@ -188,12 +191,12 @@ export class HDNodeWallet extends BaseWallet {
|
||||
}
|
||||
|
||||
static #fromSeed(_seed: BytesLike, mnemonic: null | Mnemonic): HDNodeWallet {
|
||||
const seed = logger.getBytes(_seed, "seed");
|
||||
const seed = getBytes(_seed, "seed");
|
||||
if (seed.length < 16 || seed.length > 64) {
|
||||
throw new Error("invalid seed");
|
||||
}
|
||||
|
||||
const I = logger.getBytes(computeHmac("sha512", MasterSecret, seed));
|
||||
const I = getBytes(computeHmac("sha512", MasterSecret, seed));
|
||||
const signingKey = new SigningKey(hexlify(I.slice(0, 32)));
|
||||
|
||||
return new HDNodeWallet(_guard, signingKey, "0x00000000", hexlify(I.slice(32)),
|
||||
@ -204,7 +207,7 @@ export class HDNodeWallet extends BaseWallet {
|
||||
return HDNodeWallet.#fromSeed(seed, null);
|
||||
}
|
||||
|
||||
static fromPhrase(phrase: string, password = "", path: null | string = defaultPath, wordlist: Wordlist = langEn): HDNodeWallet {
|
||||
static fromPhrase(phrase: string, password: string = "", path: null | string = defaultPath, wordlist: Wordlist = langEn): HDNodeWallet {
|
||||
if (!path) { path = defaultPath; }
|
||||
const mnemonic = Mnemonic.fromPhrase(phrase, password, wordlist)
|
||||
return HDNodeWallet.#fromSeed(mnemonic.computeSeed(), mnemonic).derivePath(path);
|
||||
@ -216,10 +219,10 @@ export class HDNodeWallet extends BaseWallet {
|
||||
}
|
||||
|
||||
static fromExtendedKey(extendedKey: string): HDNodeWallet | HDNodeVoidWallet {
|
||||
const bytes = logger.getBytes(decodeBase58(extendedKey)); // @TODO: redact
|
||||
const bytes = getBytes(decodeBase58(extendedKey)); // @TODO: redact
|
||||
|
||||
if (bytes.length !== 82 || encodeBase58Check(bytes.slice(0, 78)) !== extendedKey) {
|
||||
logger.throwArgumentError("invalid extended key", "extendedKey", "[ REDACTED ]");
|
||||
throwArgumentError("invalid extended key", "extendedKey", "[ REDACTED ]");
|
||||
}
|
||||
|
||||
const depth = bytes[4];
|
||||
@ -244,10 +247,10 @@ export class HDNodeWallet extends BaseWallet {
|
||||
}
|
||||
|
||||
|
||||
return logger.throwArgumentError("invalid extended key prefix", "extendedKey", "[ REDACTED ]");
|
||||
return throwArgumentError("invalid extended key prefix", "extendedKey", "[ REDACTED ]");
|
||||
}
|
||||
|
||||
static createRandom(password = "", path: null | string = defaultPath, wordlist: Wordlist = langEn): HDNodeWallet {
|
||||
static createRandom(password: string = "", path: null | string = defaultPath, wordlist: Wordlist = langEn): HDNodeWallet {
|
||||
if (!path) { path = defaultPath; }
|
||||
const mnemonic = Mnemonic.fromEntropy(randomBytes(16), password, wordlist)
|
||||
return HDNodeWallet.#fromSeed(mnemonic.computeSeed(), mnemonic).derivePath(path);
|
||||
@ -268,7 +271,7 @@ export class HDNodeVoidWallet extends VoidSigner {
|
||||
|
||||
constructor(guard: any, address: string, publicKey: string, parentFingerprint: string, chainCode: string, path: null | string, index: number, depth: number, provider: null | Provider) {
|
||||
super(address, provider);
|
||||
logger.assertPrivate(guard, _guard, "HDNodeVoidWallet");
|
||||
assertPrivate(guard, _guard, "HDNodeVoidWallet");
|
||||
|
||||
defineProperties<HDNodeVoidWallet>(this, { publicKey });
|
||||
|
||||
@ -305,7 +308,7 @@ export class HDNodeVoidWallet extends VoidSigner {
|
||||
hasPath(): this is { path: string } { return (this.path != null); }
|
||||
|
||||
deriveChild(_index: Numeric): HDNodeVoidWallet {
|
||||
const index = logger.getNumber(_index, "index");
|
||||
const index = getNumber(_index, "index");
|
||||
if (index > 0xffffffff) { throw new Error("invalid index - " + String(index)); }
|
||||
|
||||
// Base path
|
||||
@ -333,19 +336,19 @@ export class HDNodeVoidWallet extends VoidSigner {
|
||||
export class HDNodeWalletManager {
|
||||
#root: HDNodeWallet;
|
||||
|
||||
constructor(phrase: string, password = "", path = "m/44'/60'/0'/0", locale: Wordlist = langEn) {
|
||||
constructor(phrase: string, password: string = "", path: string = "m/44'/60'/0'/0", locale: Wordlist = langEn) {
|
||||
this.#root = HDNodeWallet.fromPhrase(phrase, password, path, locale);
|
||||
}
|
||||
|
||||
getSigner(index = 0): HDNodeWallet {
|
||||
return this.#root.deriveChild(index);
|
||||
getSigner(index?: number): HDNodeWallet {
|
||||
return this.#root.deriveChild((index == null) ? 0: index);
|
||||
}
|
||||
}
|
||||
|
||||
export function getAccountPath(_index: Numeric): string {
|
||||
const index = logger.getNumber(_index, "index");
|
||||
const index = getNumber(_index, "index");
|
||||
if (index < 0 || index >= HardenedBit) {
|
||||
logger.throwArgumentError("invalid account index", "index", index);
|
||||
throwArgumentError("invalid account index", "index", index);
|
||||
}
|
||||
return `m/44'/60'/${ index }'/0/0`;
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import { CBC, pkcs7Strip } from "aes-js";
|
||||
import { getAddress } from "../address/index.js";
|
||||
import { pbkdf2 } from "../crypto/index.js";
|
||||
import { id } from "../hash/id.js";
|
||||
import { logger } from "../utils/index.js";
|
||||
import { getBytes, throwArgumentError } from "../utils/index.js";
|
||||
|
||||
import { getPassword, looseArrayify, spelunk } from "./utils.js";
|
||||
|
||||
@ -32,17 +32,17 @@ export function decryptCrowdsaleJson(json: string, _password: string | Uint8Arra
|
||||
// Encrypted Seed
|
||||
const encseed = looseArrayify(spelunk(data, "encseed:string!"));
|
||||
if (!encseed || (encseed.length % 16) !== 0) {
|
||||
logger.throwArgumentError("invalid encseed", "json", json);
|
||||
throwArgumentError("invalid encseed", "json", json);
|
||||
}
|
||||
|
||||
const key = logger.getBytes(pbkdf2(password, password, 2000, 32, "sha256")).slice(0, 16);
|
||||
const key = getBytes(pbkdf2(password, password, 2000, 32, "sha256")).slice(0, 16);
|
||||
|
||||
const iv = encseed.slice(0, 16);
|
||||
const encryptedSeed = encseed.slice(16);
|
||||
|
||||
// Decrypt the seed
|
||||
const aesCbc = new CBC(key, iv);
|
||||
const seed = pkcs7Strip(logger.getBytes(aesCbc.decrypt(encryptedSeed)));
|
||||
const seed = pkcs7Strip(getBytes(aesCbc.decrypt(encryptedSeed)));
|
||||
|
||||
// This wallet format is weird... Convert the binary encoded hex to a string.
|
||||
let seedHex = "";
|
||||
|
@ -3,7 +3,9 @@ import { CTR } from "aes-js";
|
||||
import { getAddress } from "../address/index.js";
|
||||
import { keccak256, pbkdf2, randomBytes, scrypt, scryptSync } from "../crypto/index.js";
|
||||
import { computeAddress } from "../transaction/index.js";
|
||||
import { concat, hexlify, logger } from "../utils/index.js";
|
||||
import {
|
||||
concat, getBytes, hexlify, throwArgumentError, throwError
|
||||
} from "../utils/index.js";
|
||||
|
||||
import { getPassword, spelunk, uuidV4, zpad } from "./utils.js";
|
||||
|
||||
@ -65,18 +67,18 @@ function decrypt(data: any, key: Uint8Array, ciphertext: Uint8Array): string {
|
||||
return hexlify(aesCtr.decrypt(ciphertext));
|
||||
}
|
||||
|
||||
return logger.throwError("unsupported cipher", "UNSUPPORTED_OPERATION", {
|
||||
return throwError("unsupported cipher", "UNSUPPORTED_OPERATION", {
|
||||
operation: "decrypt"
|
||||
});
|
||||
}
|
||||
|
||||
function getAccount(data: any, _key: string): KeystoreAccount {
|
||||
const key = logger.getBytes(_key);
|
||||
const key = getBytes(_key);
|
||||
const ciphertext = spelunk<Uint8Array>(data, "crypto.ciphertext:data!");
|
||||
|
||||
const computedMAC = hexlify(keccak256(concat([ key.slice(16, 32), ciphertext ]))).substring(2);
|
||||
if (computedMAC !== spelunk(data, "crypto.mac:string!").toLowerCase()) {
|
||||
return logger.throwArgumentError("incorrect password", "password", "[ REDACTED ]");
|
||||
return throwArgumentError("incorrect password", "password", "[ REDACTED ]");
|
||||
}
|
||||
|
||||
const privateKey = decrypt(data, key.slice(0, 16), ciphertext);
|
||||
@ -87,7 +89,7 @@ function getAccount(data: any, _key: string): KeystoreAccount {
|
||||
if (check.substring(0, 2) !== "0x") { check = "0x" + check; }
|
||||
|
||||
if (getAddress(check) !== address) {
|
||||
logger.throwArgumentError("keystore address/privateKey mismatch", "address", data.address);
|
||||
throwArgumentError("keystore address/privateKey mismatch", "address", data.address);
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,7 +108,7 @@ function getAccount(data: any, _key: string): KeystoreAccount {
|
||||
account.mnemonic = {
|
||||
path: (spelunk<null | string>(data, "x-ethers.path:string") || defaultPath),
|
||||
locale: (spelunk<null | string>(data, "x-ethers.locale:string") || "en"),
|
||||
entropy: hexlify(logger.getBytes(mnemonicAesCtr.decrypt(mnemonicCiphertext)))
|
||||
entropy: hexlify(getBytes(mnemonicAesCtr.decrypt(mnemonicCiphertext)))
|
||||
};
|
||||
}
|
||||
|
||||
@ -132,7 +134,7 @@ function getKdfParams<T>(data: any): KdfParams {
|
||||
const kdf = spelunk(data, "crypto.kdf:string");
|
||||
if (kdf && typeof(kdf) === "string") {
|
||||
const throwError = function(name: string, value: any): never {
|
||||
return logger.throwArgumentError("invalid key-derivation function parameters", name, value);
|
||||
return throwArgumentError("invalid key-derivation function parameters", name, value);
|
||||
}
|
||||
|
||||
if (kdf.toLowerCase() === "scrypt") {
|
||||
@ -171,7 +173,7 @@ function getKdfParams<T>(data: any): KdfParams {
|
||||
}
|
||||
}
|
||||
|
||||
return logger.throwArgumentError("unsupported key-derivation function", "kdf", kdf);
|
||||
return throwArgumentError("unsupported key-derivation function", "kdf", kdf);
|
||||
}
|
||||
|
||||
|
||||
@ -252,7 +254,7 @@ export async function encryptKeystoreJson(account: KeystoreAccount, password: st
|
||||
}
|
||||
if (!options) { options = {}; }
|
||||
|
||||
const privateKey = logger.getBytes(account.privateKey, "privateKey");
|
||||
const privateKey = getBytes(account.privateKey, "privateKey");
|
||||
const passwordBytes = getPassword(password);
|
||||
|
||||
/*
|
||||
@ -269,18 +271,18 @@ export async function encryptKeystoreJson(account: KeystoreAccount, password: st
|
||||
}
|
||||
*/
|
||||
// Check/generate the salt
|
||||
const salt = (options.salt != null) ? logger.getBytes(options.salt, "options.slat"): randomBytes(32);
|
||||
const salt = (options.salt != null) ? getBytes(options.salt, "options.slat"): randomBytes(32);
|
||||
|
||||
// Override initialization vector
|
||||
const iv = (options.iv != null) ? logger.getBytes(options.iv, "options.iv"): randomBytes(16);
|
||||
const iv = (options.iv != null) ? getBytes(options.iv, "options.iv"): randomBytes(16);
|
||||
if (iv.length !== 16) {
|
||||
logger.throwArgumentError("invalid options.iv", "options.iv", options.iv);
|
||||
throwArgumentError("invalid options.iv", "options.iv", options.iv);
|
||||
}
|
||||
|
||||
// Override the uuid
|
||||
const uuidRandom = (options.uuid != null) ? logger.getBytes(options.uuid, "options.uuid"): randomBytes(16);
|
||||
const uuidRandom = (options.uuid != null) ? getBytes(options.uuid, "options.uuid"): randomBytes(16);
|
||||
if (uuidRandom.length !== 16) {
|
||||
logger.throwArgumentError("invalid options.uuid", "options.uuid", options.iv);
|
||||
throwArgumentError("invalid options.uuid", "options.uuid", options.iv);
|
||||
}
|
||||
if (uuidRandom.length !== 16) { throw new Error("invalid uuid"); }
|
||||
|
||||
@ -296,7 +298,7 @@ export async function encryptKeystoreJson(account: KeystoreAccount, password: st
|
||||
// - 32 bytes As normal for the Web3 secret storage (derivedKey, macPrefix)
|
||||
// - 32 bytes AES key to encrypt mnemonic with (required here to be Ethers Wallet)
|
||||
const _key = await scrypt(passwordBytes, salt, N, r, p, 64, progressCallback);
|
||||
const key = logger.getBytes(_key);
|
||||
const key = getBytes(_key);
|
||||
|
||||
// This will be used to encrypt the wallet (as per Web3 secret storage)
|
||||
const derivedKey = key.slice(0, 16);
|
||||
@ -304,7 +306,7 @@ export async function encryptKeystoreJson(account: KeystoreAccount, password: st
|
||||
|
||||
// Encrypt the private key
|
||||
const aesCtr = new CTR(derivedKey, iv);
|
||||
const ciphertext = logger.getBytes(aesCtr.encrypt(privateKey));
|
||||
const ciphertext = getBytes(aesCtr.encrypt(privateKey));
|
||||
|
||||
// Compute the message authentication code, used to check the password
|
||||
const mac = keccak256(concat([ macPrefix, ciphertext ]))
|
||||
@ -341,10 +343,10 @@ export async function encryptKeystoreJson(account: KeystoreAccount, password: st
|
||||
|
||||
const mnemonicKey = key.slice(32, 64);
|
||||
|
||||
const entropy = logger.getBytes(account.mnemonic.entropy, "account.mnemonic.entropy");
|
||||
const entropy = getBytes(account.mnemonic.entropy, "account.mnemonic.entropy");
|
||||
const mnemonicIv = randomBytes(16);
|
||||
const mnemonicAesCtr = new CTR(mnemonicKey, mnemonicIv);
|
||||
const mnemonicCiphertext = logger.getBytes(mnemonicAesCtr.encrypt(entropy));
|
||||
const mnemonicCiphertext = getBytes(mnemonicAesCtr.encrypt(entropy));
|
||||
|
||||
const now = new Date();
|
||||
const timestamp = (now.getUTCFullYear() + "-" +
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { pbkdf2, sha256 } from "../crypto/index.js";
|
||||
import { defineProperties, hexlify, logger, toUtf8Bytes } from "../utils/index.js";
|
||||
import {
|
||||
defineProperties, getBytes, hexlify, assertNormalize, assertPrivate, throwArgumentError, toUtf8Bytes
|
||||
} from "../utils/index.js";
|
||||
import { langEn } from "../wordlists/lang-en.js";
|
||||
|
||||
import type { BytesLike } from "../utils/index.js";
|
||||
@ -18,13 +20,13 @@ function getLowerMask(bits: number): number {
|
||||
|
||||
|
||||
function mnemonicToEntropy(mnemonic: string, wordlist: null | Wordlist = langEn): string {
|
||||
logger.assertNormalize("NFKD");
|
||||
assertNormalize("NFKD");
|
||||
|
||||
if (wordlist == null) { wordlist = langEn; }
|
||||
|
||||
const words = wordlist.split(mnemonic);
|
||||
if ((words.length % 3) !== 0 || words.length < 12 || words.length > 24) {
|
||||
logger.throwArgumentError("invalid mnemonic length", "mnemonic", "[ REDACTED ]");
|
||||
throwArgumentError("invalid mnemonic length", "mnemonic", "[ REDACTED ]");
|
||||
}
|
||||
|
||||
const entropy = new Uint8Array(Math.ceil(11 * words.length / 8));
|
||||
@ -33,7 +35,7 @@ function mnemonicToEntropy(mnemonic: string, wordlist: null | Wordlist = langEn)
|
||||
for (let i = 0; i < words.length; i++) {
|
||||
let index = wordlist.getWordIndex(words[i].normalize("NFKD"));
|
||||
if (index === -1) {
|
||||
logger.throwArgumentError(`invalid mnemonic word at index ${ i }`, "mnemonic", "[ REDACTED ]");
|
||||
throwArgumentError(`invalid mnemonic word at index ${ i }`, "mnemonic", "[ REDACTED ]");
|
||||
}
|
||||
|
||||
for (let bit = 0; bit < 11; bit++) {
|
||||
@ -50,10 +52,10 @@ function mnemonicToEntropy(mnemonic: string, wordlist: null | Wordlist = langEn)
|
||||
const checksumBits = words.length / 3;
|
||||
const checksumMask = getUpperMask(checksumBits);
|
||||
|
||||
const checksum = logger.getBytes(sha256(entropy.slice(0, entropyBits / 8)))[0] & checksumMask;
|
||||
const checksum = getBytes(sha256(entropy.slice(0, entropyBits / 8)))[0] & checksumMask;
|
||||
|
||||
if (checksum !== (entropy[entropy.length - 1] & checksumMask)) {
|
||||
logger.throwArgumentError("invalid mnemonic checksum", "mnemonic", "[ REDACTED ]");
|
||||
throwArgumentError("invalid mnemonic checksum", "mnemonic", "[ REDACTED ]");
|
||||
}
|
||||
|
||||
return hexlify(entropy.slice(0, entropyBits / 8));
|
||||
@ -61,7 +63,7 @@ function mnemonicToEntropy(mnemonic: string, wordlist: null | Wordlist = langEn)
|
||||
|
||||
function entropyToMnemonic(entropy: Uint8Array, wordlist: null | Wordlist = langEn): string {
|
||||
if ((entropy.length % 4) || entropy.length < 16 || entropy.length > 32) {
|
||||
logger.throwArgumentError("invalid entropy size", "entropy", "[ REDACTED ]");
|
||||
throwArgumentError("invalid entropy size", "entropy", "[ REDACTED ]");
|
||||
}
|
||||
|
||||
if (wordlist == null) { wordlist = langEn; }
|
||||
@ -113,7 +115,7 @@ export class Mnemonic {
|
||||
constructor(guard: any, entropy: string, phrase: string, password?: null | string, wordlist?: null | Wordlist) {
|
||||
if (password == null) { password = ""; }
|
||||
if (wordlist == null) { wordlist = langEn; }
|
||||
logger.assertPrivate(guard, _guard, "Mnemonic");
|
||||
assertPrivate(guard, _guard, "Mnemonic");
|
||||
defineProperties<Mnemonic>(this, { phrase, password, wordlist, entropy });
|
||||
}
|
||||
|
||||
@ -122,21 +124,21 @@ export class Mnemonic {
|
||||
return pbkdf2(toUtf8Bytes(this.phrase, "NFKD"), salt, 2048, 64, "sha512");
|
||||
}
|
||||
|
||||
static fromPhrase(phrase: string, password?: null | string, wordlist?: null | Wordlist) {
|
||||
static fromPhrase(phrase: string, password?: null | string, wordlist?: null | Wordlist): Mnemonic {
|
||||
// Normalize the case and space; throws if invalid
|
||||
const entropy = mnemonicToEntropy(phrase, wordlist);
|
||||
phrase = entropyToMnemonic(logger.getBytes(entropy), wordlist);
|
||||
phrase = entropyToMnemonic(getBytes(entropy), wordlist);
|
||||
return new Mnemonic(_guard, entropy, phrase, password, wordlist);
|
||||
}
|
||||
|
||||
static fromEntropy(_entropy: BytesLike, password?: null | string, wordlist?: null | Wordlist): Mnemonic {
|
||||
const entropy = logger.getBytes(_entropy, "entropy");
|
||||
const entropy = getBytes(_entropy, "entropy");
|
||||
const phrase = entropyToMnemonic(entropy, wordlist);
|
||||
return new Mnemonic(_guard, hexlify(entropy), phrase, password, wordlist);
|
||||
}
|
||||
|
||||
static entropyToPhrase(_entropy: BytesLike, wordlist?: null | Wordlist): string {
|
||||
const entropy = logger.getBytes(_entropy, "entropy");
|
||||
const entropy = getBytes(_entropy, "entropy");
|
||||
return entropyToMnemonic(entropy, wordlist);
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
import { hexlify, logger, toUtf8Bytes } from "../utils/index.js";
|
||||
import {
|
||||
getBytes, getBytesCopy, hexlify, throwArgumentError, toUtf8Bytes
|
||||
} from "../utils/index.js";
|
||||
|
||||
import type { BytesLike } from "../utils/index.js";
|
||||
|
||||
@ -7,7 +9,7 @@ export function looseArrayify(hexString: string): Uint8Array {
|
||||
if (typeof(hexString) === 'string' && hexString.substring(0, 2) !== '0x') {
|
||||
hexString = '0x' + hexString;
|
||||
}
|
||||
return logger.getBytesCopy(hexString);
|
||||
return getBytesCopy(hexString);
|
||||
}
|
||||
|
||||
export function zpad(value: String | number, length: number): String {
|
||||
@ -20,14 +22,14 @@ export function getPassword(password: string | Uint8Array): Uint8Array {
|
||||
if (typeof(password) === 'string') {
|
||||
return toUtf8Bytes(password, "NFKC");
|
||||
}
|
||||
return logger.getBytesCopy(password);
|
||||
return getBytesCopy(password);
|
||||
}
|
||||
|
||||
export function spelunk<T = string>(object: any, _path: string): T {
|
||||
|
||||
const match = _path.match(/^([a-z0-9$_.-]*)(:([a-z]+))?(!)?$/i);
|
||||
if (match == null) {
|
||||
return logger.throwArgumentError("invalid path", "path", _path);
|
||||
return throwArgumentError("invalid path", "path", _path);
|
||||
}
|
||||
const path = match[1];
|
||||
const type = match[3];
|
||||
@ -59,7 +61,7 @@ export function spelunk<T = string>(object: any, _path: string): T {
|
||||
}
|
||||
|
||||
if (reqd && cur == null) {
|
||||
logger.throwArgumentError("missing required value", "path", path);
|
||||
throwArgumentError("missing required value", "path", path);
|
||||
}
|
||||
|
||||
if (type && cur != null) {
|
||||
@ -84,7 +86,7 @@ export function spelunk<T = string>(object: any, _path: string): T {
|
||||
if (type === "array" && Array.isArray(cur)) { return <T><unknown>cur; }
|
||||
if (type === typeof(cur)) { return cur; }
|
||||
|
||||
logger.throwArgumentError(`wrong type found for ${ type } `, "path", path);
|
||||
throwArgumentError(`wrong type found for ${ type } `, "path", path);
|
||||
}
|
||||
|
||||
return cur;
|
||||
@ -122,7 +124,7 @@ export function followRequired(data: any, path: string): string {
|
||||
*/
|
||||
// See: https://www.ietf.org/rfc/rfc4122.txt (Section 4.4)
|
||||
export function uuidV4(randomBytes: BytesLike): string {
|
||||
const bytes = logger.getBytes(randomBytes, "randomBytes");
|
||||
const bytes = getBytes(randomBytes, "randomBytes");
|
||||
|
||||
// Section: 4.1.3:
|
||||
// - time_hi_and_version[12:16] = 0b0100
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { randomBytes, SigningKey } from "../crypto/index.js";
|
||||
import { computeAddress } from "../transaction/index.js";
|
||||
import { isHexString, logger } from "../utils/index.js";
|
||||
import { isHexString, throwArgumentError } from "../utils/index.js";
|
||||
|
||||
import { BaseWallet } from "./base-wallet.js";
|
||||
import { HDNodeWallet } from "./hdwallet.js";
|
||||
@ -90,7 +90,7 @@ export class Wallet extends BaseWallet {
|
||||
if (signingKey == null) { signingKey = trySigningKey(key); }
|
||||
|
||||
if (signingKey == null) {
|
||||
logger.throwArgumentError("invalid key", "key", "[ REDACTED ]");
|
||||
throwArgumentError("invalid key", "key", "[ REDACTED ]");
|
||||
}
|
||||
|
||||
super(signingKey as SigningKey, provider);
|
||||
@ -123,12 +123,12 @@ export class Wallet extends BaseWallet {
|
||||
if (progress) { progress(1); await stall(0); }
|
||||
|
||||
} else {
|
||||
return logger.throwArgumentError("invalid JSON wallet", "json", "[ REDACTED ]");
|
||||
return throwArgumentError("invalid JSON wallet", "json", "[ REDACTED ]");
|
||||
}
|
||||
|
||||
const wallet = new Wallet(account.privateKey);
|
||||
if (wallet.address !== account.address) {
|
||||
logger.throwArgumentError("address/privateKey mismatch", "json", "[ REDACTED ]");
|
||||
throwArgumentError("address/privateKey mismatch", "json", "[ REDACTED ]");
|
||||
}
|
||||
// @TODO: mnemonic
|
||||
return wallet;
|
||||
@ -141,12 +141,12 @@ export class Wallet extends BaseWallet {
|
||||
} else if (isCrowdsaleJson(json)) {
|
||||
account = decryptCrowdsaleJson(json, password);
|
||||
} else {
|
||||
return logger.throwArgumentError("invalid JSON wallet", "json", "[ REDACTED ]");
|
||||
return throwArgumentError("invalid JSON wallet", "json", "[ REDACTED ]");
|
||||
}
|
||||
|
||||
const wallet = new Wallet(account.privateKey);
|
||||
if (wallet.address !== account.address) {
|
||||
logger.throwArgumentError("address/privateKey mismatch", "json", "[ REDACTED ]");
|
||||
throwArgumentError("address/privateKey mismatch", "json", "[ REDACTED ]");
|
||||
}
|
||||
// @TODO: mnemonic
|
||||
return wallet;
|
||||
@ -160,7 +160,8 @@ export class Wallet extends BaseWallet {
|
||||
return new Wallet(mnemonic, provider);
|
||||
}
|
||||
|
||||
static fromPhrase(phrase: string, provider?: null | Provider, password = "", wordlist?: Wordlist): Wallet {
|
||||
static fromPhrase(phrase: string, provider?: null | Provider, password?: string, wordlist?: Wordlist): Wallet {
|
||||
if (password == null) { password = ""; }
|
||||
return new Wallet(Mnemonic.fromPhrase(phrase, password, wordlist), provider);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { assertArgument } from "../utils/logger.js";
|
||||
import { assertArgument } from "../utils/index.js";
|
||||
|
||||
|
||||
const subsChrs = " !#$%&'()*+,-./<=>?@[]^_`{|}~";
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { assertArgument } from "../utils/logger.js";
|
||||
import { assertArgument } from "../utils/index.js";
|
||||
|
||||
import { decodeBits } from "./bit-reader.js";
|
||||
import { decodeOwl } from "./decode-owl.js";
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { id } from "../hash/id.js";
|
||||
import { hexlify, logger, toUtf8Bytes, toUtf8String } from "../utils/index.js";
|
||||
import {
|
||||
hexlify, throwArgumentError, toUtf8Bytes, toUtf8String
|
||||
} from "../utils/index.js";
|
||||
|
||||
import { Wordlist } from "./wordlist.js";
|
||||
|
||||
@ -135,7 +137,7 @@ class LangJa extends Wordlist {
|
||||
getWord(index: number): string {
|
||||
const words = loadWords();
|
||||
if (index < 0 || index >= words.length) {
|
||||
logger.throwArgumentError(`invalid word index: ${ index }`, "index", index);
|
||||
throwArgumentError(`invalid word index: ${ index }`, "index", index);
|
||||
}
|
||||
return words[index];
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { id } from "../hash/id.js";
|
||||
import { logger, toUtf8String } from "../utils/index.js";
|
||||
import { throwArgumentError, toUtf8String } from "../utils/index.js";
|
||||
|
||||
import { Wordlist } from "./wordlist.js";
|
||||
|
||||
@ -70,7 +70,7 @@ class LangKo extends Wordlist {
|
||||
getWord(index: number): string {
|
||||
const words = loadWords();
|
||||
if (index < 0 || index >= words.length) {
|
||||
logger.throwArgumentError(`invalid word index: ${ index }`, "index", index);
|
||||
throwArgumentError(`invalid word index: ${ index }`, "index", index);
|
||||
}
|
||||
return words[index];
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { id } from "../hash/index.js";
|
||||
import { toUtf8String, logger } from "../utils/index.js";
|
||||
import { throwArgumentError, toUtf8String } from "../utils/index.js";
|
||||
|
||||
import { Wordlist } from "./wordlist.js";
|
||||
|
||||
@ -64,7 +64,7 @@ class LangZh extends Wordlist {
|
||||
getWord(index: number): string {
|
||||
const words = loadWords(this.locale);
|
||||
if (index < 0 || index >= words.length) {
|
||||
logger.throwArgumentError(`invalid word index: ${ index }`, "index", index);
|
||||
throwArgumentError(`invalid word index: ${ index }`, "index", index);
|
||||
}
|
||||
return words[index];
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
// data files to be consumed by this class
|
||||
|
||||
import { id } from "../hash/id.js";
|
||||
import { logger } from "../utils/logger.js";
|
||||
import { throwArgumentError } from "../utils/index.js";
|
||||
|
||||
import { decodeOwl } from "./decode-owl.js";
|
||||
import { Wordlist } from "./wordlist.js";
|
||||
@ -46,7 +46,7 @@ export class WordlistOwl extends Wordlist {
|
||||
getWord(index: number): string {
|
||||
const words = this.#loadWords();
|
||||
if (index < 0 || index >= words.length) {
|
||||
logger.throwArgumentError(`invalid word index: ${ index }`, "index", index);
|
||||
throwArgumentError(`invalid word index: ${ index }`, "index", index);
|
||||
}
|
||||
return words[index];
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user