Converted throwArgumentError to assertArgument.

This commit is contained in:
Richard Moore 2022-10-25 04:06:00 -04:00
parent 17ac965b12
commit e5c068c395
53 changed files with 297 additions and 528 deletions

@ -1,6 +1,6 @@
// See: https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI // See: https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
import { assertArgumentCount, throwArgumentError } from "../utils/index.js"; import { assertArgumentCount, assertArgument } from "../utils/index.js";
import { Coder, Reader, Result, Writer } from "./coders/abstract-coder.js"; import { Coder, Reader, Result, Writer } from "./coders/abstract-coder.js";
import { AddressCoder } from "./coders/address.js"; import { AddressCoder } from "./coders/address.js";
@ -54,9 +54,8 @@ export class AbiCoder {
let match = param.type.match(paramTypeNumber); let match = param.type.match(paramTypeNumber);
if (match) { if (match) {
let size = parseInt(match[2] || "256"); let size = parseInt(match[2] || "256");
if (size === 0 || size > 256 || (size % 8) !== 0) { assertArgument(size !== 0 && size <= 256 && (size % 8) === 0,
throwArgumentError("invalid " + match[1] + " bit length", "param", param); "invalid " + match[1] + " bit length", "param", param);
}
return new NumberCoder(size / 8, (match[1] === "int"), param.name); return new NumberCoder(size / 8, (match[1] === "int"), param.name);
} }
@ -64,13 +63,11 @@ export class AbiCoder {
match = param.type.match(paramTypeBytes); match = param.type.match(paramTypeBytes);
if (match) { if (match) {
let size = parseInt(match[1]); let size = parseInt(match[1]);
if (size === 0 || size > 32) { assertArgument(size !== 0 && size <= 32, "invalid bytes length", "param", param);
throwArgumentError("invalid bytes length", "param", param);
}
return new FixedBytesCoder(size, param.name); return new FixedBytesCoder(size, param.name);
} }
return throwArgumentError("invalid type", "type", param.type); assertArgument(false, "invalid type", "type", param.type);
} }
getDefaultValue(types: ReadonlyArray<string | ParamType>): Result { getDefaultValue(types: ReadonlyArray<string | ParamType>): Result {

@ -2,7 +2,7 @@
import { import {
defineProperties, concat, getBytesCopy, getNumber, hexlify, defineProperties, concat, getBytesCopy, getNumber, hexlify,
toArray, toBigInt, toNumber, toArray, toBigInt, toNumber,
assertPrivate, throwArgumentError, throwError assertPrivate, assertArgument, throwError
} from "../../utils/index.js"; } from "../../utils/index.js";
import type { BigNumberish, BytesLike } from "../../utils/index.js"; import type { BigNumberish, BytesLike } from "../../utils/index.js";
@ -194,7 +194,7 @@ export abstract class Coder {
} }
_throwError(message: string, value: any): never { _throwError(message: string, value: any): never {
return throwArgumentError(message, this.localName, value); assertArgument(false, message, this.localName, value);
} }
abstract encode(writer: Writer, value: any): number; abstract encode(writer: Writer, value: any): number;

@ -1,5 +1,5 @@
import { import {
defineProperties, isError, assertArgumentCount, throwArgumentError, throwError defineProperties, isError, assertArgument, assertArgumentCount, throwError
} from "../../utils/index.js"; } from "../../utils/index.js";
import { Typed } from "../typed.js"; import { Typed } from "../typed.js";
@ -43,12 +43,10 @@ export function pack(writer: Writer, coders: ReadonlyArray<Coder>, values: Array
}); });
} else { } else {
throwArgumentError("invalid tuple value", "tuple", values); assertArgument(false, "invalid tuple value", "tuple", values);
} }
if (coders.length !== arrayValues.length) { assertArgument(coders.length === arrayValues.length, "types/value length mismatch", "tuple", values);
throwArgumentError("types/value length mismatch", "tuple", values);
}
let staticWriter = new Writer(); let staticWriter = new Writer();
let dynamicWriter = new Writer(); let dynamicWriter = new Writer();

