Replaced logger class with simpler functions.

This commit is contained in:
Richard Moore 2022-09-08 23:21:08 -04:00
parent 2740976d8b
commit 29949a6309
74 changed files with 886 additions and 823 deletions

@ -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];
}