@ -1,6 +1,6 @@
import { import {
defineProperties, getBigInt, getNumber, defineProperties, getBigInt, getNumber,
assertPrivate, throwArgumentError, throwError assertPrivate, assertArgument, throwError
} from "../utils/index.js"; } from "../utils/index.js";
import { id } from "../hash/index.js"; import { id } from "../hash/index.js";
@ -401,25 +401,19 @@ const regexArrayType = new RegExp(/^(.*)\[([0-9]*)\]$/);
function verifyBasicType(type: string): string { function verifyBasicType(type: string): string {
const match = type.match(regexType); const match = type.match(regexType);
if (!match) { assertArgument(match, "invalid type", "type", type);
return throwArgumentError("invalid type", "type", type);
}
if (type === "uint") { return "uint256"; } if (type === "uint") { return "uint256"; }
if (type === "int") { return "int256"; } if (type === "int") { return "int256"; }
if (match[2]) { if (match[2]) {
// bytesXX // bytesXX
const length = parseInt(match[2]); const length = parseInt(match[2]);
if (length === 0 || length > 32) { assertArgument(length !== 0 && length <= 32, "invalid bytes length", "type", type);
throwArgumentError("invalid bytes length", "type", type);
}
} else if (match[3]) { } else if (match[3]) {
// intXX or uintXX // intXX or uintXX
const size = parseInt(match[3] as string); const size = parseInt(match[3] as string);
if (size === 0 || size > 256 || size % 8) { assertArgument(size !== 0 && size <= 256 && (size % 8) === 0, "invalid numeric width", "type", type);
throwArgumentError("invalid numeric width", "type", type);
}
} }
return type; return type;
@ -694,15 +688,12 @@ export class ParamType {
} }
const name = obj.name; const name = obj.name;
if (name && (typeof(name) !== "string" || !name.match(regexIdentifier))) { assertArgument(!name || (typeof(name) === "string" && name.match(regexIdentifier)),
throwArgumentError("invalid name", "obj.name", name); "invalid name", "obj.name", name);
}
let indexed = obj.indexed; let indexed = obj.indexed;
if (indexed != null) { if (indexed != null) {
if (!allowIndexed) { assertArgument(allowIndexed, "parameter cannot be indexed", "obj.indexed", obj.indexed);
throwArgumentError("parameter cannot be indexed", "obj.indexed", obj.indexed);
}
indexed = !!indexed; indexed = !!indexed;
} }
@ -813,9 +804,8 @@ export abstract class NamedFragment extends Fragment {
constructor(guard: any, type: FragmentType, name: string, inputs: ReadonlyArray<ParamType>) { constructor(guard: any, type: FragmentType, name: string, inputs: ReadonlyArray<ParamType>) {
super(guard, type, inputs); super(guard, type, inputs);
if (typeof(name) !== "string" || !name.match(regexIdentifier)) { assertArgument(typeof(name) === "string" && name.match(regexIdentifier),
throwArgumentError("invalid identifier", "name", name); "invalid identifier", "name", name);
}
inputs = Object.freeze(inputs.slice()); inputs = Object.freeze(inputs.slice());
defineProperties<NamedFragment>(this, { name }); defineProperties<NamedFragment>(this, { name });
} }

@ -2,7 +2,7 @@ import { keccak256 } from "../crypto/index.js"
import { id } from "../hash/index.js" import { id } from "../hash/index.js"
import { import {
concat, dataSlice, getBigInt, getBytes, getBytesCopy, concat, dataSlice, getBigInt, getBytes, getBytesCopy,
hexlify, zeroPadValue, isHexString, defineProperties, throwArgumentError, toHex, hexlify, zeroPadValue, isHexString, defineProperties, assertArgument, toHex,
throwError throwError
} from "../utils/index.js"; } from "../utils/index.js";
@ -279,7 +279,7 @@ export class Interface {
for (const fragment of this.#functions.values()) { for (const fragment of this.#functions.values()) {
if (selector === fragment.selector) { return fragment; } if (selector === fragment.selector) { return fragment; }
} }
throwArgumentError("no matching function", "selector", key); assertArgument(false, "no matching function", "selector", key);
} }
// It is a bare name, look up the function (will return null if ambiguous) // It is a bare name, look up the function (will return null if ambiguous)
@ -340,12 +340,11 @@ export class Interface {
} }
} }
if (matching.length === 0) { assertArgument(matching.length !== 0, "no matching function", "name", key);
throwArgumentError("no matching function", "name", key);
} else if (matching.length > 1 && forceUnique) { if (matching.length > 1 && forceUnique) {
const matchStr = matching.map((m) => JSON.stringify(m.format())).join(", "); const matchStr = matching.map((m) => JSON.stringify(m.format())).join(", ");
throwArgumentError(`multiple matching functions (i.e. ${ matchStr })`, "name", key); assertArgument(false, `multiple matching functions (i.e. ${ matchStr })`, "name", key);
} }
return matching[0]; return matching[0];
@ -355,7 +354,7 @@ export class Interface {
const result = this.#functions.get(FunctionFragment.from(key).format()); const result = this.#functions.get(FunctionFragment.from(key).format());
if (result) { return result; } if (result) { return result; }
return throwArgumentError("no matching function", "signature", key); assertArgument(false, "no matching function", "signature", key);
} }
/** /**
@ -390,7 +389,7 @@ export class Interface {
for (const fragment of this.#events.values()) { for (const fragment of this.#events.values()) {
if (eventTopic === fragment.topicHash) { return fragment; } if (eventTopic === fragment.topicHash) { return fragment; }
} }
throwArgumentError("no matching event", "eventTopic", key); assertArgument(false, "no matching event", "eventTopic", key);
} }
// It is a bare name, look up the function (will return null if ambiguous) // It is a bare name, look up the function (will return null if ambiguous)
@ -424,11 +423,10 @@ export class Interface {
} }
} }
if (matching.length === 0) { assertArgument(matching.length > 0, "no matching event", "name", key);
throwArgumentError("no matching event", "name", key); if (matching.length > 1 && forceUnique) {
} else if (matching.length > 1 && forceUnique) {
// @TODO: refine by Typed // @TODO: refine by Typed
throwArgumentError("multiple matching events", "name", key); assertArgument(false, "multiple matching events", "name", key);
} }
return matching[0]; return matching[0];
@ -438,7 +436,7 @@ export class Interface {
const result = this.#events.get(EventFragment.from(key).format()); const result = this.#events.get(EventFragment.from(key).format());
if (result) { return result; } if (result) { return result; }
return throwArgumentError("no matching event", "signature", key); assertArgument(false, "no matching event", "signature", key);
} }
/** /**
@ -484,7 +482,7 @@ export class Interface {
for (const fragment of this.#errors.values()) { for (const fragment of this.#errors.values()) {
if (selector === fragment.selector) { return fragment; } if (selector === fragment.selector) { return fragment; }
} }
throwArgumentError("no matching error", "selector", key); assertArgument(false, "no matching error", "selector", key);
} }
// It is a bare name, look up the function (will return null if ambiguous) // It is a bare name, look up the function (will return null if ambiguous)
@ -497,10 +495,10 @@ export class Interface {
if (matching.length === 0) { if (matching.length === 0) {
if (key === "Error") { return ErrorFragment.from("error Error(string)"); } if (key === "Error") { return ErrorFragment.from("error Error(string)"); }
if (key === "Panic") { return ErrorFragment.from("error Panic(uint256)"); } if (key === "Panic") { return ErrorFragment.from("error Panic(uint256)"); }
throwArgumentError("no matching error", "name", key); assertArgument(false, "no matching error", "name", key);
} else if (matching.length > 1) { } else if (matching.length > 1) {
// @TODO: refine by Typed // @TODO: refine by Typed
throwArgumentError("multiple matching errors", "name", key); assertArgument(false, "multiple matching errors", "name", key);
} }
return matching[0]; return matching[0];
@ -514,7 +512,7 @@ export class Interface {
const result = this.#errors.get(key); const result = this.#errors.get(key);
if (result) { return result; } if (result) { return result; }
return throwArgumentError("no matching error", "signature", key); assertArgument(false, "no matching error", "signature", key);
} }
// Get the 4-byte selector used by Solidity to identify a function // Get the 4-byte selector used by Solidity to identify a function
@ -576,9 +574,8 @@ export class Interface {
decodeErrorResult(fragment: ErrorFragment | string, data: BytesLike): Result { decodeErrorResult(fragment: ErrorFragment | string, data: BytesLike): Result {
if (typeof(fragment) === "string") { fragment = this.getError(fragment); } if (typeof(fragment) === "string") { fragment = this.getError(fragment); }
if (dataSlice(data, 0, 4) !== fragment.selector) { assertArgument(dataSlice(data, 0, 4) === fragment.selector,
throwArgumentError(`data signature does not match error ${ fragment.name }.`, "data", data); `data signature does not match error ${ fragment.name }.`, "data", data);
}
return this._decodeParams(fragment.inputs, dataSlice(data, 4)); return this._decodeParams(fragment.inputs, dataSlice(data, 4));
} }
@ -611,9 +608,8 @@ export class Interface {
decodeFunctionData(key: FunctionFragment | string, data: BytesLike): Result { decodeFunctionData(key: FunctionFragment | string, data: BytesLike): Result {
const fragment = (typeof(key) === "string") ? this.getFunction(key): key; const fragment = (typeof(key) === "string") ? this.getFunction(key): key;
if (dataSlice(data, 0, 4) !== fragment.selector) { assertArgument(dataSlice(data, 0, 4) === fragment.selector,
throwArgumentError(`data signature does not match function ${ fragment.name }.`, "data", data); `data signature does not match function ${ fragment.name }.`, "data", data);
}
return this._decodeParams(fragment.inputs, dataSlice(data, 4)); return this._decodeParams(fragment.inputs, dataSlice(data, 4));
} }
@ -788,16 +784,15 @@ export class Interface {
const param = (<EventFragment>eventFragment).inputs[index]; const param = (<EventFragment>eventFragment).inputs[index];
if (!param.indexed) { if (!param.indexed) {
if (value != null) { assertArgument(value == null,
throwArgumentError("cannot filter non-indexed parameters; must be null", ("contract." + param.name), value); "cannot filter non-indexed parameters; must be null", ("contract." + param.name), value);
}
return; return;
} }
if (value == null) { if (value == null) {
topics.push(null); topics.push(null);
} else if (param.baseType === "array" || param.baseType === "tuple") { } else if (param.baseType === "array" || param.baseType === "tuple") {
throwArgumentError("filtering with tuples or arrays not supported", ("contract." + param.name), value); assertArgument(false, "filtering with tuples or arrays not supported", ("contract." + param.name), value);
} else if (Array.isArray(value)) { } else if (Array.isArray(value)) {
topics.push(value.map((value) => encodeTopic(param, value))); topics.push(value.map((value) => encodeTopic(param, value)));
} else { } else {
@ -827,9 +822,8 @@ export class Interface {
topics.push(eventFragment.topicHash); topics.push(eventFragment.topicHash);
} }
if (values.length !== eventFragment.inputs.length) { assertArgument(values.length !== eventFragment.inputs.length,
throwArgumentError("event arguments/values mismatch", "values", values); "event arguments/values mismatch", "values", values);
}
eventFragment.inputs.forEach((param, index) => { eventFragment.inputs.forEach((param, index) => {
const value = values[index]; const value = values[index];
@ -864,9 +858,8 @@ export class Interface {
if (topics != null && !eventFragment.anonymous) { if (topics != null && !eventFragment.anonymous) {
const eventTopic = eventFragment.topicHash; const eventTopic = eventFragment.topicHash;
if (!isHexString(topics[0], 32) || topics[0].toLowerCase() !== eventTopic) { assertArgument(isHexString(topics[0], 32) && topics[0].toLowerCase() === eventTopic,
throwArgumentError("fragment/topic mismatch", "topics[0]", topics[0]); "fragment/topic mismatch", "topics[0]", topics[0]);
}
topics = topics.slice(1); topics = topics.slice(1);
} }

@ -1,5 +1,5 @@
import { keccak256 } from "../crypto/index.js"; import { keccak256 } from "../crypto/index.js";
import { getBytes, throwArgumentError } from "../utils/index.js"; import { getBytes, assertArgument } from "../utils/index.js";
const BN_0 = BigInt(0); const BN_0 = BigInt(0);
@ -83,9 +83,7 @@ function fromBase36(value: string): bigint {
export function getAddress(address: string): string { export function getAddress(address: string): string {
if (typeof(address) !== "string") { assertArgument(typeof(address) === "string", "invalid address", "address", address);
throwArgumentError("invalid address", "address", address);
}
if (address.match(/^(0x)?[0-9a-fA-F]{40}$/)) { if (address.match(/^(0x)?[0-9a-fA-F]{40}$/)) {
@ -95,9 +93,8 @@ export function getAddress(address: string): string {
const result = getChecksumAddress(address); const result = getChecksumAddress(address);
// It is a checksummed address with a bad checksum // It is a checksummed address with a bad checksum
if (address.match(/([A-F].*[a-f])|([a-f].*[A-F])/) && result !== address) { assertArgument(!address.match(/([A-F].*[a-f])|([a-f].*[A-F])/) || result === address,
throwArgumentError("bad address checksum", "address", address); "bad address checksum", "address", address);
}
return result; return result;
} }
@ -105,16 +102,14 @@ export function getAddress(address: string): string {
// Maybe ICAP? (we only support direct mode) // Maybe ICAP? (we only support direct mode)
if (address.match(/^XE[0-9]{2}[0-9A-Za-z]{30,31}$/)) { if (address.match(/^XE[0-9]{2}[0-9A-Za-z]{30,31}$/)) {
// It is an ICAP address with a bad checksum // It is an ICAP address with a bad checksum
if (address.substring(2, 4) !== ibanChecksum(address)) { assertArgument(address.substring(2, 4) === ibanChecksum(address), "bad icap checksum", "address", address);
throwArgumentError("bad icap checksum", "address", address);
}
let result = fromBase36(address.substring(4)).toString(16); let result = fromBase36(address.substring(4)).toString(16);
while (result.length < 40) { result = "0" + result; } while (result.length < 40) { result = "0" + result; }
return getChecksumAddress("0x" + result); return getChecksumAddress("0x" + result);
} }
return throwArgumentError("invalid address", "address", address); assertArgument(false, "invalid address", "address", address);
} }
export function getIcapAddress(address: string): string { export function getIcapAddress(address: string): string {

@ -1,4 +1,4 @@
import { throwArgumentError, throwError } from "../utils/index.js"; import { assertArgument, throwError } from "../utils/index.js";
import { getAddress } from "./address.js"; import { getAddress } from "./address.js";
@ -23,7 +23,7 @@ async function checkAddress(target: any, promise: Promise<null | string>): Promi
if (typeof(target) === "string") { if (typeof(target) === "string") {
return throwError("unconfigured name", "UNCONFIGURED_NAME", { value: target }); return throwError("unconfigured name", "UNCONFIGURED_NAME", { value: target });
} }
return throwArgumentError("invalid AddressLike value; did not resolve to a value address", "target", target); assertArgument(false, "invalid AddressLike value; did not resolve to a value address", "target", target);
} }
return getAddress(result); return getAddress(result);
} }
@ -50,5 +50,5 @@ export function resolveAddress(target: AddressLike, resolver?: null | NameResolv
return checkAddress(target, target); return checkAddress(target, target);
} }
return throwArgumentError("unsupported addressable value", "target", target); assertArgument(false, "unsupported addressable value", "target", target);
} }

@ -1,6 +1,6 @@
import { keccak256 } from "../crypto/index.js"; import { keccak256 } from "../crypto/index.js";
import { import {
concat, dataSlice, getBigInt, getBytes, encodeRlp, throwArgumentError concat, dataSlice, getBigInt, getBytes, encodeRlp, assertArgument
} from "../utils/index.js"; } from "../utils/index.js";
import { getAddress } from "./address.js"; import { getAddress } from "./address.js";
@ -30,13 +30,9 @@ export function getCreate2Address(_from: string, _salt: BytesLike, _initCodeHash
const salt = getBytes(_salt, "salt"); const salt = getBytes(_salt, "salt");
const initCodeHash = getBytes(_initCodeHash, "initCodeHash"); const initCodeHash = getBytes(_initCodeHash, "initCodeHash");
if (salt.length !== 32) { assertArgument(salt.length === 32, "salt must be 32 bytes", "salt", _salt);
throwArgumentError("salt must be 32 bytes", "salt", _salt);
}
if (initCodeHash.length !== 32) { assertArgument(initCodeHash.length === 32, "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)) return getAddress(dataSlice(keccak256(concat([ "0xff", from, salt, initCodeHash ])), 12))
} }

@ -3,7 +3,7 @@ import { resolveAddress } from "../address/index.js";
import { copyRequest, Log, TransactionResponse } from "../providers/index.js"; import { copyRequest, Log, TransactionResponse } from "../providers/index.js";
import { import {
defineProperties, isCallException, isHexString, resolveProperties, defineProperties, isCallException, isHexString, resolveProperties,
makeError, throwArgumentError, throwError makeError, assertArgument, throwError
} from "../utils/index.js"; } from "../utils/index.js";
import { import {
@ -133,9 +133,9 @@ export async function copyOverrides(arg: any): Promise<Omit<ContractTransaction,
// Some sanity checking; these are what these methods adds // Some sanity checking; these are what these methods adds
//if ((<any>overrides).to) { //if ((<any>overrides).to) {
if (overrides.to) { if (overrides.to) {
throwArgumentError("cannot override to", "overrides.to", overrides.to); assertArgument(false, "cannot override to", "overrides.to", overrides.to);
} else if (overrides.data) { } else if (overrides.data) {
throwArgumentError("cannot override data", "overrides.data", overrides.data); assertArgument(false, "cannot override data", "overrides.data", overrides.data);
} }
// Resolve any from // Resolve any from

@ -3,7 +3,7 @@ import { Interface } from "../abi/index.js";
import { getCreateAddress } from "../address/index.js"; import { getCreateAddress } from "../address/index.js";
import { import {
concat, defineProperties, getBytes, hexlify, concat, defineProperties, getBytes, hexlify,
throwArgumentError, throwError assertArgument, throwError
} from "../utils/index.js"; } from "../utils/index.js";
import { BaseContract, copyOverrides, resolveArgs } from "./contract.js"; import { BaseContract, copyOverrides, resolveArgs } from "./contract.js";
@ -80,9 +80,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> { static fromSolidity<A extends Array<any> = Array<any>, I = ContractInterface>(output: any, runner?: ContractRunner): ContractFactory<A, I> {
if (output == null) { assertArgument(output != null, "bad compiler output", "output", output);
throwArgumentError("bad compiler output", "output", output);
}
if (typeof(output) === "string") { output = JSON.parse(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 { sha256 } from "@noble/hashes/sha256";
import { sha512 } from "@noble/hashes/sha512"; import { sha512 } from "@noble/hashes/sha512";
import { throwArgumentError, throwError } from "../utils/index.js"; import { assertArgument, throwError } from "../utils/index.js";
declare global { declare global {
@ -37,22 +37,18 @@ export function createHash(algo: string): CryptoHasher {
case "sha256": return sha256.create(); case "sha256": return sha256.create();
case "sha512": return sha512.create(); case "sha512": return sha512.create();
} }
return throwArgumentError("invalid hashing algorithm name", "algorithm", algo); assertArgument(false, "invalid hashing algorithm name", "algorithm", algo);
} }
export function createHmac(_algo: string, key: Uint8Array): CryptoHasher { export function createHmac(_algo: string, key: Uint8Array): CryptoHasher {
const algo = ({ sha256, sha512 }[_algo]); const algo = ({ sha256, sha512 }[_algo]);
if (algo == null) { assertArgument(algo != null, "invalid hmac algorithm", "algorithm", _algo);
return throwArgumentError("invalid hmac algorithm", "algorithm", _algo);
}
return hmac.create(algo, key); return hmac.create(algo, key);
} }
export function pbkdf2Sync(password: Uint8Array, salt: Uint8Array, iterations: number, keylen: number, _algo: "sha256" | "sha512"): Uint8Array { export function pbkdf2Sync(password: Uint8Array, salt: Uint8Array, iterations: number, keylen: number, _algo: "sha256" | "sha512"): Uint8Array {
const algo = ({ sha256, sha512 }[_algo]); const algo = ({ sha256, sha512 }[_algo]);
if (algo == null) { assertArgument(algo != null, "invalid pbkdf2 algorithm", "algorithm", _algo);
return throwArgumentError("invalid pbkdf2 algorithm", "algorithm", _algo);
}
return pbkdf2(algo, password, salt, { c: iterations, dkLen: keylen }); return pbkdf2(algo, password, salt, { c: iterations, dkLen: keylen });
} }
@ -63,9 +59,7 @@ export function randomBytes(length: number): Uint8Array {
}); });
} }
if (!Number.isInteger(length) || length <= 0 || length > 1024) { assertArgument(Number.isInteger(length) && length > 0 && length <= 1024, "invalid length", "length", length);
throwArgumentError("invalid length", "length", length);
}
const result = new Uint8Array(length); const result = new Uint8Array(length);
crypto.getRandomValues(result); crypto.getRandomValues(result);

@ -1,4 +1,4 @@
import { createHmac } from "./crypto-browser.js"; import { createHmac } from "./crypto.js";
import { getBytes, hexlify } from "../utils/index.js"; import { getBytes, hexlify } from "../utils/index.js";
import type { BytesLike } from "../utils/index.js"; import type { BytesLike } from "../utils/index.js";

@ -2,7 +2,7 @@ import { ZeroHash } from "../constants/index.js";
import { import {
concat, dataLength, getBigInt, getBytes, getNumber, getStore, hexlify, concat, dataLength, getBigInt, getBytes, getNumber, getStore, hexlify,
isHexString, setStore, isHexString, setStore,
assertPrivate, throwArgumentError assertArgument, assertPrivate
} from "../utils/index.js"; } from "../utils/index.js";
import type { import type {
@ -48,26 +48,21 @@ export class Signature implements Freezable<Signature> {
get r(): string { return getStore(this.#props, "r"); } get r(): string { return getStore(this.#props, "r"); }
set r(value: BytesLike) { set r(value: BytesLike) {
if (dataLength(value) !== 32) { assertArgument(dataLength(value) === 32, "invalid r", "value", value);
throwArgumentError("invalid r", "value", value);
}
setStore(this.#props, "r", hexlify(value)); setStore(this.#props, "r", hexlify(value));
} }
get s(): string { return getStore(this.#props, "s"); } get s(): string { return getStore(this.#props, "s"); }
set s(value: BytesLike) { set s(value: BytesLike) {
if (dataLength(value) !== 32) { assertArgument(dataLength(value) === 32, "invalid r", "value", value);
throwArgumentError("invalid r", "value", value); assertArgument((getBytes(value)[0] & 0x80) === 0, "non-canonical s", "value", value);
} else if (getBytes(value)[0] & 0x80) {
throwArgumentError("non-canonical s", "value", value);
}
setStore(this.#props, "s", hexlify(value)); setStore(this.#props, "s", hexlify(value));
} }
get v(): 27 | 28 { return getStore(this.#props, "v"); } get v(): 27 | 28 { return getStore(this.#props, "v"); }
set v(value: BigNumberish) { set v(value: BigNumberish) {
const v = getNumber(value, "value"); const v = getNumber(value, "value");
if (v !== 27 && v !== 28) { throw new Error("@TODO"); } assertArgument(v === 27 || v === 28, "invalid v", "v", value);
setStore(this.#props, "v", v); setStore(this.#props, "v", v);
} }
@ -130,10 +125,6 @@ export class Signature implements Freezable<Signature> {
}; };
} }
//static create(): Signature {
// return new Signature(_guard, ZeroHash, ZeroHash, 27);
//}
// Get the chain ID from an EIP-155 v // Get the chain ID from an EIP-155 v
static getChainId(v: BigNumberish): bigint { static getChainId(v: BigNumberish): bigint {
const bv = getBigInt(v, "v"); const bv = getBigInt(v, "v");
@ -142,7 +133,7 @@ export class Signature implements Freezable<Signature> {
if ((bv == BN_27) || (bv == BN_28)) { return BN_0; } if ((bv == BN_27) || (bv == BN_28)) { return BN_0; }
// Bad value for an EIP-155 v // Bad value for an EIP-155 v
if (bv < BN_35) { throwArgumentError("invalid EIP-155 v", "v", v); } assertArgument(bv >= BN_35, "invalid EIP-155 v", "v", v);
return (bv - BN_35) / BN_2; return (bv - BN_35) / BN_2;
} }
@ -164,14 +155,14 @@ export class Signature implements Freezable<Signature> {
} }
static from(sig?: SignatureLike): Signature { static from(sig?: SignatureLike): Signature {
function assertError(check: unknown, message: string): asserts check {
assertArgument(check, message, "signature", sig);
};
if (sig == null) { if (sig == null) {
return new Signature(_guard, ZeroHash, ZeroHash, 27); return new Signature(_guard, ZeroHash, ZeroHash, 27);
} }
const throwError = (message: string) => {
return throwArgumentError(message, "signature", sig);
};
if (typeof(sig) === "string") { if (typeof(sig) === "string") {
const bytes = getBytes(sig, "signature"); const bytes = getBytes(sig, "signature");
if (bytes.length === 64) { if (bytes.length === 64) {
@ -185,38 +176,38 @@ export class Signature implements Freezable<Signature> {
if (bytes.length === 65) { if (bytes.length === 65) {
const r = hexlify(bytes.slice(0, 32)); const r = hexlify(bytes.slice(0, 32));
const s = bytes.slice(32, 64); const s = bytes.slice(32, 64);
if (s[0] & 0x80) { throwError("non-canonical s"); } assertError((s[0] & 0x80) === 0, "non-canonical s");
const v = Signature.getNormalizedV(bytes[64]); const v = Signature.getNormalizedV(bytes[64]);
return new Signature(_guard, r, hexlify(s), v); return new Signature(_guard, r, hexlify(s), v);
} }
return throwError("invlaid raw signature length"); assertError(false, "invlaid raw signature length");
} }
if (sig instanceof Signature) { return sig.clone(); } if (sig instanceof Signature) { return sig.clone(); }
// Get r // Get r
const r = sig.r; const r = sig.r;
if (r == null) { throwError("missing r"); } assertError(r != null, "missing r");
if (!isHexString(r, 32)) { throwError("invalid r"); } assertError(isHexString(r, 32), "invalid r");
// Get s; by any means necessary (we check consistency below) // Get s; by any means necessary (we check consistency below)
const s = (function(s?: string, yParityAndS?: string) { const s = (function(s?: string, yParityAndS?: string) {
if (s != null) { if (s != null) {
if (!isHexString(s, 32)) { throwError("invalid s"); } assertError(isHexString(s, 32), "invalid s");
return s; return s;
} }
if (yParityAndS != null) { if (yParityAndS != null) {
if (!isHexString(yParityAndS, 32)) { throwError("invalid yParityAndS"); } assertError(isHexString(yParityAndS, 32), "invalid yParityAndS");
const bytes = getBytes(yParityAndS); const bytes = getBytes(yParityAndS);
bytes[0] &= 0x7f; bytes[0] &= 0x7f;
return hexlify(bytes); return hexlify(bytes);
} }
return throwError("missing s"); assertError(false, "missing s");
})(sig.s, sig.yParityAndS); })(sig.s, sig.yParityAndS);
if (getBytes(s)[0] & 0x80) { throwError("non-canonical s"); } assertError((getBytes(s)[0] & 0x80) == 0, "non-canonical s");
// Get v; by any means necessary (we check consistency below) // 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 } { const { networkV, v } = (function(_v?: BigNumberish, yParityAndS?: string, yParity?: number): { networkV?: bigint, v: 27 | 28 } {
@ -229,7 +220,7 @@ export class Signature implements Freezable<Signature> {
} }
if (yParityAndS != null) { if (yParityAndS != null) {
if (!isHexString(yParityAndS, 32)) { throwError("invalid yParityAndS"); } assertError(isHexString(yParityAndS, 32), "invalid yParityAndS");
return { v: ((getBytes(yParityAndS)[0] & 0x80) ? 28: 27) }; return { v: ((getBytes(yParityAndS)[0] & 0x80) ? 28: 27) };
} }
@ -238,21 +229,18 @@ export class Signature implements Freezable<Signature> {
case 0: return { v: 27 }; case 0: return { v: 27 };
case 1: return { v: 28 }; case 1: return { v: 28 };
} }
return throwError("invalid yParity"); assertError(false, "invalid yParity");
} }
return throwError("missing v"); assertError(false, "missing v");
})(sig.v, sig.yParityAndS, sig.yParity); })(sig.v, sig.yParityAndS, sig.yParity);
const result = new Signature(_guard, r, s, v); const result = new Signature(_guard, r, s, v);
if (networkV) { setStore(result.#props, "networkV", networkV); } if (networkV) { setStore(result.#props, "networkV", networkV); }
// If multiple of v, yParity, yParityAndS we given, check they match // If multiple of v, yParity, yParityAndS we given, check they match
if ("yParity" in sig && sig.yParity !== result.yParity) { assertError(!("yParity" in sig && sig.yParity !== result.yParity), "yParity mismatch");
throwError("yParity mismatch"); assertError(!("yParityAndS" in sig && sig.yParityAndS !== result.yParityAndS), "yParityAndS mismatch");
} else if ("yParityAndS" in sig && sig.yParityAndS !== result.yParityAndS) {
throwError("yParityAndS mismatch");
}
return result; return result;
} }

@ -3,7 +3,7 @@ import * as secp256k1 from "@noble/secp256k1";
import { import {
concat, dataLength, getBytes, getBytesCopy, hexlify, toHex, concat, dataLength, getBytes, getBytesCopy, hexlify, toHex,
assertArgument, throwArgumentError assertArgument
} from "../utils/index.js"; } from "../utils/index.js";
import { computeHmac } from "./hmac.js"; import { computeHmac } from "./hmac.js";
@ -87,7 +87,7 @@ export class SigningKey {
const pubKey = secp256k1.recoverPublicKey(getBytesCopy(digest), der, sig.yParity); const pubKey = secp256k1.recoverPublicKey(getBytesCopy(digest), der, sig.yParity);
if (pubKey != null) { return hexlify(pubKey); } if (pubKey != null) { return hexlify(pubKey); }
return throwArgumentError("invalid signautre for digest", "signature", signature); assertArgument(false, "invalid signautre for digest", "signature", signature);
} }
static _addPoints(p0: BytesLike, p1: BytesLike, compressed?: boolean): string { static _addPoints(p0: BytesLike, p1: BytesLike, compressed?: boolean): string {

@ -81,14 +81,14 @@ export {
concat, dataLength, dataSlice, getBytes, getBytesCopy, hexlify, concat, dataLength, dataSlice, getBytes, getBytesCopy, hexlify,
isHexString, isBytesLike, stripZerosLeft, zeroPadBytes, zeroPadValue, isHexString, isBytesLike, stripZerosLeft, zeroPadBytes, zeroPadValue,
assertArgument, assertArgumentCount, assertNormalize, assertPrivate, assertArgument, assertArgumentCount, assertNormalize, assertPrivate,
makeError, throwArgumentError, throwError, makeError, throwError,
isCallException, isError, isCallException, isError,
getIpfsGatewayFunc, FetchRequest, FetchResponse, FetchCancelSignal, getIpfsGatewayFunc, FetchRequest, FetchResponse, FetchCancelSignal,
FixedFormat, FixedNumber, formatFixed, parseFixed, FixedFormat, FixedNumber, formatFixed, parseFixed,
getBigInt, getNumber, toArray, toBigInt, toHex, toNumber, toQuantity, getBigInt, getNumber, toArray, toBigInt, toHex, toNumber, toQuantity,
fromTwos, toTwos, mask, fromTwos, toTwos, mask,
formatEther, parseEther, formatUnits, parseUnits, formatEther, parseEther, formatUnits, parseUnits,
_toEscapedUtf8String, toUtf8Bytes, toUtf8CodePoints, toUtf8String, toUtf8Bytes, toUtf8CodePoints, toUtf8String,
Utf8ErrorFuncs, Utf8ErrorFuncs,
decodeRlp, encodeRlp decodeRlp, encodeRlp
} from "./utils/index.js"; } from "./utils/index.js";

@ -1,7 +1,7 @@
import { keccak256 } from "../crypto/index.js"; import { keccak256 } from "../crypto/index.js";
import { import {
concat, hexlify, throwArgumentError, toUtf8Bytes, toUtf8String concat, hexlify, assertArgument, toUtf8Bytes, toUtf8String
} from "../utils/index.js"; } from "../utils/index.js";
@ -56,9 +56,7 @@ export function isValidName(name: string): boolean {
export function namehash(name: string): string { export function namehash(name: string): string {
/* istanbul ignore if */ /* istanbul ignore if */
if (typeof(name) !== "string") { assertArgument(typeof(name) === "string", "invalid ENS name; not a string", "name", name);
throwArgumentError("invalid ENS name; not a string", "name", name);
}
let result: string | Uint8Array = Zeros; let result: string | Uint8Array = Zeros;

@ -3,7 +3,7 @@ import {
} from "../crypto/index.js"; } from "../crypto/index.js";
import { import {
concat, dataLength, getBytes, hexlify, toArray, toTwos, toUtf8Bytes, zeroPadBytes, zeroPadValue, concat, dataLength, getBytes, hexlify, toArray, toTwos, toUtf8Bytes, zeroPadBytes, zeroPadValue,
throwArgumentError assertArgument
} from "../utils/index.js"; } from "../utils/index.js";
@ -31,9 +31,7 @@ function _pack(type: string, value: any, isArray?: boolean): Uint8Array {
if (match) { if (match) {
let size = parseInt(match[2] || "256") let size = parseInt(match[2] || "256")
if ((match[2] && String(size) !== match[2]) || (size % 8 !== 0) || size === 0 || size > 256) { assertArgument((!match[2] || match[2] === String(size)) && (size % 8 === 0) && size !== 0 && size <= 256, "invalid number type", "type", type);
return throwArgumentError("invalid number type", "type", type)
}
if (isArray) { size = 256; } if (isArray) { size = 256; }
@ -46,12 +44,9 @@ function _pack(type: string, value: any, isArray?: boolean): Uint8Array {
if (match) { if (match) {
const size = parseInt(match[1]); const size = parseInt(match[1]);
if (String(size) !== match[1] || size === 0 || size > 32) { assertArgument(String(size) === match[1] && size !== 0 && size <= 32, "invalid bytes type", "type", type);
return throwArgumentError("invalid bytes type", "type", type) assertArgument(dataLength(value) === size, `invalid value for ${ type }`, "value", value);
}
if (dataLength(value) !== size) {
return throwArgumentError(`invalid value for ${ type }`, "value", value)
}
if (isArray) { return getBytes(zeroPadBytes(value, 32)); } if (isArray) { return getBytes(zeroPadBytes(value, 32)); }
return value; return value;
} }
@ -60,9 +55,8 @@ function _pack(type: string, value: any, isArray?: boolean): Uint8Array {
if (match && Array.isArray(value)) { if (match && Array.isArray(value)) {
const baseType = match[1]; const baseType = match[1];
const count = parseInt(match[2] || String(value.length)); const count = parseInt(match[2] || String(value.length));
if (count != value.length) { assertArgument(count === value.length, `invalid array length for ${ type }`, "value", value);
throwArgumentError(`invalid array length for ${ type }`, "value", value)
}
const result: Array<Uint8Array> = []; const result: Array<Uint8Array> = [];
value.forEach(function(value) { value.forEach(function(value) {
result.push(_pack(baseType, value, true)); result.push(_pack(baseType, value, true));
@ -70,15 +64,14 @@ function _pack(type: string, value: any, isArray?: boolean): Uint8Array {
return getBytes(concat(result)); return getBytes(concat(result));
} }
return throwArgumentError("invalid type", "type", type) assertArgument(false, "invalid type", "type", type)
} }
// @TODO: Array Enum // @TODO: Array Enum
export function solidityPacked(types: ReadonlyArray<string>, values: ReadonlyArray<any>): string { export function solidityPacked(types: ReadonlyArray<string>, values: ReadonlyArray<any>): string {
if (types.length != values.length) { assertArgument(types.length === values.length, "wrong number of values; expected ${ types.length }", "values", values);
throwArgumentError("wrong number of values; expected ${ types.length }", "values", values)
}
const tight: Array<Uint8Array> = []; const tight: Array<Uint8Array> = [];
types.forEach(function(type, index) { types.forEach(function(type, index) {
tight.push(_pack(type, values[index])); tight.push(_pack(type, values[index]));

@ -3,7 +3,7 @@ import { getAddress } from "../address/index.js";
import { keccak256 } from "../crypto/index.js"; import { keccak256 } from "../crypto/index.js";
import { import {
concat, defineProperties, getBigInt, getBytes, hexlify, isHexString, mask, toHex, toTwos, zeroPadValue, concat, defineProperties, getBigInt, getBytes, hexlify, isHexString, mask, toHex, toTwos, zeroPadValue,
throwArgumentError assertArgument
} from "../utils/index.js"; } from "../utils/index.js";
import { id } from "./id.js"; import { id } from "./id.js";
@ -58,9 +58,7 @@ const domainFieldNames: Array<string> = [
function checkString(key: string): (value: any) => string { function checkString(key: string): (value: any) => string {
return function (value: any){ return function (value: any){
if (typeof(value) !== "string") { assertArgument(typeof(value) === "string", `invalid domain value for ${ JSON.stringify(key) }`, `domain.${ key }`, value);
throwArgumentError(`invalid domain value for ${ JSON.stringify(key) }`, `domain.${ key }`, value);
}
return value; return value;
} }
} }
@ -75,13 +73,11 @@ const domainChecks: Record<string, (value: any) => any> = {
try { try {
return getAddress(value).toLowerCase(); return getAddress(value).toLowerCase();
} catch (error) { } } catch (error) { }
return throwArgumentError(`invalid domain value "verifyingContract"`, "domain.verifyingContract", value); assertArgument(false, `invalid domain value "verifyingContract"`, "domain.verifyingContract", value);
}, },
salt: function(value: any) { salt: function(value: any) {
const bytes = getBytes(value, "domain.salt"); const bytes = getBytes(value, "domain.salt");
if (bytes.length !== 32) { assertArgument(bytes.length === 32, `invalid domain value "salt"`, "domain.salt", value);
throwArgumentError(`invalid domain value "salt"`, "domain.salt", value);
}
return hexlify(bytes); return hexlify(bytes);
} }
} }
@ -94,9 +90,7 @@ function getBaseEncoder(type: string): null | ((value: any) => string) {
const signed = (match[1] === ""); const signed = (match[1] === "");
const width = parseInt(match[2] || "256"); const width = parseInt(match[2] || "256");
if (width % 8 !== 0 || width > 256 || (match[2] && match[2] !== String(width))) { assertArgument(width % 8 === 0 && width !== 0 && width <= 256 && (match[2] == null || match[2] === String(width)), "invalid numeric width", "type", type);
throwArgumentError("invalid numeric width", "type", type);
}
const boundsUpper = mask(BN_MAX_UINT256, signed ? (width - 1): width); const boundsUpper = mask(BN_MAX_UINT256, signed ? (width - 1): width);
const boundsLower = signed ? ((boundsUpper + BN_1) * BN__1): BN_0; const boundsLower = signed ? ((boundsUpper + BN_1) * BN__1): BN_0;
@ -104,9 +98,7 @@ function getBaseEncoder(type: string): null | ((value: any) => string) {
return function(_value: BigNumberish) { return function(_value: BigNumberish) {
const value = getBigInt(_value, "value"); const value = getBigInt(_value, "value");
if (value < boundsLower || value > boundsUpper) { assertArgument(value >= boundsLower && value <= boundsUpper, `value out-of-bounds for ${ type }`, "value", value);
throwArgumentError(`value out-of-bounds for ${ type }`, "value", value);
}
return toHex(toTwos(value, 256), 32); return toHex(toTwos(value, 256), 32);
}; };
@ -118,15 +110,11 @@ function getBaseEncoder(type: string): null | ((value: any) => string) {
const match = type.match(/^bytes(\d+)$/); const match = type.match(/^bytes(\d+)$/);
if (match) { if (match) {
const width = parseInt(match[1]); const width = parseInt(match[1]);
if (width === 0 || width > 32 || match[1] !== String(width)) { assertArgument(width !== 0 && width <= 32 && match[1] === String(width), "invalid bytes width", "type", type);
throwArgumentError("invalid bytes width", "type", type);
}
return function(value: BytesLike) { return function(value: BytesLike) {
const bytes = getBytes(value); const bytes = getBytes(value);
if (bytes.length !== width) { assertArgument(bytes.length === width, `invalid length for ${ type }`, "value", value);
throwArgumentError(`invalid length for ${ type }`, "value", value);
}
return hexPadRight(value); return hexPadRight(value);
}; };
} }
@ -192,24 +180,18 @@ export class TypedDataEncoder {
for (const field of types[name]) { for (const field of types[name]) {
// Check each field has a unique name // Check each field has a unique name
if (uniqueNames.has(field.name)) { assertArgument(!uniqueNames.has(field.name), `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); uniqueNames.add(field.name);
// Get the base type (drop any array specifiers) // Get the base type (drop any array specifiers)
const baseType = (<any>(field.type.match(/^([^\x5b]*)(\x5b|$)/)))[1] || null; const baseType = (<any>(field.type.match(/^([^\x5b]*)(\x5b|$)/)))[1] || null;
if (baseType === name) { assertArgument(baseType !== name, `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? // Is this a base encoding type?
const encoder = getBaseEncoder(baseType); const encoder = getBaseEncoder(baseType);
if (encoder) { continue; } if (encoder) { continue; }
if (!parents.has(baseType)) { assertArgument(parents.has(baseType), `unknown type ${ JSON.stringify(baseType) }`, "types", types);
throwArgumentError(`unknown type ${ JSON.stringify(baseType) }`, "types", types);
}
// Add linkage // Add linkage
(parents.get(baseType) as Array<string>).push(name); (parents.get(baseType) as Array<string>).push(name);
@ -219,20 +201,14 @@ export class TypedDataEncoder {
// Deduce the primary type // Deduce the primary type
const primaryTypes = Array.from(parents.keys()).filter((n) => ((parents.get(n) as Array<string>).length === 0)); const primaryTypes = Array.from(parents.keys()).filter((n) => ((parents.get(n) as Array<string>).length === 0));
assertArgument(primaryTypes.length !== 0, "missing primary type", "types", types);
if (primaryTypes.length === 0) { assertArgument(primaryTypes.length === 1, `ambiguous primary types or unused types: ${ primaryTypes.map((t) => (JSON.stringify(t))).join(", ") }`, "types", types);
throwArgumentError("missing primary type", "types", types);
} else if (primaryTypes.length > 1) {
throwArgumentError(`ambiguous primary types or unused types: ${ primaryTypes.map((t) => (JSON.stringify(t))).join(", ") }`, "types", types);
}
defineProperties<TypedDataEncoder>(this, { primaryType: primaryTypes[0] }); defineProperties<TypedDataEncoder>(this, { primaryType: primaryTypes[0] });
// Check for circular type references // Check for circular type references
function checkCircular(type: string, found: Set<string>) { function checkCircular(type: string, found: Set<string>) {
if (found.has(type)) { assertArgument(!found.has(type), `circular type reference to ${ JSON.stringify(type) }`, "types", types);
throwArgumentError(`circular type reference to ${ JSON.stringify(type) }`, "types", types);
}
found.add(type); found.add(type);
@ -282,11 +258,8 @@ export class TypedDataEncoder {
if (match) { if (match) {
const subtype = match[1]; const subtype = match[1];
const subEncoder = this.getEncoder(subtype); const subEncoder = this.getEncoder(subtype);
const length = parseInt(match[3]);
return (value: Array<any>) => { return (value: Array<any>) => {
if (length >= 0 && value.length !== length) { assertArgument(!match[3] || parseInt(match[3]) === value.length, `array length mismatch; expected length ${ parseInt(match[3]) }`, "value", value);
throwArgumentError("array length mismatch; expected length ${ arrayLength }", "value", value);
}
let result = value.map(subEncoder); let result = value.map(subEncoder);
if (this.#fullTypes.has(subtype)) { if (this.#fullTypes.has(subtype)) {
@ -312,14 +285,12 @@ export class TypedDataEncoder {
} }
} }
return throwArgumentError(`unknown type: ${ type }`, "type", type); assertArgument(false, `unknown type: ${ type }`, "type", type);
} }
encodeType(name: string): string { encodeType(name: string): string {
const result = this.#fullTypes.get(name); const result = this.#fullTypes.get(name);
if (!result) { assertArgument(result, `unknown type: ${ JSON.stringify(name) }`, "name", name);
return throwArgumentError(`unknown type: ${ JSON.stringify(name) }`, "name", name);
}
return result; return result;
} }
@ -349,12 +320,8 @@ export class TypedDataEncoder {
// Array // Array
const match = type.match(/^(.*)(\x5b(\d*)\x5d)$/); const match = type.match(/^(.*)(\x5b(\d*)\x5d)$/);
if (match) { if (match) {
const subtype = match[1]; assertArgument(!match[3] || parseInt(match[3]) === value.length, `array length mismatch; expected length ${ parseInt(match[3]) }`, "value", value);
const length = parseInt(match[3]); return value.map((v: any) => this._visit(match[1], v, callback));
if (length >= 0 && value.length !== length) {
throwArgumentError("array length mismatch; expected length ${ arrayLength }", "value", value);
}
return value.map((v: any) => this._visit(subtype, v, callback));
} }
// Struct // Struct
@ -366,7 +333,7 @@ export class TypedDataEncoder {
}, <Record<string, any>>{}); }, <Record<string, any>>{});
} }
return throwArgumentError(`unknown type: ${ type }`, "type", type); assertArgument(false, `unknown type: ${ type }`, "type", type);
} }
visit(value: Record<string, any>, callback: (type: string, data: any) => any): any { visit(value: Record<string, any>, callback: (type: string, data: any) => any): any {
@ -389,9 +356,7 @@ export class TypedDataEncoder {
const domainFields: Array<TypedDataField> = [ ]; const domainFields: Array<TypedDataField> = [ ];
for (const name in domain) { for (const name in domain) {
const type = domainFieldTypes[name]; const type = domainFieldTypes[name];
if (!type) { assertArgument(type, `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 }); domainFields.push({ name, type });
} }
@ -475,11 +440,9 @@ export class TypedDataEncoder {
const encoder = TypedDataEncoder.from(types); const encoder = TypedDataEncoder.from(types);
const typesWithDomain = Object.assign({ }, types); const typesWithDomain = Object.assign({ }, types);
if (typesWithDomain.EIP712Domain) { assertArgument(typesWithDomain.EIP712Domain == null, "types must not contain EIP712Domain type", "types.EIP712Domain", types);
throwArgumentError("types must not contain EIP712Domain type", "types.EIP712Domain", types);
} else {
typesWithDomain.EIP712Domain = domainTypes; typesWithDomain.EIP712Domain = domainTypes;
}
// Validate the data structures and types // Validate the data structures and types
encoder.encode(value); encoder.encode(value);
@ -506,13 +469,11 @@ export class TypedDataEncoder {
case "bool": case "bool":
return !!value; return !!value;
case "string": case "string":
if (typeof(value) !== "string") { assertArgument(typeof(value) === "string", "invalid string", "value", value);
throwArgumentError(`invalid string`, "value", value);
}
return value; return value;
} }
return throwArgumentError("unsupported type", "type", type); assertArgument(false, "unsupported type", "type", type);
}) })
}; };
} }

@ -11,7 +11,7 @@ import { Transaction } from "../transaction/index.js";
import { import {
concat, dataLength, dataSlice, hexlify, isHexString, concat, dataLength, dataSlice, hexlify, isHexString,
getBigInt, getBytes, getNumber, getBigInt, getBytes, getNumber,
isCallException, makeError, throwError, throwArgumentError, isCallException, makeError, throwError, assertArgument,
FetchRequest, FetchRequest,
toArray, toQuantity, toArray, toQuantity,
defineProperties, EventPayload, resolveProperties, defineProperties, EventPayload, resolveProperties,
@ -198,7 +198,7 @@ async function getSubscription(_event: ProviderEvent, provider: AbstractProvider
return { filter, tag: getTag("event", filter), type: "event" }; return { filter, tag: getTag("event", filter), type: "event" };
} }
return throwArgumentError("unknown ProviderEvent", "event", _event); assertArgument(false, "unknown ProviderEvent", "event", _event);
} }
function getTime(): number { return (new Date()).getTime(); } function getTime(): number { return (new Date()).getTime(); }
@ -500,7 +500,7 @@ export class AbstractProvider implements Provider {
return this.getBlockNumber().then((b) => toQuantity(b + blockTag)); return this.getBlockNumber().then((b) => toQuantity(b + blockTag));
} }
return throwArgumentError("invalid blockTag", "blockTag", blockTag); assertArgument(false, "invalid blockTag", "blockTag", blockTag);
} }
_getFilter(filter: Filter | FilterByBlockHash): PerformActionFilter | Promise<PerformActionFilter> { _getFilter(filter: Filter | FilterByBlockHash): PerformActionFilter | Promise<PerformActionFilter> {

@ -1,7 +1,7 @@
import { Transaction } from "../transaction/index.js"; import { Transaction } from "../transaction/index.js";
import { import {
defineProperties, getBigInt, resolveProperties, defineProperties, getBigInt, resolveProperties,
throwArgumentError, throwError assertArgument, throwError
} from "../utils/index.js"; } from "../utils/index.js";
import type { TypedDataDomain, TypedDataField } from "../hash/index.js"; import type { TypedDataDomain, TypedDataField } from "../hash/index.js";
@ -40,9 +40,7 @@ export abstract class AbstractSigner<P extends null | Provider = null | Provider
if (pop.to != null) { if (pop.to != null) {
pop.to = provider.resolveName(pop.to).then((to) => { pop.to = provider.resolveName(pop.to).then((to) => {
if (to == null) { assertArgument(to != null, "transaction to ENS name not configured", "tx.to", pop.to);
return throwArgumentError("transaction to ENS name not configured", "tx.to", pop.to);
}
return to; return to;
}); });
} }
@ -53,9 +51,8 @@ export abstract class AbstractSigner<P extends null | Provider = null | Provider
this.getAddress(), this.getAddress(),
this.resolveName(from) this.resolveName(from)
]).then(([ address, from ]) => { ]).then(([ address, from ]) => {
if (!from || address.toLowerCase() !== from.toLowerCase()) { assertArgument(from && address.toLowerCase() === from.toLowerCase(),
return throwArgumentError("transaction from mismatch", "tx.from", from); "transaction from mismatch", "tx.from", from);
}
return address; return address;
}); });
} }
@ -84,9 +81,7 @@ export abstract class AbstractSigner<P extends null | Provider = null | Provider
const network = await (<Provider>(this.provider)).getNetwork(); const network = await (<Provider>(this.provider)).getNetwork();
if (pop.chainId != null) { if (pop.chainId != null) {
const chainId = getBigInt(pop.chainId); const chainId = getBigInt(pop.chainId);
if (chainId !== network.chainId) { assertArgument(chainId === network.chainId, "transaction chainId mismatch", "tx.chainId", tx.chainId);
throwArgumentError("transaction chainId mismatch", "tx.chainId", tx.chainId);
}
} else { } else {
pop.chainId = network.chainId; pop.chainId = network.chainId;
} }
@ -94,9 +89,9 @@ export abstract class AbstractSigner<P extends null | Provider = null | Provider
// Do not allow mixing pre-eip-1559 and eip-1559 properties // Do not allow mixing pre-eip-1559 and eip-1559 properties
const hasEip1559 = (pop.maxFeePerGas != null || pop.maxPriorityFeePerGas != null); const hasEip1559 = (pop.maxFeePerGas != null || pop.maxPriorityFeePerGas != null);
if (pop.gasPrice != null && (pop.type === 2 || hasEip1559)) { if (pop.gasPrice != null && (pop.type === 2 || hasEip1559)) {
throwArgumentError("eip-1559 transaction do not support gasPrice", "tx", tx); assertArgument(false, "eip-1559 transaction do not support gasPrice", "tx", tx);
} else if ((pop.type === 0 || pop.type === 1) && hasEip1559) { } else if ((pop.type === 0 || pop.type === 1) && hasEip1559) {
throwArgumentError("pre-eip-1559 transaction do not support maxFeePerGas/maxPriorityFeePerGas", "tx", tx); assertArgument(false, "pre-eip-1559 transaction do not support maxFeePerGas/maxPriorityFeePerGas", "tx", tx);
} }
if ((pop.type === 2 || pop.type == null) && (pop.maxFeePerGas != null && pop.maxPriorityFeePerGas != null)) { if ((pop.type === 2 || pop.type == null) && (pop.maxFeePerGas != null && pop.maxPriorityFeePerGas != null)) {

@ -5,7 +5,7 @@ import {
concat, dataSlice, getBytes, hexlify, zeroPadValue, concat, dataSlice, getBytes, hexlify, zeroPadValue,
defineProperties, encodeBase58, getBigInt, toArray, defineProperties, encodeBase58, getBigInt, toArray,
toNumber, toUtf8Bytes, toUtf8String, toNumber, toUtf8Bytes, toUtf8String,
throwArgumentError, throwError, assertArgument, throwError,
FetchRequest FetchRequest
} from "../utils/index.js"; } from "../utils/index.js";
@ -81,9 +81,8 @@ function encodeBytes(datas: Array<BytesLike>) {
} }
function callAddress(value: string): string { function callAddress(value: string): string {
if (value.length !== 66 || dataSlice(value, 0, 12) !== "0x000000000000000000000000") { assertArgument(value.length === 66 && dataSlice(value, 0, 12) === "0x000000000000000000000000",
throwArgumentError("invalid call address", "value", value); "invalid call address", "value", value);
}
return getAddress("0x" + value.substring(26)); return getAddress("0x" + value.substring(26));
} }
@ -95,7 +94,7 @@ function getIpfsLink(link: string): string {
} else if (link.match(/^ipfs:\/\//i)) { } else if (link.match(/^ipfs:\/\//i)) {
link = link.substring(7); link = link.substring(7);
} else { } else {
throwArgumentError("unsupported IPFS format", "link", link); assertArgument(false, "unsupported IPFS format", "link", link);
} }
return `https:/\/gateway.ipfs.io/ipfs/${ link }`; return `https:/\/gateway.ipfs.io/ipfs/${ link }`;

@ -4,7 +4,7 @@ import { Signature } from "../crypto/index.js"
import { accessListify } from "../transaction/index.js"; import { accessListify } from "../transaction/index.js";
import { import {
getBigInt, getNumber, hexlify, isHexString, zeroPadValue, getBigInt, getNumber, hexlify, isHexString, zeroPadValue,
throwArgumentError, throwError assertArgument, throwError
} from "../utils/index.js"; } from "../utils/index.js";
@ -63,20 +63,16 @@ export function formatBoolean(value: any): boolean {
case false: case "false": case false: case "false":
return false; return false;
} }
return throwArgumentError(`invalid boolean; ${ JSON.stringify(value) }`, "value", value); assertArgument(false, `invalid boolean; ${ JSON.stringify(value) }`, "value", value);
} }
export function formatData(value: string): string { export function formatData(value: string): string {
if (!isHexString(value, true)) { assertArgument(isHexString(value, true), "invalid data", "value", value);
throwArgumentError("", "value", value);
}
return value; return value;
} }
export function formatHash(value: any): string { export function formatHash(value: any): string {
if (!isHexString(value, 32)) { assertArgument(isHexString(value, 32), "invalid hash", "value", value);
throwArgumentError("", "value", value);
}
return value; return value;
} }

@ -1,6 +1,6 @@
import { accessListify } from "../transaction/index.js"; import { accessListify } from "../transaction/index.js";
import { import {
getStore, getBigInt, setStore, throwArgumentError getStore, getBigInt, setStore, assertArgument
} from "../utils/index.js"; } from "../utils/index.js";
import { EnsPlugin, GasCostPlugin } from "./plugins-network.js"; import { EnsPlugin, GasCostPlugin } from "./plugins-network.js";
@ -192,7 +192,7 @@ export class Network {
return new Network("unknown", network); return new Network("unknown", network);
} }
throwArgumentError("unknown network", "network", network); assertArgument(false, "unknown network", "network", network);
} }
// Clonable with network-like abilities // Clonable with network-like abilities
@ -205,9 +205,8 @@ export class Network {
// Networkish // Networkish
if (typeof(network) === "object") { if (typeof(network) === "object") {
if (typeof(network.name) !== "string" || typeof(network.chainId) !== "number") { assertArgument(typeof(network.name) === "string" && typeof(network.chainId) === "number",
throwArgumentError("invalid network object name or chainId", "network", network); "invalid network object name or chainId", "network", network);
}
const custom = new Network(<string>(network.name), <number>(network.chainId)); const custom = new Network(<string>(network.name), <number>(network.chainId));
@ -222,7 +221,7 @@ export class Network {
return custom; return custom;
} }
return throwArgumentError("invalid network", "network", network); assertArgument(false, "invalid network", "network", network);
} }
/** /**
@ -233,7 +232,7 @@ export class Network {
if (typeof(nameOrChainId) === "number") { nameOrChainId = BigInt(nameOrChainId); } if (typeof(nameOrChainId) === "number") { nameOrChainId = BigInt(nameOrChainId); }
const existing = Networks.get(nameOrChainId); const existing = Networks.get(nameOrChainId);
if (existing) { if (existing) {
throwArgumentError(`conflicting network for ${ JSON.stringify(existing.name) }`, "nameOrChainId", nameOrChainId); assertArgument(false, `conflicting network for ${ JSON.stringify(existing.name) }`, "nameOrChainId", nameOrChainId);
} }
Networks.set(nameOrChainId, networkFunc); Networks.set(nameOrChainId, networkFunc);
} }

@ -1,6 +1,6 @@
import { defineProperties } from "../utils/properties.js"; import { defineProperties } from "../utils/properties.js";
import { throwArgumentError } from "../utils/index.js"; import { assertArgument } from "../utils/index.js";
import type { FeeData, Provider } from "./provider.js"; import type { FeeData, Provider } from "./provider.js";
@ -52,9 +52,7 @@ export class GasCostPlugin extends NetworkPlugin implements GasCostParameters {
function set(name: keyof GasCostParameters, nullish: number): void { function set(name: keyof GasCostParameters, nullish: number): void {
let value = (costs || { })[name]; let value = (costs || { })[name];
if (value == null) { value = nullish; } if (value == null) { value = nullish; }
if (typeof(value) !== "number") { assertArgument(typeof(value) === "number", `invalud value for ${ name }`, "costs", costs);
throwArgumentError(`invalud value for ${ name }`, "costs", costs);
}
props[name] = value; props[name] = value;
} }

@ -1,6 +1,6 @@
import { import {
defineProperties, resolveProperties, throwArgumentError, throwError, defineProperties, resolveProperties, assertArgument, throwError,
FetchRequest FetchRequest
} from "../utils/index.js"; } from "../utils/index.js";
@ -36,7 +36,7 @@ function getHost(name: string): string {
return "opt-goerli.g.alchemy.com"; return "opt-goerli.g.alchemy.com";
} }
return throwArgumentError("unsupported network", "network", name); assertArgument(false, "unsupported network", "network", name);
} }
export class AlchemyProvider extends JsonRpcProvider implements CommunityResourcable { export class AlchemyProvider extends JsonRpcProvider implements CommunityResourcable {

@ -1,5 +1,5 @@
import { import {
defineProperties, FetchRequest, throwArgumentError defineProperties, FetchRequest, assertArgument
} from "../utils/index.js"; } from "../utils/index.js";
import { AbstractProvider } from "./abstract-provider.js"; import { AbstractProvider } from "./abstract-provider.js";
@ -28,7 +28,8 @@ function getHost(name: string): string {
case "arbitrum": case "arbitrum":
return "rpc.ankr.com/arbitrum"; return "rpc.ankr.com/arbitrum";
} }
return throwArgumentError("unsupported network", "network", name);
assertArgument(false, "unsupported network", "network", name);
} }

@ -1,4 +1,4 @@
import { throwArgumentError } from "../utils/index.js"; import { assertArgument } from "../utils/index.js";
import { Network } from "./network.js"; import { Network } from "./network.js";
import { JsonRpcProvider } from "./provider-jsonrpc.js"; import { JsonRpcProvider } from "./provider-jsonrpc.js";
@ -9,9 +9,7 @@ import type { Networkish } from "./network.js";
export class CloudflareProvider extends JsonRpcProvider { export class CloudflareProvider extends JsonRpcProvider {
constructor(_network: Networkish = "mainnet") { constructor(_network: Networkish = "mainnet") {
const network = Network.from(_network); const network = Network.from(_network);
if (network.name !== "mainnet") { assertArgument(network.name === "mainnet", "unsupported network", "network", _network);
return throwArgumentError("unsupported network", "network", _network);
}
super("https:/\/cloudflare-eth.com/", network, { staticNetwork: network }); super("https:/\/cloudflare-eth.com/", network, { staticNetwork: network });
} }
} }

@ -4,7 +4,7 @@ import {
defineProperties, defineProperties,
hexlify, toQuantity, hexlify, toQuantity,
FetchRequest, FetchRequest,
throwArgumentError, throwError, assertArgument, throwError,
toUtf8String toUtf8String
} from "../utils/index.js"; } from "../utils/index.js";
@ -103,7 +103,7 @@ export class BaseEtherscanProvider extends AbstractProvider {
default: default:
} }
return throwArgumentError("unsupported network", "network", this.network); assertArgument(false, "unsupported network", "network", this.network);
} }
getUrl(module: string, params: Record<string, string>): string { getUrl(module: string, params: Record<string, string>): string {

@ -1,6 +1,6 @@
import { import {
getBigInt, getNumber, hexlify, throwError, throwArgumentError getBigInt, getNumber, hexlify, throwError, assertArgument
} from "../utils/index.js"; } from "../utils/index.js";
import { AbstractProvider } from "./abstract-provider.js"; import { AbstractProvider } from "./abstract-provider.js";
@ -284,9 +284,8 @@ export class FallbackProvider extends AbstractProvider {
this.eventQuorum = 1; this.eventQuorum = 1;
this.eventWorkers = 1; this.eventWorkers = 1;
if (this.quorum > this.#configs.reduce((a, c) => (a + c.weight), 0)) { assertArgument(this.quorum <= this.#configs.reduce((a, c) => (a + c.weight), 0),
throwArgumentError("quorum exceed provider wieght", "quorum", this.quorum); "quorum exceed provider wieght", "quorum", this.quorum);
}
} }
// @TOOD: Copy these and only return public values // @TOOD: Copy these and only return public values

@ -1,5 +1,5 @@
import { import {
defineProperties, FetchRequest, throwArgumentError, throwError defineProperties, FetchRequest, assertArgument, throwError
} from "../utils/index.js"; } from "../utils/index.js";
import { showThrottleMessage } from "./community.js"; import { showThrottleMessage } from "./community.js";
@ -37,7 +37,7 @@ function getHost(name: string): string {
return "optimism-goerli.infura.io"; return "optimism-goerli.infura.io";
} }
return throwArgumentError("unsupported network", "network", name); assertArgument(false, "unsupported network", "network", name);
} }
export class InfuraWebSocketProvider extends WebSocketProvider implements CommunityResourcable { export class InfuraWebSocketProvider extends WebSocketProvider implements CommunityResourcable {

@ -9,7 +9,7 @@ import { TypedDataEncoder } from "../hash/index.js";
import { accessListify } from "../transaction/index.js"; import { accessListify } from "../transaction/index.js";
import { import {
defineProperties, getBigInt, hexlify, isHexString, toQuantity, toUtf8Bytes, defineProperties, getBigInt, hexlify, isHexString, toQuantity, toUtf8Bytes,
makeError, throwArgumentError, throwError, makeError, assertArgument, throwError,
FetchRequest, resolveProperties FetchRequest, resolveProperties
} from "../utils/index.js"; } from "../utils/index.js";
@ -220,9 +220,8 @@ export class JsonRpcSigner extends AbstractSigner<JsonRpcApiProvider> {
const _from = tx.from; const _from = tx.from;
promises.push((async () => { promises.push((async () => {
const from = await resolveAddress(_from, this.provider); const from = await resolveAddress(_from, this.provider);
if (from == null || from.toLowerCase() !== this.address.toLowerCase()) { assertArgument(from != null && from.toLowerCase() === this.address.toLowerCase(),
throwArgumentError("from address mismatch", "transaction", _tx); "from address mismatch", "transaction", _tx);
}
tx.from = from; tx.from = from;
})()); })());
} else { } else {
@ -287,9 +286,8 @@ export class JsonRpcSigner extends AbstractSigner<JsonRpcApiProvider> {
// Make sure the from matches the sender // Make sure the from matches the sender
if (tx.from) { if (tx.from) {
const from = await resolveAddress(tx.from, this.provider); const from = await resolveAddress(tx.from, this.provider);
if (from == null || from.toLowerCase() !== this.address.toLowerCase()) { assertArgument(from != null && from.toLowerCase() === this.address.toLowerCase(),
return throwArgumentError("from address mismatch", "transaction", _tx); "from address mismatch", "transaction", _tx);
}
tx.from = from; tx.from = from;
} else { } else {
tx.from = this.address; tx.from = this.address;
@ -312,9 +310,7 @@ export class JsonRpcSigner extends AbstractSigner<JsonRpcApiProvider> {
// Populate any ENS names (in-place) // Populate any ENS names (in-place)
const populated = await TypedDataEncoder.resolveNames(domain, types, value, async (value: string) => { const populated = await TypedDataEncoder.resolveNames(domain, types, value, async (value: string) => {
const address = await resolveAddress(value); const address = await resolveAddress(value);
if (address == null) { assertArgument(address != null, "TypedData does not support null address", "value", value);
return throwArgumentError("TypedData does not support null address", "value", value);
}
return address; return address;
}); });
@ -462,9 +458,8 @@ export class JsonRpcApiProvider extends AbstractProvider {
// This could be relaxed in the future to just check equivalent networks // This could be relaxed in the future to just check equivalent networks
const staticNetwork = this._getOption("staticNetwork"); const staticNetwork = this._getOption("staticNetwork");
if (staticNetwork) { if (staticNetwork) {
if (staticNetwork !== network) { assertArgument(staticNetwork === network,
throwArgumentError("staticNetwork MUST match network object", "options", options); "staticNetwork MUST match network object", "options", options);
}
this.#network = staticNetwork; this.#network = staticNetwork;
} }
} }

@ -3,7 +3,7 @@ import { getAddress } from "../address/index.js";
import { keccak256, Signature } from "../crypto/index.js"; import { keccak256, Signature } from "../crypto/index.js";
import { import {
concat, decodeRlp, encodeRlp, getBytes, getStore, getBigInt, getNumber, hexlify, concat, decodeRlp, encodeRlp, getBytes, getStore, getBigInt, getNumber, hexlify,
setStore, throwArgumentError, toArray, zeroPadValue setStore, assertArgument, toArray, zeroPadValue
} from "../utils/index.js"; } from "../utils/index.js";
import { accessListify } from "./accesslist.js"; import { accessListify } from "./accesslist.js";
@ -56,7 +56,7 @@ function handleData(value: string, param: string): string {
try { try {
return hexlify(value); return hexlify(value);
} catch (error) { } catch (error) {
return throwArgumentError("invalid data", param, value); assertArgument(false, "invalid data", param, value);
} }
} }
@ -64,7 +64,7 @@ function handleAccessList(value: any, param: string): AccessList {
try { try {
return accessListify(value); return accessListify(value);
} catch (error) { } catch (error) {
return throwArgumentError("invalid accessList", param, value); assertArgument(false, "invalid accessList", param, value);
} }
} }
@ -76,16 +76,14 @@ function handleNumber(_value: string, param: string): number {
function handleUint(_value: string, param: string): bigint { function handleUint(_value: string, param: string): bigint {
if (_value === "0x") { return BN_0; } if (_value === "0x") { return BN_0; }
const value = getBigInt(_value, param); const value = getBigInt(_value, param);
if (value > BN_MAX_UINT) { throwArgumentError("value exceeds uint size", param, value); } assertArgument(value <= BN_MAX_UINT, "value exceeds uint size", param, value);
return value; return value;
} }
function formatNumber(_value: BigNumberish, name: string): Uint8Array { function formatNumber(_value: BigNumberish, name: string): Uint8Array {
const value = getBigInt(_value, "value"); const value = getBigInt(_value, "value");
const result = toArray(value); const result = toArray(value);
if (result.length > 32) { assertArgument(result.length <= 32, `value too large`, `tx.${ name }`, value);
throwArgumentError(`value too large`, `tx.${ name }`, value);
}
return result; return result;
} }
@ -96,9 +94,8 @@ function formatAccessList(value: AccessListish): Array<[ string, Array<string> ]
function _parseLegacy(data: Uint8Array): TransactionLike { function _parseLegacy(data: Uint8Array): TransactionLike {
const fields: any = decodeRlp(data); const fields: any = decodeRlp(data);
if (!Array.isArray(fields) || (fields.length !== 9 && fields.length !== 6)) { assertArgument(Array.isArray(fields) && (fields.length === 9 || fields.length === 6),
return throwArgumentError("invalid field count for legacy transaction", "data", data); "invalid field count for legacy transaction", "data", data);
}
const tx: TransactionLike = { const tx: TransactionLike = {
type: 0, type: 0,
@ -130,9 +127,7 @@ function _parseLegacy(data: Uint8Array): TransactionLike {
tx.chainId = chainId tx.chainId = chainId
// Signed Legacy Transaction // Signed Legacy Transaction
if (chainId === BN_0 && (v < BN_27 || v > BN_28)) { assertArgument(chainId !== BN_0 || (v === BN_27 || v === BN_28), "non-canonical legacy v", "v", fields[6]);
throwArgumentError("non-canonical legacy v", "v", fields[6]);
}
tx.signature = Signature.from({ tx.signature = Signature.from({
r: zeroPadValue(fields[7], 32), r: zeroPadValue(fields[7], 32),
@ -163,9 +158,8 @@ function _serializeLegacy(tx: Transaction, sig?: Signature): string {
// We have a chainId in the tx and an EIP-155 v in the signature, // We have a chainId in the tx and an EIP-155 v in the signature,
// make sure they agree with each other // make sure they agree with each other
if (sig && sig.networkV != null && sig.legacyChainId !== chainId) { assertArgument(!sig || sig.networkV == null || sig.legacyChainId === chainId,
throwArgumentError("tx.chainId/sig.v mismatch", "sig", sig); "tx.chainId/sig.v mismatch", "sig", sig);
}
} else if (sig) { } else if (sig) {
// No chainId provided, but the signature is signing with EIP-155; derive chainId // No chainId provided, but the signature is signing with EIP-155; derive chainId
@ -190,7 +184,7 @@ function _serializeLegacy(tx: Transaction, sig?: Signature): string {
if (chainId !== BN_0) { if (chainId !== BN_0) {
v = Signature.getChainIdV(chainId, sig.v); v = Signature.getChainIdV(chainId, sig.v);
} else if (BigInt(sig.v) !== v) { } else if (BigInt(sig.v) !== v) {
throwArgumentError("tx.chainId/sig.v mismatch", "sig", sig); assertArgument(false, "tx.chainId/sig.v mismatch", "sig", sig);
} }
fields.push(toArray(v)); fields.push(toArray(v));
@ -206,7 +200,7 @@ function _parseEipSignature(tx: TransactionLike, fields: Array<string>, serializ
yParity = handleNumber(fields[0], "yParity"); yParity = handleNumber(fields[0], "yParity");
if (yParity !== 0 && yParity !== 1) { throw new Error("bad yParity"); } if (yParity !== 0 && yParity !== 1) { throw new Error("bad yParity"); }
} catch (error) { } catch (error) {
return throwArgumentError("invalid yParity", "yParity", fields[0]); assertArgument(false, "invalid yParity", "yParity", fields[0]);
} }
const r = zeroPadValue(fields[1], 32); const r = zeroPadValue(fields[1], 32);
@ -219,9 +213,8 @@ function _parseEipSignature(tx: TransactionLike, fields: Array<string>, serializ
function _parseEip1559(data: Uint8Array): TransactionLike { function _parseEip1559(data: Uint8Array): TransactionLike {
const fields: any = decodeRlp(getBytes(data).slice(1)); const fields: any = decodeRlp(getBytes(data).slice(1));
if (!Array.isArray(fields) || (fields.length !== 9 && fields.length !== 12)) { assertArgument(Array.isArray(fields) && (fields.length === 9 || fields.length === 12),
throwArgumentError("invalid field count for transaction type: 2", "data", hexlify(data)); "invalid field count for transaction type: 2", "data", hexlify(data));
}
const maxPriorityFeePerGas = handleUint(fields[2], "maxPriorityFeePerGas"); const maxPriorityFeePerGas = handleUint(fields[2], "maxPriorityFeePerGas");
const maxFeePerGas = handleUint(fields[3], "maxFeePerGas"); const maxFeePerGas = handleUint(fields[3], "maxFeePerGas");
@ -274,9 +267,8 @@ function _serializeEip1559(tx: TransactionLike, sig?: Signature): string {
function _parseEip2930(data: Uint8Array): TransactionLike { function _parseEip2930(data: Uint8Array): TransactionLike {
const fields: any = decodeRlp(getBytes(data).slice(1)); const fields: any = decodeRlp(getBytes(data).slice(1));
if (!Array.isArray(fields) || (fields.length !== 8 && fields.length !== 11)) { assertArgument(Array.isArray(fields) && (fields.length === 8 || fields.length === 11),
throwArgumentError("invalid field count for transaction type: 1", "data", hexlify(data)); "invalid field count for transaction type: 1", "data", hexlify(data));
}
const tx: TransactionLike = { const tx: TransactionLike = {
type: 1, type: 1,

@ -1,6 +1,6 @@
import { getBytes } from "./data.js"; import { getBytes } from "./data.js";
import { throwArgumentError } from "./errors.js"; import { assertArgument } from "./errors.js";
import { toBigInt, toHex } from "./maths.js"; import { toBigInt, toHex } from "./maths.js";
import type { BytesLike } from "./index.js"; import type { BytesLike } from "./index.js";
@ -17,9 +17,7 @@ function getAlpha(letter: string): bigint {
} }
} }
const result = Lookup[letter]; const result = Lookup[letter];
if (result == null) { assertArgument(result != null, `invalid base58 value`, "letter", letter);
throwArgumentError(`invalid base58 value`, "letter", letter);
}
return result; return result;
} }

@ -1,4 +1,4 @@
import { throwArgumentError, throwError } from "./errors.js"; import { assertArgument, throwError } from "./errors.js";
export type BytesLike = string | Uint8Array; export type BytesLike = string | Uint8Array;
@ -19,7 +19,7 @@ function _getBytes(value: BytesLike, name?: string, copy?: boolean): Uint8Array
return result; return result;
} }
return throwArgumentError("invalid BytesLike value", name || "value", value); assertArgument(false, "invalid BytesLike value", name || "value", value);
} }
/** /**

@ -327,16 +327,6 @@ export function throwError<K extends ErrorCode, T extends CodedEthersError<K>>(m
throw makeError(message, code, info); throw makeError(message, code, info);
} }
/**
* Throws an [[api:ArgumentError]] with %%message%% for the parameter with
* %%name%% and the %%value%%.
*/
export function throwArgumentError(message: string, name: string, value: any): never {
return throwError(message, "INVALID_ARGUMENT", {
argument: name,
value: value
});
}
/** /**
* A simple helper to simply ensuring provided arguments match expected * A simple helper to simply ensuring provided arguments match expected
@ -346,7 +336,9 @@ export function throwArgumentError(message: string, name: string, value: any): n
* any further code does not need additional compile-time checks. * any further code does not need additional compile-time checks.
*/ */
export function assertArgument(check: unknown, message: string, name: string, value: unknown): asserts check { export function assertArgument(check: unknown, message: string, name: string, value: unknown): asserts check {
if (!check) { throwArgumentError(message, name, value); } if (!check) {
throwError(message, "INVALID_ARGUMENT", { argument: name, value: value });
}
} }
export function assertArgumentCount(count: number, expectedCount: number, message: string = ""): void { export function assertArgumentCount(count: number, expectedCount: number, message: string = ""): void {

@ -1,6 +1,6 @@
import { decodeBase64, encodeBase64 } from "./base64.js"; import { decodeBase64, encodeBase64 } from "./base64.js";
import { hexlify } from "./data.js"; import { hexlify } from "./data.js";
import { assertArgument, throwArgumentError, throwError } from "./errors.js"; import { assertArgument, throwError } from "./errors.js";
import { defineProperties } from "./properties.js"; import { defineProperties } from "./properties.js";
import { toUtf8Bytes, toUtf8String } from "./utf8.js" import { toUtf8Bytes, toUtf8String } from "./utf8.js"
@ -310,9 +310,7 @@ export class FetchRequest implements Iterable<[ key: string, value: string ]> {
* Sets an ``Authorization`` for %%username%% with %%password%%. * Sets an ``Authorization`` for %%username%% with %%password%%.
*/ */
setCredentials(username: string, password: string): void { setCredentials(username: string, password: string): void {
if (username.match(/:/)) { assertArgument(!username.match(/:/), "invalid basic authentication username", "username", "[REDACTED]");
throwArgumentError("invalid basic authentication username", "username", "[REDACTED]");
}
this.#creds = `${ username }:${ password }`; this.#creds = `${ username }:${ password }`;
} }
@ -762,8 +760,8 @@ export class FetchResponse implements Iterable<[ key: string, value: string ]> {
throwThrottleError(message?: string, stall?: number): never { throwThrottleError(message?: string, stall?: number): never {
if (stall == null) { if (stall == null) {
stall = -1; stall = -1;
} else if (typeof(stall) !== "number" || !Number.isInteger(stall) || stall < 0) { } else {
return throwArgumentError("invalid stall timeout", "stall", stall); assertArgument(Number.isInteger(stall) && stall >= 0, "invalid stall timeout", "stall", stall);
} }
const error = new Error(message || "throttling requests"); const error = new Error(message || "throttling requests");

@ -1,5 +1,5 @@
import { getBytes } from "./data.js"; import { getBytes } from "./data.js";
import { throwArgumentError, throwError } from "./errors.js"; import { assertArgument, throwError } from "./errors.js";
import { getBigInt, getNumber, fromTwos, toBigInt, toHex, toTwos } from "./maths.js"; import { getBigInt, getNumber, fromTwos, toBigInt, toHex, toTwos } from "./maths.js";
import type { BigNumberish, BytesLike, Numeric } from "./index.js"; import type { BigNumberish, BytesLike, Numeric } from "./index.js";
@ -22,9 +22,8 @@ while (zeros.length < 256) { zeros += zeros; }
// Returns a string "1" followed by decimal "0"s // Returns a string "1" followed by decimal "0"s
function getMultiplier(decimals: number): bigint { function getMultiplier(decimals: number): bigint {
if (typeof(decimals) !== "number" || decimals < 0 || decimals > 256 || decimals % 1 ) { assertArgument(Number.isInteger(decimals) && decimals >= 0 && decimals <= 256,
throwArgumentError("invalid decimal length", "decimals", decimals); "invalid decimal length", "decimals", decimals);
}
return BigInt("1" + zeros.substring(0, decimals)); return BigInt("1" + zeros.substring(0, decimals));
} }
@ -65,23 +64,18 @@ export function parseFixed(value: string, _decimals: Numeric): bigint {
const multiplier = getMultiplier(decimals); const multiplier = getMultiplier(decimals);
if (typeof(value) !== "string" || !value.match(/^-?[0-9.]+$/)) { assertArgument(typeof(value) === "string" && value.match(/^-?[0-9.]+$/),
throwArgumentError("invalid decimal value", "value", value); "invalid decimal value", "value", value);
}
// Is it negative? // Is it negative?
const negative = (value.substring(0, 1) === "-"); const negative = (value.substring(0, 1) === "-");
if (negative) { value = value.substring(1); } if (negative) { value = value.substring(1); }
if (value === ".") { assertArgument(value !== ".", "missing value", "value", value);
throwArgumentError("missing value", "value", value);
}
// Split it into a whole and fractional part // Split it into a whole and fractional part
const comps = value.split("."); const comps = value.split(".");
if (comps.length > 2) { assertArgument(comps.length <= 2, "too many decimal points", "value", value);
throwArgumentError("too many decimal points", "value", value);
}
let whole = (comps[0] || "0"), fraction = (comps[1] || "0"); let whole = (comps[0] || "0"), fraction = (comps[1] || "0");
@ -155,9 +149,7 @@ export class FixedFormat {
signed = false; signed = false;
} else { } else {
const match = value.match(/^(u?)fixed([0-9]+)x([0-9]+)$/); const match = value.match(/^(u?)fixed([0-9]+)x([0-9]+)$/);
if (!match) { assertArgument(match, "invalid fixed format", "format", value);
return throwArgumentError("invalid fixed format", "format", value);
}
signed = (match[1] !== "u"); signed = (match[1] !== "u");
width = parseInt(match[2]); width = parseInt(match[2]);
decimals = parseInt(match[3]); decimals = parseInt(match[3]);
@ -165,9 +157,8 @@ export class FixedFormat {
} else if (value) { } else if (value) {
const check = (key: string, type: string, defaultValue: any): any => { const check = (key: string, type: string, defaultValue: any): any => {
if (value[key] == null) { return defaultValue; } if (value[key] == null) { return defaultValue; }
if (typeof(value[key]) !== type) { assertArgument(typeof(value[key]) === type,
throwArgumentError("invalid fixed format (" + key + " not " + type +")", "format." + key, value[key]); "invalid fixed format (" + key + " not " + type +")", "format." + key, value[key]);
}
return value[key]; return value[key];
} }
signed = check("signed", "boolean", signed); signed = check("signed", "boolean", signed);
@ -175,13 +166,8 @@ export class FixedFormat {
decimals = check("decimals", "number", decimals); decimals = check("decimals", "number", decimals);
} }
if (width % 8) { assertArgument((width % 8) === 0, "invalid fixed format width (not byte aligned)", "format.width", width);
throwArgumentError("invalid fixed format width (not byte aligned)", "format.width", width); assertArgument(decimals <= 80, "invalid fixed format (decimals too large)", "format.decimals", decimals);
}
if (decimals > 80) {
throwArgumentError("invalid fixed format (decimals too large)", "format.decimals", decimals);
}
return new FixedFormat(_constructorGuard, signed, width, decimals); return new FixedFormat(_constructorGuard, signed, width, decimals);
} }
@ -215,9 +201,8 @@ export class FixedNumber {
} }
#checkFormat(other: FixedNumber): void { #checkFormat(other: FixedNumber): void {
if (this.format.name !== other.format.name) { assertArgument(this.format.name === other.format.name,
throwArgumentError("incompatible format; use fixedNumber.toFormat", "other", other); "incompatible format; use fixedNumber.toFormat", "other", other);
}
} }
/** /**
@ -288,9 +273,8 @@ export class FixedNumber {
const comps = this.toString().split("."); const comps = this.toString().split(".");
if (comps.length === 1) { comps.push("0"); } if (comps.length === 1) { comps.push("0"); }
if (decimals < 0 || decimals > 80 || (decimals % 1)) { assertArgument(Number.isInteger(decimals) && decimals >= 0 && decimals <= 80,
throwArgumentError("invalid decimal count", "decimals", decimals); "invalid decimal count", "decimals", decimals);
}
if (comps[1].length <= decimals) { return this; } if (comps[1].length <= decimals) { return this; }
@ -391,7 +375,7 @@ export class FixedNumber {
} }
} }
return throwArgumentError("invalid FixedNumber value", "value", value); assertArgument(false, "invalid FixedNumber value", "value", value);
} }
static isFixedNumber(value: any): value is FixedNumber { static isFixedNumber(value: any): value is FixedNumber {

@ -25,7 +25,7 @@ export {
export { export {
isCallException, isError, isCallException, isError,
makeError, throwError, throwArgumentError, makeError, throwError,
assertArgument, assertArgumentCount, assertPrivate, assertNormalize assertArgument, assertArgumentCount, assertPrivate, assertNormalize
} from "./errors.js" } from "./errors.js"
@ -53,7 +53,6 @@ export { getStore, setStore} from "./storage.js";
export { formatEther, parseEther, formatUnits, parseUnits } from "./units.js"; export { formatEther, parseEther, formatUnits, parseUnits } from "./units.js";
export { export {
_toEscapedUtf8String,
toUtf8Bytes, toUtf8Bytes,
toUtf8CodePoints, toUtf8CodePoints,
toUtf8String, toUtf8String,

@ -1,5 +1,5 @@
import { hexlify, isBytesLike } from "./data.js"; import { hexlify, isBytesLike } from "./data.js";
import { throwArgumentError } from "./errors.js"; import { assertArgument } from "./errors.js";
import type { BytesLike } from "./data.js"; import type { BytesLike } from "./data.js";
@ -68,11 +68,8 @@ export function getBigInt(value: BigNumberish, name?: string): bigint {
switch (typeof(value)) { switch (typeof(value)) {
case "bigint": return value; case "bigint": return value;
case "number": case "number":
if (!Number.isInteger(value)) { assertArgument(Number.isInteger(value), "underflow", name || "value", value);
throwArgumentError("underflow", name || "value", value); assertArgument(value >= -maxValue && value <= maxValue, "overflow", name || "value", value);
} else if (value < -maxValue || value > maxValue) {
throwArgumentError("overflow", name || "value", value);
}
return BigInt(value); return BigInt(value);
case "string": case "string":
try { try {
@ -81,10 +78,10 @@ export function getBigInt(value: BigNumberish, name?: string): bigint {
} }
return BigInt(value); return BigInt(value);
} catch(e: any) { } catch(e: any) {
throwArgumentError(`invalid BigNumberish string: ${ e.message }`, name || "value", value); assertArgument(false, `invalid BigNumberish string: ${ e.message }`, name || "value", value);
} }
} }
return throwArgumentError("invalid BigNumberish value", name || "value", value); assertArgument(false, "invalid BigNumberish value", name || "value", value);
} }
@ -114,25 +111,20 @@ export function toBigInt(value: BigNumberish | Uint8Array): bigint {
export function getNumber(value: BigNumberish, name?: string): number { export function getNumber(value: BigNumberish, name?: string): number {
switch (typeof(value)) { switch (typeof(value)) {
case "bigint": case "bigint":
if (value < -maxValue || value > maxValue) { assertArgument(value >= -maxValue && value <= maxValue, "overflow", name || "value", value);
throwArgumentError("overflow", name || "value", value);
}
return Number(value); return Number(value);
case "number": case "number":
if (!Number.isInteger(value)) { assertArgument(Number.isInteger(value), "underflow", name || "value", value);
throwArgumentError("underflow", name || "value", value); assertArgument(value >= -maxValue && value <= maxValue, "overflow", name || "value", value);
} else if (value < -maxValue || value > maxValue) {
throwArgumentError("overflow", name || "value", value);
}
return value; return value;
case "string": case "string":
try { try {
return getNumber(BigInt(value), name); return getNumber(BigInt(value), name);
} catch(e: any) { } catch(e: any) {
throwArgumentError(`invalid numeric string: ${ e.message }`, name || "value", value); assertArgument(false, `invalid numeric string: ${ e.message }`, name || "value", value);
} }
} }
return throwArgumentError("invalid numeric value", name || "value", value); assertArgument(false, "invalid numeric value", name || "value", value);
} }

@ -1,7 +1,7 @@
//See: https://github.com/ethereum/wiki/wiki/RLP //See: https://github.com/ethereum/wiki/wiki/RLP
import { hexlify } from "./data.js"; import { hexlify } from "./data.js";
import { throwArgumentError, throwError } from "./errors.js"; import { assertArgument, throwError } from "./errors.js";
import { getBytes } from "./data.js"; import { getBytes } from "./data.js";
import type { BytesLike, RlpStructuredData } from "./index.js"; import type { BytesLike, RlpStructuredData } from "./index.js";
@ -104,9 +104,7 @@ function _decode(data: Uint8Array, offset: number): { consumed: number, result:
export function decodeRlp(_data: BytesLike): RlpStructuredData { export function decodeRlp(_data: BytesLike): RlpStructuredData {
const data = getBytes(_data, "data"); const data = getBytes(_data, "data");
const decoded = _decode(data, 0); const decoded = _decode(data, 0);
if (decoded.consumed !== data.length) { assertArgument(decoded.consumed === data.length, "unexpected junk after rlp payload", "data", _data);
throwArgumentError("unexpected junk after rlp payload", "data", _data);
}
return decoded.result; return decoded.result;
} }

@ -1,5 +1,5 @@
import { formatFixed, parseFixed } from "./fixednumber.js"; import { formatFixed, parseFixed } from "./fixednumber.js";
import { throwArgumentError } from "./errors.js"; import { assertArgument } from "./errors.js";
import type { BigNumberish, Numeric } from "../utils/index.js"; import type { BigNumberish, Numeric } from "../utils/index.js";
@ -23,7 +23,7 @@ const names = [
export function formatUnits(value: BigNumberish, unit?: string | Numeric): string { export function formatUnits(value: BigNumberish, unit?: string | Numeric): string {
if (typeof(unit) === "string") { if (typeof(unit) === "string") {
const index = names.indexOf(unit); const index = names.indexOf(unit);
if (index === -1) { throwArgumentError("invalid unit", "unit", unit); } assertArgument(index >= 0, "invalid unit", "unit", unit);
unit = 3 * index; unit = 3 * index;
} }
return formatFixed(value, (unit != null) ? unit: 18); return formatFixed(value, (unit != null) ? unit: 18);
@ -35,15 +35,14 @@ export function formatUnits(value: BigNumberish, unit?: string | Numeric): strin
* or the name of a unit (e.g. ``"gwei"`` for 9 decimal places). * or the name of a unit (e.g. ``"gwei"`` for 9 decimal places).
*/ */
export function parseUnits(value: string, unit?: string | Numeric): bigint { export function parseUnits(value: string, unit?: string | Numeric): bigint {
if (typeof(value) !== "string") { assertArgument(typeof(value) === "string", "value must be a string", "value", value);
throwArgumentError("value must be a string", "value", value);
}
if (typeof(unit) === "string") { if (typeof(unit) === "string") {
const index = names.indexOf(unit); const index = names.indexOf(unit);
if (index === -1) { throwArgumentError("invalid unit", "unit", unit); } assertArgument(index >= 0, "invalid unit", "unit", unit);
unit = 3 * index; unit = 3 * index;
} }
return parseFixed(value, (unit != null) ? unit: 18); return parseFixed(value, (unit != null) ? unit: 18);
} }

@ -1,5 +1,5 @@
import { getBytes } from "./data.js"; import { getBytes } from "./data.js";
import { assertNormalize, throwArgumentError } from "./errors.js"; import { assertArgument, assertNormalize } from "./errors.js";
import type { BytesLike } from "./index.js"; import type { BytesLike } from "./index.js";
@ -44,10 +44,8 @@ export type Utf8ErrorReason =
export type Utf8ErrorFunc = (reason: Utf8ErrorReason, offset: number, bytes: ArrayLike<number>, output: Array<number>, badCodepoint?: number) => number; 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 { function errorFunc(reason: Utf8ErrorReason, offset: number, bytes: ArrayLike<number>, output: Array<number>, badCodepoint?: number): number {
return throwArgumentError(`invalid codepoint at offset ${ offset }; ${ reason }`, "bytes", bytes); assertArgument(false, `invalid codepoint at offset ${ offset }; ${ reason }`, "bytes", bytes);
} }
function ignoreFunc(reason: Utf8ErrorReason, offset: number, bytes: ArrayLike<number>, output: Array<number>, badCodepoint?: number): number { function ignoreFunc(reason: Utf8ErrorReason, offset: number, bytes: ArrayLike<number>, output: Array<number>, badCodepoint?: number): number {
@ -215,9 +213,8 @@ export function toUtf8Bytes(str: string, form?: UnicodeNormalizationForm): Uint8
i++; i++;
const c2 = str.charCodeAt(i); const c2 = str.charCodeAt(i);
if (i >= str.length || (c2 & 0xfc00) !== 0xdc00) { assertArgument(i < str.length && ((c2 & 0xfc00) === 0xdc00),
throw new Error("invalid utf-8 string"); "invalid surrogate pair", "str", str);
}
// Surrogate Pair // Surrogate Pair
const pair = 0x10000 + ((c & 0x03ff) << 10) + (c2 & 0x03ff); const pair = 0x10000 + ((c & 0x03ff) << 10) + (c2 & 0x03ff);
@ -236,37 +233,6 @@ export function toUtf8Bytes(str: string, form?: UnicodeNormalizationForm): Uint8
return new Uint8Array(result); return new Uint8Array(result);
}; };
function escapeChar(value: number): string {
const hex = ("0000" + value.toString(16));
return "\\u" + hex.substring(hex.length - 4);
}
export function _toEscapedUtf8String(bytes: BytesLike, onError?: Utf8ErrorFunc): string {
return '"' + getUtf8CodePoints(bytes, onError).map((codePoint) => {
if (codePoint < 256) {
switch (codePoint) {
case 8: return "\\b";
case 9: return "\\t";
case 10: return "\\n"
case 13: return "\\r";
case 34: return "\\\"";
case 92: return "\\\\";
}
if (codePoint >= 32 && codePoint < 127) {
return String.fromCharCode(codePoint);
}
}
if (codePoint <= 0xffff) {
return escapeChar(codePoint);
}
codePoint -= 0x10000;
return escapeChar(((codePoint >> 10) & 0x3ff) + 0xd800) + escapeChar((codePoint & 0x3ff) + 0xdc00);
}).join("") + '"';
}
export function _toUtf8String(codePoints: Array<number>): string { export function _toUtf8String(codePoints: Array<number>): string {
return codePoints.map((codePoint) => { return codePoints.map((codePoint) => {
if (codePoint <= 0xffff) { if (codePoint <= 0xffff) {

@ -3,7 +3,7 @@ import { hashMessage, TypedDataEncoder } from "../hash/index.js";
import { AbstractSigner } from "../providers/index.js"; import { AbstractSigner } from "../providers/index.js";
import { computeAddress, Transaction } from "../transaction/index.js"; import { computeAddress, Transaction } from "../transaction/index.js";
import { import {
defineProperties, resolveProperties, throwArgumentError, throwError defineProperties, resolveProperties, assertArgument, throwError
} from "../utils/index.js"; } from "../utils/index.js";
import type { SigningKey } from "../crypto/index.js"; import type { SigningKey } from "../crypto/index.js";
@ -46,9 +46,8 @@ export class BaseWallet extends AbstractSigner {
if (from != null) { tx.from = from; } if (from != null) { tx.from = from; }
if (tx.from != null) { if (tx.from != null) {
if (getAddress(<string>(tx.from)) !== this.address) { assertArgument(getAddress(<string>(tx.from)) === this.address,
throwArgumentError("transaction from address mismatch", "tx.from", tx.from); "transaction from address mismatch", "tx.from", tx.from);
}
delete tx.from; delete tx.from;
} }

@ -5,7 +5,7 @@ import {
concat, dataSlice, decodeBase58, defineProperties, encodeBase58, concat, dataSlice, decodeBase58, defineProperties, encodeBase58,
getBytes, hexlify, getBytes, hexlify,
getNumber, toBigInt, toHex, getNumber, toBigInt, toHex,
assertPrivate, throwArgumentError, throwError assertPrivate, assertArgument, throwError
} from "../utils/index.js"; } from "../utils/index.js";
import { langEn } from "../wordlists/lang-en.js"; import { langEn } from "../wordlists/lang-en.js";
@ -216,9 +216,8 @@ export class HDNodeWallet extends BaseWallet {
static fromExtendedKey(extendedKey: string): HDNodeWallet | HDNodeVoidWallet { static fromExtendedKey(extendedKey: string): HDNodeWallet | HDNodeVoidWallet {
const bytes = getBytes(decodeBase58(extendedKey)); // @TODO: redact const bytes = getBytes(decodeBase58(extendedKey)); // @TODO: redact
if (bytes.length !== 82 || encodeBase58Check(bytes.slice(0, 78)) !== extendedKey) { assertArgument(bytes.length === 82 || encodeBase58Check(bytes.slice(0, 78)) === extendedKey,
throwArgumentError("invalid extended key", "extendedKey", "[ REDACTED ]"); "invalid extended key", "extendedKey", "[ REDACTED ]");
}
const depth = bytes[4]; const depth = bytes[4];
const parentFingerprint = hexlify(bytes.slice(5, 9)); const parentFingerprint = hexlify(bytes.slice(5, 9));
@ -242,7 +241,7 @@ export class HDNodeWallet extends BaseWallet {
} }
return throwArgumentError("invalid extended key prefix", "extendedKey", "[ REDACTED ]"); assertArgument(false, "invalid extended key prefix", "extendedKey", "[ REDACTED ]");
} }
static createRandom(password: string = "", path: null | string = defaultPath, wordlist: Wordlist = langEn): HDNodeWallet { static createRandom(password: string = "", path: null | string = defaultPath, wordlist: Wordlist = langEn): HDNodeWallet {
@ -342,9 +341,7 @@ export class HDNodeWalletManager {
export function getAccountPath(_index: Numeric): string { export function getAccountPath(_index: Numeric): string {
const index = getNumber(_index, "index"); const index = getNumber(_index, "index");
if (index < 0 || index >= HardenedBit) { assertArgument(index >= 0 && index < HardenedBit, "invalid account index", "index", index);
throwArgumentError("invalid account index", "index", index);
}
return `m/44'/60'/${ index }'/0/0`; return `m/44'/60'/${ index }'/0/0`;
} }

@ -3,7 +3,7 @@ import { CBC, pkcs7Strip } from "aes-js";
import { getAddress } from "../address/index.js"; import { getAddress } from "../address/index.js";
import { pbkdf2 } from "../crypto/index.js"; import { pbkdf2 } from "../crypto/index.js";
import { id } from "../hash/index.js"; import { id } from "../hash/index.js";
import { getBytes, throwArgumentError } from "../utils/index.js"; import { getBytes, assertArgument } from "../utils/index.js";
import { getPassword, looseArrayify, spelunk } from "./utils.js"; import { getPassword, looseArrayify, spelunk } from "./utils.js";
@ -31,9 +31,7 @@ export function decryptCrowdsaleJson(json: string, _password: string | Uint8Arra
// Encrypted Seed // Encrypted Seed
const encseed = looseArrayify(spelunk(data, "encseed:string!")); const encseed = looseArrayify(spelunk(data, "encseed:string!"));
if (!encseed || (encseed.length % 16) !== 0) { assertArgument(encseed && (encseed.length % 16) === 0, "invalid encseed", "json", json);
throwArgumentError("invalid encseed", "json", json);
}
const key = getBytes(pbkdf2(password, password, 2000, 32, "sha256")).slice(0, 16); const key = getBytes(pbkdf2(password, password, 2000, 32, "sha256")).slice(0, 16);

@ -4,7 +4,7 @@ import { getAddress } from "../address/index.js";
import { keccak256, pbkdf2, randomBytes, scrypt, scryptSync } from "../crypto/index.js"; import { keccak256, pbkdf2, randomBytes, scrypt, scryptSync } from "../crypto/index.js";
import { computeAddress } from "../transaction/index.js"; import { computeAddress } from "../transaction/index.js";
import { import {
concat, getBytes, hexlify, throwArgumentError, throwError concat, getBytes, hexlify, assertArgument, throwError
} from "../utils/index.js"; } from "../utils/index.js";
import { getPassword, spelunk, uuidV4, zpad } from "./utils.js"; import { getPassword, spelunk, uuidV4, zpad } from "./utils.js";
@ -77,9 +77,8 @@ function getAccount(data: any, _key: string): KeystoreAccount {
const ciphertext = spelunk<Uint8Array>(data, "crypto.ciphertext:data!"); const ciphertext = spelunk<Uint8Array>(data, "crypto.ciphertext:data!");
const computedMAC = hexlify(keccak256(concat([ key.slice(16, 32), ciphertext ]))).substring(2); const computedMAC = hexlify(keccak256(concat([ key.slice(16, 32), ciphertext ]))).substring(2);
if (computedMAC !== spelunk(data, "crypto.mac:string!").toLowerCase()) { assertArgument(computedMAC === spelunk(data, "crypto.mac:string!").toLowerCase(),
return throwArgumentError("incorrect password", "password", "[ REDACTED ]"); "incorrect password", "password", "[ REDACTED ]");
}
const privateKey = decrypt(data, key.slice(0, 16), ciphertext); const privateKey = decrypt(data, key.slice(0, 16), ciphertext);
@ -88,9 +87,7 @@ function getAccount(data: any, _key: string): KeystoreAccount {
let check = data.address.toLowerCase(); let check = data.address.toLowerCase();
if (check.substring(0, 2) !== "0x") { check = "0x" + check; } if (check.substring(0, 2) !== "0x") { check = "0x" + check; }
if (getAddress(check) !== address) { assertArgument(getAddress(check) === address, "keystore address/privateKey mismatch", "address", data.address);
throwArgumentError("keystore address/privateKey mismatch", "address", data.address);
}
} }
const account: KeystoreAccount = { address, privateKey }; const account: KeystoreAccount = { address, privateKey };
@ -134,7 +131,7 @@ function getKdfParams<T>(data: any): KdfParams {
const kdf = spelunk(data, "crypto.kdf:string"); const kdf = spelunk(data, "crypto.kdf:string");
if (kdf && typeof(kdf) === "string") { if (kdf && typeof(kdf) === "string") {
const throwError = function(name: string, value: any): never { const throwError = function(name: string, value: any): never {
return throwArgumentError("invalid key-derivation function parameters", name, value); assertArgument(false, "invalid key-derivation function parameters", name, value);
} }
if (kdf.toLowerCase() === "scrypt") { if (kdf.toLowerCase() === "scrypt") {
@ -173,7 +170,7 @@ function getKdfParams<T>(data: any): KdfParams {
} }
} }
return throwArgumentError("unsupported key-derivation function", "kdf", kdf); assertArgument(false, "unsupported key-derivation function", "kdf", kdf);
} }
@ -275,15 +272,11 @@ export async function encryptKeystoreJson(account: KeystoreAccount, password: st
// Override initialization vector // Override initialization vector
const iv = (options.iv != null) ? getBytes(options.iv, "options.iv"): randomBytes(16); const iv = (options.iv != null) ? getBytes(options.iv, "options.iv"): randomBytes(16);
if (iv.length !== 16) { assertArgument(iv.length === 16, "invalid options.iv", "options.iv", options.iv);
throwArgumentError("invalid options.iv", "options.iv", options.iv);
}
// Override the uuid // Override the uuid
const uuidRandom = (options.uuid != null) ? getBytes(options.uuid, "options.uuid"): randomBytes(16); const uuidRandom = (options.uuid != null) ? getBytes(options.uuid, "options.uuid"): randomBytes(16);
if (uuidRandom.length !== 16) { assertArgument(uuidRandom.length === 16, "invalid options.uuid", "options.uuid", options.iv);
throwArgumentError("invalid options.uuid", "options.uuid", options.iv);
}
if (uuidRandom.length !== 16) { throw new Error("invalid uuid"); } if (uuidRandom.length !== 16) { throw new Error("invalid uuid"); }
// Override the scrypt password-based key derivation function parameters // Override the scrypt password-based key derivation function parameters

@ -1,6 +1,6 @@
import { pbkdf2, sha256 } from "../crypto/index.js"; import { pbkdf2, sha256 } from "../crypto/index.js";
import { import {
defineProperties, getBytes, hexlify, assertNormalize, assertPrivate, throwArgumentError, toUtf8Bytes defineProperties, getBytes, hexlify, assertNormalize, assertPrivate, assertArgument, toUtf8Bytes
} from "../utils/index.js"; } from "../utils/index.js";
import { langEn } from "../wordlists/lang-en.js"; import { langEn } from "../wordlists/lang-en.js";
@ -25,18 +25,15 @@ function mnemonicToEntropy(mnemonic: string, wordlist: null | Wordlist = langEn)
if (wordlist == null) { wordlist = langEn; } if (wordlist == null) { wordlist = langEn; }
const words = wordlist.split(mnemonic); const words = wordlist.split(mnemonic);
if ((words.length % 3) !== 0 || words.length < 12 || words.length > 24) { assertArgument((words.length % 3) === 0 && words.length >= 12 && words.length <= 24,
throwArgumentError("invalid mnemonic length", "mnemonic", "[ REDACTED ]"); "invalid mnemonic length", "mnemonic", "[ REDACTED ]");
}
const entropy = new Uint8Array(Math.ceil(11 * words.length / 8)); const entropy = new Uint8Array(Math.ceil(11 * words.length / 8));
let offset = 0; let offset = 0;
for (let i = 0; i < words.length; i++) { for (let i = 0; i < words.length; i++) {
let index = wordlist.getWordIndex(words[i].normalize("NFKD")); let index = wordlist.getWordIndex(words[i].normalize("NFKD"));
if (index === -1) { assertArgument(index >= 0, `invalid mnemonic word at index ${ i }`, "mnemonic", "[ REDACTED ]");
throwArgumentError(`invalid mnemonic word at index ${ i }`, "mnemonic", "[ REDACTED ]");
}
for (let bit = 0; bit < 11; bit++) { for (let bit = 0; bit < 11; bit++) {
if (index & (1 << (10 - bit))) { if (index & (1 << (10 - bit))) {
@ -54,17 +51,15 @@ function mnemonicToEntropy(mnemonic: string, wordlist: null | Wordlist = langEn)
const checksum = 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)) { assertArgument(checksum === (entropy[entropy.length - 1] & checksumMask),
throwArgumentError("invalid mnemonic checksum", "mnemonic", "[ REDACTED ]"); "invalid mnemonic checksum", "mnemonic", "[ REDACTED ]");
}
return hexlify(entropy.slice(0, entropyBits / 8)); return hexlify(entropy.slice(0, entropyBits / 8));
} }
function entropyToMnemonic(entropy: Uint8Array, wordlist: null | Wordlist = langEn): string { function entropyToMnemonic(entropy: Uint8Array, wordlist: null | Wordlist = langEn): string {
if ((entropy.length % 4) || entropy.length < 16 || entropy.length > 32) { assertArgument((entropy.length % 4) === 0 && entropy.length >= 16 && entropy.length <= 32,
throwArgumentError("invalid entropy size", "entropy", "[ REDACTED ]"); "invalid entropy size", "entropy", "[ REDACTED ]");
}
if (wordlist == null) { wordlist = langEn; } if (wordlist == null) { wordlist = langEn; }

@ -1,5 +1,5 @@
import { import {
getBytes, getBytesCopy, hexlify, throwArgumentError, toUtf8Bytes getBytes, getBytesCopy, hexlify, assertArgument, toUtf8Bytes
} from "../utils/index.js"; } from "../utils/index.js";
import type { BytesLike } from "../utils/index.js"; import type { BytesLike } from "../utils/index.js";
@ -28,9 +28,8 @@ export function getPassword(password: string | Uint8Array): Uint8Array {
export function spelunk<T = string>(object: any, _path: string): T { export function spelunk<T = string>(object: any, _path: string): T {
const match = _path.match(/^([a-z0-9$_.-]*)(:([a-z]+))?(!)?$/i); const match = _path.match(/^([a-z0-9$_.-]*)(:([a-z]+))?(!)?$/i);
if (match == null) { assertArgument(match != null, "invalid path", "path", _path);
return throwArgumentError("invalid path", "path", _path);
}
const path = match[1]; const path = match[1];
const type = match[3]; const type = match[3];
const reqd = (match[4] === "!"); const reqd = (match[4] === "!");
@ -60,9 +59,7 @@ export function spelunk<T = string>(object: any, _path: string): T {
if (cur == null) { break; } if (cur == null) { break; }
} }
if (reqd && cur == null) { assertArgument(!reqd || cur != null, "missing required value", "path", path);
throwArgumentError("missing required value", "path", path);
}
if (type && cur != null) { if (type && cur != null) {
if (type === "int") { if (type === "int") {
@ -86,7 +83,7 @@ export function spelunk<T = string>(object: any, _path: string): T {
if (type === "array" && Array.isArray(cur)) { return <T><unknown>cur; } if (type === "array" && Array.isArray(cur)) { return <T><unknown>cur; }
if (type === typeof(cur)) { return cur; } if (type === typeof(cur)) { return cur; }
throwArgumentError(`wrong type found for ${ type } `, "path", path); assertArgument(false, `wrong type found for ${ type } `, "path", path);
} }
return cur; return cur;

@ -1,6 +1,6 @@
import { randomBytes, SigningKey } from "../crypto/index.js"; import { randomBytes, SigningKey } from "../crypto/index.js";
import { computeAddress } from "../transaction/index.js"; import { computeAddress } from "../transaction/index.js";
import { isHexString, throwArgumentError } from "../utils/index.js"; import { isHexString, assertArgument } from "../utils/index.js";
import { BaseWallet } from "./base-wallet.js"; import { BaseWallet } from "./base-wallet.js";
import { HDNodeWallet } from "./hdwallet.js"; import { HDNodeWallet } from "./hdwallet.js";
@ -89,9 +89,7 @@ export class Wallet extends BaseWallet {
// A signing key // A signing key
if (signingKey == null) { signingKey = trySigningKey(key); } if (signingKey == null) { signingKey = trySigningKey(key); }
if (signingKey == null) { assertArgument(signingKey != null, "invalid key", "key", "[ REDACTED ]");
throwArgumentError("invalid key", "key", "[ REDACTED ]");
}
super(signingKey as SigningKey, provider); super(signingKey as SigningKey, provider);
this.#mnemonic = mnemonic; this.#mnemonic = mnemonic;
@ -123,13 +121,12 @@ export class Wallet extends BaseWallet {
if (progress) { progress(1); await stall(0); } if (progress) { progress(1); await stall(0); }
} else { } else {
return throwArgumentError("invalid JSON wallet", "json", "[ REDACTED ]"); assertArgument(false, "invalid JSON wallet", "json", "[ REDACTED ]");
} }
const wallet = new Wallet(account.privateKey); const wallet = new Wallet(account.privateKey);
if (wallet.address !== account.address) { assertArgument(wallet.address === account.address,
throwArgumentError("address/privateKey mismatch", "json", "[ REDACTED ]"); "address/privateKey mismatch", "json", "[ REDACTED ]");
}
// @TODO: mnemonic // @TODO: mnemonic
return wallet; return wallet;
} }
@ -141,13 +138,12 @@ export class Wallet extends BaseWallet {
} else if (isCrowdsaleJson(json)) { } else if (isCrowdsaleJson(json)) {
account = decryptCrowdsaleJson(json, password); account = decryptCrowdsaleJson(json, password);
} else { } else {
return throwArgumentError("invalid JSON wallet", "json", "[ REDACTED ]"); assertArgument(false, "invalid JSON wallet", "json", "[ REDACTED ]");
} }
const wallet = new Wallet(account.privateKey); const wallet = new Wallet(account.privateKey);
if (wallet.address !== account.address) { assertArgument(wallet.address === account.address,
throwArgumentError("address/privateKey mismatch", "json", "[ REDACTED ]"); "address/privateKey mismatch", "json", "[ REDACTED ]");
}
// @TODO: mnemonic // @TODO: mnemonic
return wallet; return wallet;
} }

@ -1,6 +1,6 @@
import { id } from "../hash/index.js"; import { id } from "../hash/index.js";
import { import {
hexlify, throwArgumentError, toUtf8Bytes, toUtf8String hexlify, assertArgument, toUtf8Bytes, toUtf8String
} from "../utils/index.js"; } from "../utils/index.js";
import { Wordlist } from "./wordlist.js"; import { Wordlist } from "./wordlist.js";
@ -136,9 +136,8 @@ class LangJa extends Wordlist {
getWord(index: number): string { getWord(index: number): string {
const words = loadWords(); const words = loadWords();
if (index < 0 || index >= words.length) { assertArgument(index >= 0 && index < words.length,
throwArgumentError(`invalid word index: ${ index }`, "index", index); `invalid word index: ${ index }`, "index", index);
}
return words[index]; return words[index];
} }

@ -1,5 +1,5 @@
import { id } from "../hash/index.js"; import { id } from "../hash/index.js";
import { throwArgumentError, toUtf8String } from "../utils/index.js"; import { assertArgument, toUtf8String } from "../utils/index.js";
import { Wordlist } from "./wordlist.js"; import { Wordlist } from "./wordlist.js";
@ -69,9 +69,8 @@ class LangKo extends Wordlist {
getWord(index: number): string { getWord(index: number): string {
const words = loadWords(); const words = loadWords();
if (index < 0 || index >= words.length) { assertArgument(index >= 0 && index < words.length,
throwArgumentError(`invalid word index: ${ index }`, "index", index); `invalid word index: ${ index }`, "index", index);
}
return words[index]; return words[index];
} }

@ -1,5 +1,5 @@
import { id } from "../hash/index.js"; import { id } from "../hash/index.js";
import { throwArgumentError, toUtf8String } from "../utils/index.js"; import { assertArgument, toUtf8String } from "../utils/index.js";
import { Wordlist } from "./wordlist.js"; import { Wordlist } from "./wordlist.js";
@ -63,9 +63,8 @@ class LangZh extends Wordlist {
getWord(index: number): string { getWord(index: number): string {
const words = loadWords(this.locale); const words = loadWords(this.locale);
if (index < 0 || index >= words.length) { assertArgument(index >= 0 && index < words.length,
throwArgumentError(`invalid word index: ${ index }`, "index", index); `invalid word index: ${ index }`, "index", index);
}
return words[index]; return words[index];
} }

@ -3,7 +3,7 @@
// data files to be consumed by this class // data files to be consumed by this class
import { id } from "../hash/index.js"; import { id } from "../hash/index.js";
import { throwArgumentError } from "../utils/index.js"; import { assertArgument } from "../utils/index.js";
import { decodeOwl } from "./decode-owl.js"; import { decodeOwl } from "./decode-owl.js";
import { Wordlist } from "./wordlist.js"; import { Wordlist } from "./wordlist.js";
@ -45,9 +45,7 @@ export class WordlistOwl extends Wordlist {
getWord(index: number): string { getWord(index: number): string {
const words = this.#loadWords(); const words = this.#loadWords();
if (index < 0 || index >= words.length) { assertArgument(index >= 0 && index < words.length, `invalid word index: ${ index }`, "index", index);
throwArgumentError(`invalid word index: ${ index }`, "index", index);
}
return words[index]; return words[index];
} }