Replaced logger class with simpler functions.
This commit is contained in:
parent
2740976d8b
commit
29949a6309
@ -1,6 +1,6 @@
|
|||||||
// See: https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
|
// See: https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
|
||||||
|
|
||||||
import { logger } from "../utils/logger.js";
|
import { assertArgumentCount, throwArgumentError } from "../utils/index.js";
|
||||||
|
|
||||||
import { Coder, Reader, Result, Writer } from "./coders/abstract-coder.js";
|
import { Coder, Reader, Result, Writer } from "./coders/abstract-coder.js";
|
||||||
import { AddressCoder } from "./coders/address.js";
|
import { AddressCoder } from "./coders/address.js";
|
||||||
@ -49,7 +49,7 @@ export class AbiCoder {
|
|||||||
if (match) {
|
if (match) {
|
||||||
let size = parseInt(match[2] || "256");
|
let size = parseInt(match[2] || "256");
|
||||||
if (size === 0 || size > 256 || (size % 8) !== 0) {
|
if (size === 0 || size > 256 || (size % 8) !== 0) {
|
||||||
logger.throwArgumentError("invalid " + match[1] + " bit length", "param", param);
|
throwArgumentError("invalid " + match[1] + " bit length", "param", param);
|
||||||
}
|
}
|
||||||
return new NumberCoder(size / 8, (match[1] === "int"), param.name);
|
return new NumberCoder(size / 8, (match[1] === "int"), param.name);
|
||||||
}
|
}
|
||||||
@ -59,12 +59,12 @@ export class AbiCoder {
|
|||||||
if (match) {
|
if (match) {
|
||||||
let size = parseInt(match[1]);
|
let size = parseInt(match[1]);
|
||||||
if (size === 0 || size > 32) {
|
if (size === 0 || size > 32) {
|
||||||
logger.throwArgumentError("invalid bytes length", "param", param);
|
throwArgumentError("invalid bytes length", "param", param);
|
||||||
}
|
}
|
||||||
return new FixedBytesCoder(size, param.name);
|
return new FixedBytesCoder(size, param.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return logger.throwArgumentError("invalid type", "type", param.type);
|
return throwArgumentError("invalid type", "type", param.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
getDefaultValue(types: ReadonlyArray<string | ParamType>): Result {
|
getDefaultValue(types: ReadonlyArray<string | ParamType>): Result {
|
||||||
@ -74,7 +74,7 @@ export class AbiCoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
encode(types: ReadonlyArray<string | ParamType>, values: ReadonlyArray<any>): string {
|
encode(types: ReadonlyArray<string | ParamType>, values: ReadonlyArray<any>): string {
|
||||||
logger.assertArgumentCount(values.length, types.length, "types/values length mismatch");
|
assertArgumentCount(values.length, types.length, "types/values length mismatch");
|
||||||
|
|
||||||
const coders = types.map((type) => this.#getCoder(ParamType.from(type)));
|
const coders = types.map((type) => this.#getCoder(ParamType.from(type)));
|
||||||
const coder = (new TupleCoder(coders, "_"));
|
const coder = (new TupleCoder(coders, "_"));
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
|
|
||||||
import { zeroPadBytes } from "../utils/data.js";
|
import {
|
||||||
|
getBytes, toUtf8Bytes, toUtf8String, zeroPadBytes
|
||||||
import { logger } from "../utils/logger.js";
|
} from "../utils/index.js";
|
||||||
|
|
||||||
import { toUtf8Bytes, toUtf8String } from "../utils/utf8.js";
|
|
||||||
|
|
||||||
import type { BytesLike } from "../utils/index.js";
|
import type { BytesLike } from "../utils/index.js";
|
||||||
|
|
||||||
@ -21,7 +19,7 @@ export function formatBytes32String(text: string): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function parseBytes32String(_bytes: BytesLike): string {
|
export function parseBytes32String(_bytes: BytesLike): string {
|
||||||
const data = logger.getBytes(_bytes, "bytes");
|
const data = getBytes(_bytes, "bytes");
|
||||||
|
|
||||||
// Must be 32 bytes with a null-termination
|
// Must be 32 bytes with a null-termination
|
||||||
if (data.length !== 32) { throw new Error("invalid bytes32 - not 32 bytes long"); }
|
if (data.length !== 32) { throw new Error("invalid bytes32 - not 32 bytes long"); }
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
|
|
||||||
import { toArray, toBigInt, toNumber } from "../../utils/maths.js";
|
import {
|
||||||
import { concat, hexlify } from "../../utils/data.js";
|
defineProperties, concat, getBytesCopy, getNumber, hexlify,
|
||||||
import { defineProperties } from "../../utils/properties.js";
|
toArray, toBigInt, toNumber,
|
||||||
|
assertPrivate, throwArgumentError, throwError
|
||||||
import { logger } from "../../utils/logger.js";
|
} from "../../utils/index.js";
|
||||||
|
|
||||||
import type { BigNumberish, BytesLike } from "../../utils/index.js";
|
import type { BigNumberish, BytesLike } from "../../utils/index.js";
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ export class Result extends Array<any> {
|
|||||||
[ K: string | number ]: any
|
[ K: string | number ]: any
|
||||||
|
|
||||||
constructor(guard: any, items: Array<any>, keys?: Array<null | string>) {
|
constructor(guard: any, items: Array<any>, keys?: Array<null | string>) {
|
||||||
logger.assertPrivate(guard, _guard, "Result");
|
assertPrivate(guard, _guard, "Result");
|
||||||
super(...items);
|
super(...items);
|
||||||
|
|
||||||
// Name lookup table
|
// Name lookup table
|
||||||
@ -44,7 +44,7 @@ export class Result extends Array<any> {
|
|||||||
get: (target, prop, receiver) => {
|
get: (target, prop, receiver) => {
|
||||||
if (typeof(prop) === "string") {
|
if (typeof(prop) === "string") {
|
||||||
if (prop.match(/^[0-9]+$/)) {
|
if (prop.match(/^[0-9]+$/)) {
|
||||||
const index = logger.getNumber(prop, "%index");
|
const index = getNumber(prop, "%index");
|
||||||
if (index < 0 || index >= this.length) {
|
if (index < 0 || index >= this.length) {
|
||||||
throw new RangeError("out of result range");
|
throw new RangeError("out of result range");
|
||||||
}
|
}
|
||||||
@ -153,7 +153,7 @@ function getValue(value: BigNumberish): Uint8Array {
|
|||||||
let bytes = toArray(value);
|
let bytes = toArray(value);
|
||||||
|
|
||||||
if (bytes.length > WordSize) {
|
if (bytes.length > WordSize) {
|
||||||
logger.throwError("value out-of-bounds", "BUFFER_OVERRUN", {
|
throwError("value out-of-bounds", "BUFFER_OVERRUN", {
|
||||||
buffer: bytes,
|
buffer: bytes,
|
||||||
length: WordSize,
|
length: WordSize,
|
||||||
offset: bytes.length
|
offset: bytes.length
|
||||||
@ -161,7 +161,7 @@ function getValue(value: BigNumberish): Uint8Array {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (bytes.length !== WordSize) {
|
if (bytes.length !== WordSize) {
|
||||||
bytes = logger.getBytesCopy(concat([ Padding.slice(bytes.length % WordSize), bytes ]));
|
bytes = getBytesCopy(concat([ Padding.slice(bytes.length % WordSize), bytes ]));
|
||||||
}
|
}
|
||||||
|
|
||||||
return bytes;
|
return bytes;
|
||||||
@ -194,7 +194,7 @@ export abstract class Coder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_throwError(message: string, value: any): never {
|
_throwError(message: string, value: any): never {
|
||||||
return logger.throwArgumentError(message, this.localName, value);
|
return throwArgumentError(message, this.localName, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract encode(writer: Writer, value: any): number;
|
abstract encode(writer: Writer, value: any): number;
|
||||||
@ -225,15 +225,15 @@ export class Writer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
appendWriter(writer: Writer): number {
|
appendWriter(writer: Writer): number {
|
||||||
return this.#writeData(logger.getBytesCopy(writer.data));
|
return this.#writeData(getBytesCopy(writer.data));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Arrayish item; pad on the right to *nearest* WordSize
|
// Arrayish item; pad on the right to *nearest* WordSize
|
||||||
writeBytes(value: BytesLike): number {
|
writeBytes(value: BytesLike): number {
|
||||||
let bytes = logger.getBytesCopy(value);
|
let bytes = getBytesCopy(value);
|
||||||
const paddingOffset = bytes.length % WordSize;
|
const paddingOffset = bytes.length % WordSize;
|
||||||
if (paddingOffset) {
|
if (paddingOffset) {
|
||||||
bytes = logger.getBytesCopy(concat([ bytes, Padding.slice(paddingOffset) ]))
|
bytes = getBytesCopy(concat([ bytes, Padding.slice(paddingOffset) ]))
|
||||||
}
|
}
|
||||||
return this.#writeData(bytes);
|
return this.#writeData(bytes);
|
||||||
}
|
}
|
||||||
@ -268,7 +268,7 @@ export class Reader {
|
|||||||
constructor(data: BytesLike, allowLoose?: boolean) {
|
constructor(data: BytesLike, allowLoose?: boolean) {
|
||||||
defineProperties<Reader>(this, { allowLoose: !!allowLoose });
|
defineProperties<Reader>(this, { allowLoose: !!allowLoose });
|
||||||
|
|
||||||
this.#data = logger.getBytesCopy(data);
|
this.#data = getBytesCopy(data);
|
||||||
|
|
||||||
this.#offset = 0;
|
this.#offset = 0;
|
||||||
}
|
}
|
||||||
@ -284,8 +284,8 @@ export class Reader {
|
|||||||
if (this.allowLoose && loose && this.#offset + length <= this.#data.length) {
|
if (this.allowLoose && loose && this.#offset + length <= this.#data.length) {
|
||||||
alignedLength = length;
|
alignedLength = length;
|
||||||
} else {
|
} else {
|
||||||
logger.throwError("data out-of-bounds", "BUFFER_OVERRUN", {
|
throwError("data out-of-bounds", "BUFFER_OVERRUN", {
|
||||||
buffer: logger.getBytesCopy(this.#data),
|
buffer: getBytesCopy(this.#data),
|
||||||
length: this.#data.length,
|
length: this.#data.length,
|
||||||
offset: this.#offset + alignedLength
|
offset: this.#offset + alignedLength
|
||||||
});
|
});
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { defineProperties } from "../../utils/properties.js";
|
import {
|
||||||
import { isError } from "../../utils/errors.js";
|
defineProperties, isError, assertArgumentCount, throwArgumentError, throwError
|
||||||
import { logger } from "../../utils/logger.js";
|
} from "../../utils/index.js";
|
||||||
|
|
||||||
import { Typed } from "../typed.js";
|
import { Typed } from "../typed.js";
|
||||||
|
|
||||||
import { Coder, Result, WordSize, Writer } from "./abstract-coder.js";
|
import { Coder, Result, WordSize, Writer } from "./abstract-coder.js";
|
||||||
import { AnonymousCoder } from "./anonymous.js";
|
import { AnonymousCoder } from "./anonymous.js";
|
||||||
|
|
||||||
@ -21,7 +22,7 @@ export function pack(writer: Writer, coders: ReadonlyArray<Coder>, values: Array
|
|||||||
arrayValues = coders.map((coder) => {
|
arrayValues = coders.map((coder) => {
|
||||||
const name = coder.localName;
|
const name = coder.localName;
|
||||||
if (!name) {
|
if (!name) {
|
||||||
logger.throwError("cannot encode object for signature with missing names", "INVALID_ARGUMENT", {
|
throwError("cannot encode object for signature with missing names", "INVALID_ARGUMENT", {
|
||||||
argument: "values",
|
argument: "values",
|
||||||
info: { coder },
|
info: { coder },
|
||||||
value: values
|
value: values
|
||||||
@ -29,7 +30,7 @@ export function pack(writer: Writer, coders: ReadonlyArray<Coder>, values: Array
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (unique[name]) {
|
if (unique[name]) {
|
||||||
logger.throwError("cannot encode object for signature with duplicate names", "INVALID_ARGUMENT", {
|
throwError("cannot encode object for signature with duplicate names", "INVALID_ARGUMENT", {
|
||||||
argument: "values",
|
argument: "values",
|
||||||
info: { coder },
|
info: { coder },
|
||||||
value: values
|
value: values
|
||||||
@ -42,11 +43,11 @@ export function pack(writer: Writer, coders: ReadonlyArray<Coder>, values: Array
|
|||||||
});
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
logger.throwArgumentError("invalid tuple value", "tuple", values);
|
throwArgumentError("invalid tuple value", "tuple", values);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (coders.length !== arrayValues.length) {
|
if (coders.length !== arrayValues.length) {
|
||||||
logger.throwArgumentError("types/value length mismatch", "tuple", values);
|
throwArgumentError("types/value length mismatch", "tuple", values);
|
||||||
}
|
}
|
||||||
|
|
||||||
let staticWriter = new Writer();
|
let staticWriter = new Writer();
|
||||||
@ -173,7 +174,7 @@ export class ArrayCoder extends Coder {
|
|||||||
writer.writeValue(value.length);
|
writer.writeValue(value.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.assertArgumentCount(value.length, count, "coder array" + (this.localName? (" "+ this.localName): ""));
|
assertArgumentCount(value.length, count, "coder array" + (this.localName? (" "+ this.localName): ""));
|
||||||
|
|
||||||
let coders = [];
|
let coders = [];
|
||||||
for (let i = 0; i < value.length; i++) { coders.push(this.coder); }
|
for (let i = 0; i < value.length; i++) { coders.push(this.coder); }
|
||||||
@ -192,7 +193,7 @@ export class ArrayCoder extends Coder {
|
|||||||
// bytes as a link to the data). This could use a much
|
// bytes as a link to the data). This could use a much
|
||||||
// tighter bound, but we are erroring on the side of safety.
|
// tighter bound, but we are erroring on the side of safety.
|
||||||
if (count * WordSize > reader.dataLength) {
|
if (count * WordSize > reader.dataLength) {
|
||||||
logger.throwError("insufficient data length", "BUFFER_OVERRUN", {
|
throwError("insufficient data length", "BUFFER_OVERRUN", {
|
||||||
buffer: reader.bytes,
|
buffer: reader.bytes,
|
||||||
offset: count * WordSize,
|
offset: count * WordSize,
|
||||||
length: reader.dataLength
|
length: reader.dataLength
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { logger } from "../../utils/logger.js";
|
import { getBytesCopy, hexlify } from "../../utils/index.js";
|
||||||
import { hexlify } from "../../utils/data.js";
|
|
||||||
|
|
||||||
import { Coder } from "./abstract-coder.js";
|
import { Coder } from "./abstract-coder.js";
|
||||||
|
|
||||||
@ -16,7 +15,7 @@ export class DynamicBytesCoder extends Coder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
encode(writer: Writer, value: any): number {
|
encode(writer: Writer, value: any): number {
|
||||||
value = logger.getBytesCopy(value);
|
value = getBytesCopy(value);
|
||||||
let length = writer.writeValue(value.length);
|
let length = writer.writeValue(value.length);
|
||||||
length += writer.writeBytes(value);
|
length += writer.writeBytes(value);
|
||||||
return length;
|
return length;
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
|
|
||||||
import { logger } from "../../utils/logger.js";
|
import { defineProperties, getBytesCopy, hexlify } from "../../utils/index.js";
|
||||||
import { hexlify } from "../../utils/data.js";
|
|
||||||
import { defineProperties } from "../../utils/properties.js";
|
|
||||||
|
|
||||||
import { Typed } from "../typed.js";
|
import { Typed } from "../typed.js";
|
||||||
import { Coder } from "./abstract-coder.js";
|
import { Coder } from "./abstract-coder.js";
|
||||||
@ -25,7 +23,7 @@ export class FixedBytesCoder extends Coder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
encode(writer: Writer, _value: BytesLike | Typed): number {
|
encode(writer: Writer, _value: BytesLike | Typed): number {
|
||||||
let data = logger.getBytesCopy(Typed.dereference(_value, this.type));
|
let data = getBytesCopy(Typed.dereference(_value, this.type));
|
||||||
if (data.length !== this.size) { this._throwError("incorrect data length", _value); }
|
if (data.length !== this.size) { this._throwError("incorrect data length", _value); }
|
||||||
return writer.writeBytes(data);
|
return writer.writeBytes(data);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { fromTwos, mask, toTwos } from "../../utils/maths.js";
|
import {
|
||||||
import { defineProperties } from "../../utils/properties.js";
|
defineProperties, fromTwos, getBigInt, mask, toTwos
|
||||||
|
} from "../../utils/index.js";
|
||||||
|
|
||||||
import { logger } from "../../utils/logger.js";
|
|
||||||
import { Typed } from "../typed.js";
|
import { Typed } from "../typed.js";
|
||||||
import { Coder, WordSize } from "./abstract-coder.js";
|
import { Coder, WordSize } from "./abstract-coder.js";
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ export class NumberCoder extends Coder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
encode(writer: Writer, _value: BigNumberish | Typed): number {
|
encode(writer: Writer, _value: BigNumberish | Typed): number {
|
||||||
let value = logger.getBigInt(Typed.dereference(_value, this.type));
|
let value = getBigInt(Typed.dereference(_value, this.type));
|
||||||
|
|
||||||
// Check bounds are safe for encoding
|
// Check bounds are safe for encoding
|
||||||
let maxUintValue = mask(BN_MAX_UINT256, WordSize * 8);
|
let maxUintValue = mask(BN_MAX_UINT256, WordSize * 8);
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import { logger } from "../utils/logger.js";
|
import {
|
||||||
import { defineProperties } from "../utils/index.js";
|
defineProperties, getBigInt, getNumber,
|
||||||
|
assertPrivate, throwArgumentError, throwError
|
||||||
|
} from "../utils/index.js";
|
||||||
|
|
||||||
|
|
||||||
export interface JsonFragmentType {
|
export interface JsonFragmentType {
|
||||||
@ -76,7 +78,9 @@ const regexNumber = new RegExp("^([0-9]+)");
|
|||||||
const regexIdentifier = new RegExp("^([a-zA-Z$_][a-zA-Z0-9$_]*)");
|
const regexIdentifier = new RegExp("^([a-zA-Z$_][a-zA-Z0-9$_]*)");
|
||||||
const regexType = new RegExp("^(address|bool|bytes([0-9]*)|string|u?int([0-9]*))");
|
const regexType = new RegExp("^(address|bool|bytes([0-9]*)|string|u?int([0-9]*))");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore:
|
||||||
|
*/
|
||||||
export type Token = Readonly<{
|
export type Token = Readonly<{
|
||||||
// Type of token (e.g. TYPE, KEYWORD, NUMBER, etc)
|
// Type of token (e.g. TYPE, KEYWORD, NUMBER, etc)
|
||||||
type: string;
|
type: string;
|
||||||
@ -268,7 +272,7 @@ export function lex(text: string): TokenString {
|
|||||||
if (tokens.length > 0 && tokens[tokens.length - 1].type === "NUMBER") {
|
if (tokens.length > 0 && tokens[tokens.length - 1].type === "NUMBER") {
|
||||||
const value = (tokens.pop() as Token).text;
|
const value = (tokens.pop() as Token).text;
|
||||||
suffix = value + suffix;
|
suffix = value + suffix;
|
||||||
(<Writeable<Token>>(tokens[tokens.length - 1])).value = logger.getNumber(value);
|
(<Writeable<Token>>(tokens[tokens.length - 1])).value = getNumber(value);
|
||||||
}
|
}
|
||||||
if (tokens.length === 0 || tokens[tokens.length - 1].type !== "BRACKET") {
|
if (tokens.length === 0 || tokens[tokens.length - 1].type !== "BRACKET") {
|
||||||
throw new Error("missing opening bracket");
|
throw new Error("missing opening bracket");
|
||||||
@ -381,7 +385,7 @@ function consumeGas(tokens: TokenString): null | bigint {
|
|||||||
if (tokens.peekType("AT")) {
|
if (tokens.peekType("AT")) {
|
||||||
tokens.pop();
|
tokens.pop();
|
||||||
if (tokens.peekType("NUMBER")) {
|
if (tokens.peekType("NUMBER")) {
|
||||||
return logger.getBigInt(tokens.pop().text);
|
return getBigInt(tokens.pop().text);
|
||||||
}
|
}
|
||||||
throw new Error("invalid gas");
|
throw new Error("invalid gas");
|
||||||
}
|
}
|
||||||
@ -399,7 +403,7 @@ 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) {
|
if (!match) {
|
||||||
return logger.throwArgumentError("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"; }
|
||||||
@ -408,14 +412,14 @@ function verifyBasicType(type: string): string {
|
|||||||
// bytesXX
|
// bytesXX
|
||||||
const length = parseInt(match[2]);
|
const length = parseInt(match[2]);
|
||||||
if (length === 0 || length > 32) {
|
if (length === 0 || length > 32) {
|
||||||
logger.throwArgumentError("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) {
|
if (size === 0 || size > 256 || size % 8) {
|
||||||
logger.throwArgumentError("invalid numeric width", "type", type);
|
throwArgumentError("invalid numeric width", "type", type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -470,7 +474,7 @@ export class ParamType {
|
|||||||
|
|
||||||
|
|
||||||
constructor(guard: any, name: string, type: string, baseType: string, indexed: null | boolean, components: null | ReadonlyArray<ParamType>, arrayLength: null | number, arrayChildren: null | ParamType) {
|
constructor(guard: any, name: string, type: string, baseType: string, indexed: null | boolean, components: null | ReadonlyArray<ParamType>, arrayLength: null | number, arrayChildren: null | ParamType) {
|
||||||
logger.assertPrivate(guard, _guard, "ParamType");
|
assertPrivate(guard, _guard, "ParamType");
|
||||||
Object.defineProperty(this, internal, { value: ParamTypeInternal });
|
Object.defineProperty(this, internal, { value: ParamTypeInternal });
|
||||||
|
|
||||||
if (components) { components = Object.freeze(components.slice()); }
|
if (components) { components = Object.freeze(components.slice()); }
|
||||||
@ -500,7 +504,7 @@ export class ParamType {
|
|||||||
// - full: "tuple(uint256 foo, address bar) indexed baz"
|
// - full: "tuple(uint256 foo, address bar) indexed baz"
|
||||||
format(format: FormatType = FormatType.sighash): string {
|
format(format: FormatType = FormatType.sighash): string {
|
||||||
if (!FormatType[format]) {
|
if (!FormatType[format]) {
|
||||||
logger.throwArgumentError("invalid format type", "format", format);
|
throwArgumentError("invalid format type", "format", format);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (format === FormatType.json) {
|
if (format === FormatType.json) {
|
||||||
@ -656,13 +660,13 @@ export class ParamType {
|
|||||||
|
|
||||||
const name = obj.name;
|
const name = obj.name;
|
||||||
if (name && (typeof(name) !== "string" || !name.match(regexIdentifier))) {
|
if (name && (typeof(name) !== "string" || !name.match(regexIdentifier))) {
|
||||||
logger.throwArgumentError("invalid name", "obj.name", name);
|
throwArgumentError("invalid name", "obj.name", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
let indexed = obj.indexed;
|
let indexed = obj.indexed;
|
||||||
if (indexed != null) {
|
if (indexed != null) {
|
||||||
if (!allowIndexed) {
|
if (!allowIndexed) {
|
||||||
logger.throwArgumentError("parameter cannot be indexed", "obj.indexed", obj.indexed);
|
throwArgumentError("parameter cannot be indexed", "obj.indexed", obj.indexed);
|
||||||
}
|
}
|
||||||
indexed = !!indexed;
|
indexed = !!indexed;
|
||||||
}
|
}
|
||||||
@ -756,7 +760,7 @@ export abstract class Fragment {
|
|||||||
readonly inputs!: ReadonlyArray<ParamType>;
|
readonly inputs!: ReadonlyArray<ParamType>;
|
||||||
|
|
||||||
constructor(guard: any, type: FragmentType, inputs: ReadonlyArray<ParamType>) {
|
constructor(guard: any, type: FragmentType, inputs: ReadonlyArray<ParamType>) {
|
||||||
logger.assertPrivate(guard, _guard, "Fragment");
|
assertPrivate(guard, _guard, "Fragment");
|
||||||
inputs = Object.freeze(inputs.slice());
|
inputs = Object.freeze(inputs.slice());
|
||||||
defineProperties<Fragment>(this, { type, inputs });
|
defineProperties<Fragment>(this, { type, inputs });
|
||||||
}
|
}
|
||||||
@ -864,7 +868,7 @@ export class ErrorFragment extends NamedFragment {
|
|||||||
|
|
||||||
format(format: FormatType = FormatType.sighash): string {
|
format(format: FormatType = FormatType.sighash): string {
|
||||||
if (!FormatType[format]) {
|
if (!FormatType[format]) {
|
||||||
logger.throwArgumentError("invalid format type", "format", format);
|
throwArgumentError("invalid format type", "format", format);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (format === FormatType.json) {
|
if (format === FormatType.json) {
|
||||||
@ -905,7 +909,7 @@ export class EventFragment extends NamedFragment {
|
|||||||
|
|
||||||
format(format: FormatType = FormatType.sighash): string {
|
format(format: FormatType = FormatType.sighash): string {
|
||||||
if (!FormatType[format]) {
|
if (!FormatType[format]) {
|
||||||
logger.throwArgumentError("invalid format type", "format", format);
|
throwArgumentError("invalid format type", "format", format);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (format === FormatType.json) {
|
if (format === FormatType.json) {
|
||||||
@ -950,11 +954,11 @@ export class ConstructorFragment extends Fragment {
|
|||||||
|
|
||||||
format(format: FormatType = FormatType.sighash): string {
|
format(format: FormatType = FormatType.sighash): string {
|
||||||
if (!FormatType[format]) {
|
if (!FormatType[format]) {
|
||||||
logger.throwArgumentError("invalid format type", "format", format);
|
throwArgumentError("invalid format type", "format", format);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (format === FormatType.sighash) {
|
if (format === FormatType.sighash) {
|
||||||
logger.throwError("cannot format a constructor for sighash", "UNSUPPORTED_OPERATION", {
|
throwError("cannot format a constructor for sighash", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "format(sighash)"
|
operation: "format(sighash)"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1012,7 +1016,7 @@ export class FunctionFragment extends NamedFragment {
|
|||||||
|
|
||||||
format(format: FormatType = FormatType.sighash): string {
|
format(format: FormatType = FormatType.sighash): string {
|
||||||
if (!FormatType[format]) {
|
if (!FormatType[format]) {
|
||||||
logger.throwArgumentError("invalid format type", "format", format);
|
throwArgumentError("invalid format type", "format", format);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (format === FormatType.json) {
|
if (format === FormatType.json) {
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import { concat, dataSlice, hexlify, zeroPadValue, isHexString } from "../utils/data.js";
|
|
||||||
import { keccak256 } from "../crypto/index.js"
|
import { keccak256 } from "../crypto/index.js"
|
||||||
import { id } from "../hash/index.js"
|
import { id } from "../hash/index.js"
|
||||||
import { logger } from "../utils/logger.js";
|
import {
|
||||||
import { defineProperties } from "../utils/properties.js";
|
concat, dataSlice, getBigInt, getBytes, getBytesCopy, hexlify,
|
||||||
import { toHex } from "../utils/maths.js";
|
zeroPadValue, isHexString, defineProperties, throwArgumentError, toHex,
|
||||||
|
throwError, makeError
|
||||||
|
} from "../utils/index.js";
|
||||||
|
|
||||||
import { AbiCoder, defaultAbiCoder } from "./abi-coder.js";
|
import { AbiCoder, defaultAbiCoder } from "./abi-coder.js";
|
||||||
import { checkResultErrors, Result } from "./coders/abstract-coder.js";
|
import { checkResultErrors, Result } from "./coders/abstract-coder.js";
|
||||||
@ -182,7 +183,7 @@ export class Interface {
|
|||||||
switch (fragment.type) {
|
switch (fragment.type) {
|
||||||
case "constructor":
|
case "constructor":
|
||||||
if (this.deploy) {
|
if (this.deploy) {
|
||||||
logger.warn("duplicate definition - constructor");
|
console.log("duplicate definition - constructor");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//checkNames(fragment, "input", fragment.inputs);
|
//checkNames(fragment, "input", fragment.inputs);
|
||||||
@ -208,11 +209,9 @@ export class Interface {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Two identical entries; ignore it
|
||||||
const signature = fragment.format();
|
const signature = fragment.format();
|
||||||
if (bucket.has(signature)) {
|
if (bucket.has(signature)) { return; }
|
||||||
logger.warn("duplicate definition - " + signature);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bucket.set(signature, fragment);
|
bucket.set(signature, fragment);
|
||||||
});
|
});
|
||||||
@ -228,7 +227,7 @@ export class Interface {
|
|||||||
format(format?: FormatType): string | Array<string> {
|
format(format?: FormatType): string | Array<string> {
|
||||||
if (!format) { format = FormatType.full; }
|
if (!format) { format = FormatType.full; }
|
||||||
if (format === FormatType.sighash) {
|
if (format === FormatType.sighash) {
|
||||||
logger.throwArgumentError("interface does not support formatting sighash", "format", format);
|
throwArgumentError("interface does not support formatting sighash", "format", format);
|
||||||
}
|
}
|
||||||
|
|
||||||
const abi = this.fragments.map((f) => f.format(format));
|
const abi = this.fragments.map((f) => f.format(format));
|
||||||
@ -266,7 +265,7 @@ export class Interface {
|
|||||||
for (const fragment of this.#functions.values()) {
|
for (const fragment of this.#functions.values()) {
|
||||||
if (selector === this.getSelector(fragment)) { return fragment; }
|
if (selector === this.getSelector(fragment)) { return fragment; }
|
||||||
}
|
}
|
||||||
logger.throwArgumentError("no matching function", "selector", key);
|
throwArgumentError("no matching function", "selector", key);
|
||||||
}
|
}
|
||||||
|
|
||||||
// It is a bare name, look up the function (will return null if ambiguous)
|
// It is a bare name, look up the function (will return null if ambiguous)
|
||||||
@ -328,11 +327,11 @@ export class Interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (matching.length === 0) {
|
if (matching.length === 0) {
|
||||||
logger.throwArgumentError("no matching function", "name", key);
|
throwArgumentError("no matching function", "name", key);
|
||||||
|
|
||||||
} else if (matching.length > 1 && forceUnique) {
|
} else 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(", ");
|
||||||
logger.throwArgumentError(`multiple matching functions (i.e. ${ matchStr })`, "name", key);
|
throwArgumentError(`multiple matching functions (i.e. ${ matchStr })`, "name", key);
|
||||||
}
|
}
|
||||||
|
|
||||||
return matching[0];
|
return matching[0];
|
||||||
@ -342,7 +341,7 @@ export class Interface {
|
|||||||
const result = this.#functions.get(FunctionFragment.fromString(key).format());
|
const result = this.#functions.get(FunctionFragment.fromString(key).format());
|
||||||
if (result) { return result; }
|
if (result) { return result; }
|
||||||
|
|
||||||
return logger.throwArgumentError("no matching function", "signature", key);
|
return throwArgumentError("no matching function", "signature", key);
|
||||||
}
|
}
|
||||||
getFunctionName(key: string): string {
|
getFunctionName(key: string): string {
|
||||||
return (this.#getFunction(key, null, false)).name;
|
return (this.#getFunction(key, null, false)).name;
|
||||||
@ -361,7 +360,7 @@ export class Interface {
|
|||||||
for (const fragment of this.#events.values()) {
|
for (const fragment of this.#events.values()) {
|
||||||
if (eventTopic === this.getEventTopic(fragment)) { return fragment; }
|
if (eventTopic === this.getEventTopic(fragment)) { return fragment; }
|
||||||
}
|
}
|
||||||
logger.throwArgumentError("no matching event", "eventTopic", key);
|
throwArgumentError("no matching event", "eventTopic", key);
|
||||||
}
|
}
|
||||||
|
|
||||||
// It is a bare name, look up the function (will return null if ambiguous)
|
// It is a bare name, look up the function (will return null if ambiguous)
|
||||||
@ -396,10 +395,10 @@ export class Interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (matching.length === 0) {
|
if (matching.length === 0) {
|
||||||
logger.throwArgumentError("no matching event", "name", key);
|
throwArgumentError("no matching event", "name", key);
|
||||||
} else if (matching.length > 1 && forceUnique) {
|
} else if (matching.length > 1 && forceUnique) {
|
||||||
// @TODO: refine by Typed
|
// @TODO: refine by Typed
|
||||||
logger.throwArgumentError("multiple matching events", "name", key);
|
throwArgumentError("multiple matching events", "name", key);
|
||||||
}
|
}
|
||||||
|
|
||||||
return matching[0];
|
return matching[0];
|
||||||
@ -409,7 +408,7 @@ export class Interface {
|
|||||||
const result = this.#events.get(EventFragment.fromString(key).format());
|
const result = this.#events.get(EventFragment.fromString(key).format());
|
||||||
if (result) { return result; }
|
if (result) { return result; }
|
||||||
|
|
||||||
return logger.throwArgumentError("no matching event", "signature", key);
|
return throwArgumentError("no matching event", "signature", key);
|
||||||
}
|
}
|
||||||
getEventName(key: string): string {
|
getEventName(key: string): string {
|
||||||
return (this.#getEvent(key, null, false)).name;
|
return (this.#getEvent(key, null, false)).name;
|
||||||
@ -430,7 +429,7 @@ export class Interface {
|
|||||||
for (const fragment of this.#errors.values()) {
|
for (const fragment of this.#errors.values()) {
|
||||||
if (selector === this.getSelector(fragment)) { return fragment; }
|
if (selector === this.getSelector(fragment)) { return fragment; }
|
||||||
}
|
}
|
||||||
logger.throwArgumentError("no matching error", "selector", key);
|
throwArgumentError("no matching error", "selector", key);
|
||||||
}
|
}
|
||||||
|
|
||||||
// It is a bare name, look up the function (will return null if ambiguous)
|
// It is a bare name, look up the function (will return null if ambiguous)
|
||||||
@ -443,10 +442,10 @@ export class Interface {
|
|||||||
if (matching.length === 0) {
|
if (matching.length === 0) {
|
||||||
if (key === "Error") { return ErrorFragment.fromString("error Error(string)"); }
|
if (key === "Error") { return ErrorFragment.fromString("error Error(string)"); }
|
||||||
if (key === "Panic") { return ErrorFragment.fromString("error Panic(uint256)"); }
|
if (key === "Panic") { return ErrorFragment.fromString("error Panic(uint256)"); }
|
||||||
logger.throwArgumentError("no matching error", "name", key);
|
throwArgumentError("no matching error", "name", key);
|
||||||
} else if (matching.length > 1) {
|
} else if (matching.length > 1) {
|
||||||
// @TODO: refine by Typed
|
// @TODO: refine by Typed
|
||||||
logger.throwArgumentError("multiple matching errors", "name", key);
|
throwArgumentError("multiple matching errors", "name", key);
|
||||||
}
|
}
|
||||||
|
|
||||||
return matching[0];
|
return matching[0];
|
||||||
@ -460,7 +459,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 logger.throwArgumentError("no matching error", "signature", key);
|
return throwArgumentError("no matching error", "signature", key);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the 4-byte selector used by Solidity to identify a function
|
// Get the 4-byte selector used by Solidity to identify a function
|
||||||
@ -508,7 +507,7 @@ export class Interface {
|
|||||||
if (typeof(fragment) === "string") { fragment = this.getError(fragment); }
|
if (typeof(fragment) === "string") { fragment = this.getError(fragment); }
|
||||||
|
|
||||||
if (dataSlice(data, 0, 4) !== this.getSelector(fragment)) {
|
if (dataSlice(data, 0, 4) !== this.getSelector(fragment)) {
|
||||||
logger.throwArgumentError(`data signature does not match error ${ fragment.name }.`, "data", data);
|
throwArgumentError(`data signature does not match error ${ fragment.name }.`, "data", data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._decodeParams(fragment.inputs, dataSlice(data, 4));
|
return this._decodeParams(fragment.inputs, dataSlice(data, 4));
|
||||||
@ -528,7 +527,7 @@ export class Interface {
|
|||||||
if (typeof(fragment) === "string") { fragment = this.getFunction(fragment); }
|
if (typeof(fragment) === "string") { fragment = this.getFunction(fragment); }
|
||||||
|
|
||||||
if (dataSlice(data, 0, 4) !== this.getSelector(fragment)) {
|
if (dataSlice(data, 0, 4) !== this.getSelector(fragment)) {
|
||||||
logger.throwArgumentError(`data signature does not match function ${ fragment.name }.`, "data", data);
|
throwArgumentError(`data signature does not match function ${ fragment.name }.`, "data", data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._decodeParams(fragment.inputs, dataSlice(data, 4));
|
return this._decodeParams(fragment.inputs, dataSlice(data, 4));
|
||||||
@ -550,7 +549,7 @@ export class Interface {
|
|||||||
|
|
||||||
let message = "invalid length for result data";
|
let message = "invalid length for result data";
|
||||||
|
|
||||||
const bytes = logger.getBytesCopy(data);
|
const bytes = getBytesCopy(data);
|
||||||
if ((bytes.length % 32) === 0) {
|
if ((bytes.length % 32) === 0) {
|
||||||
try {
|
try {
|
||||||
return this.#abiCoder.decode(fragment.outputs, bytes);
|
return this.#abiCoder.decode(fragment.outputs, bytes);
|
||||||
@ -560,7 +559,7 @@ export class Interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Call returned data with no error, but the data is junk
|
// Call returned data with no error, but the data is junk
|
||||||
return logger.throwError(message, "BAD_DATA", {
|
return throwError(message, "BAD_DATA", {
|
||||||
value: hexlify(bytes),
|
value: hexlify(bytes),
|
||||||
info: { method: fragment.name, signature: fragment.format() }
|
info: { method: fragment.name, signature: fragment.format() }
|
||||||
});
|
});
|
||||||
@ -569,7 +568,7 @@ export class Interface {
|
|||||||
makeError(fragment: FunctionFragment | string, _data: BytesLike, tx?: { data: string }): Error {
|
makeError(fragment: FunctionFragment | string, _data: BytesLike, tx?: { data: string }): Error {
|
||||||
if (typeof(fragment) === "string") { fragment = this.getFunction(fragment); }
|
if (typeof(fragment) === "string") { fragment = this.getFunction(fragment); }
|
||||||
|
|
||||||
const data = logger.getBytes(_data);
|
const data = getBytes(_data);
|
||||||
|
|
||||||
let args: undefined | Result = undefined;
|
let args: undefined | Result = undefined;
|
||||||
if (tx) {
|
if (tx) {
|
||||||
@ -616,7 +615,7 @@ export class Interface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return logger.makeError("call revert exception", "CALL_EXCEPTION", {
|
return makeError("call revert exception", "CALL_EXCEPTION", {
|
||||||
data: hexlify(data), transaction: null,
|
data: hexlify(data), transaction: null,
|
||||||
method: fragment.name, signature: fragment.format(), args,
|
method: fragment.name, signature: fragment.format(), args,
|
||||||
errorArgs, errorName, errorSignature, reason
|
errorArgs, errorName, errorSignature, reason
|
||||||
@ -668,7 +667,7 @@ export class Interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (values.length > eventFragment.inputs.length) {
|
if (values.length > eventFragment.inputs.length) {
|
||||||
logger.throwError("too many arguments for " + eventFragment.format(), "UNEXPECTED_ARGUMENT", {
|
throwError("too many arguments for " + eventFragment.format(), "UNEXPECTED_ARGUMENT", {
|
||||||
count: values.length,
|
count: values.length,
|
||||||
expectedCount: eventFragment.inputs.length
|
expectedCount: eventFragment.inputs.length
|
||||||
})
|
})
|
||||||
@ -705,7 +704,7 @@ export class Interface {
|
|||||||
|
|
||||||
if (!param.indexed) {
|
if (!param.indexed) {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
logger.throwArgumentError("cannot filter non-indexed parameters; must be null", ("contract." + param.name), value);
|
throwArgumentError("cannot filter non-indexed parameters; must be null", ("contract." + param.name), value);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -713,7 +712,7 @@ export class Interface {
|
|||||||
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") {
|
||||||
logger.throwArgumentError("filtering with tuples or arrays not supported", ("contract." + param.name), value);
|
throwArgumentError("filtering with tuples or arrays not supported", ("contract." + param.name), value);
|
||||||
} else if (Array.isArray(value)) {
|
} else if (Array.isArray(value)) {
|
||||||
topics.push(value.map((value) => encodeTopic(param, value)));
|
topics.push(value.map((value) => encodeTopic(param, value)));
|
||||||
} else {
|
} else {
|
||||||
@ -744,7 +743,7 @@ export class Interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (values.length !== eventFragment.inputs.length) {
|
if (values.length !== eventFragment.inputs.length) {
|
||||||
logger.throwArgumentError("event arguments/values mismatch", "values", values);
|
throwArgumentError("event arguments/values mismatch", "values", values);
|
||||||
}
|
}
|
||||||
|
|
||||||
eventFragment.inputs.forEach((param, index) => {
|
eventFragment.inputs.forEach((param, index) => {
|
||||||
@ -781,7 +780,7 @@ export class Interface {
|
|||||||
if (topics != null && !eventFragment.anonymous) {
|
if (topics != null && !eventFragment.anonymous) {
|
||||||
const eventTopic = this.getEventTopic(eventFragment);
|
const eventTopic = this.getEventTopic(eventFragment);
|
||||||
if (!isHexString(topics[0], 32) || topics[0].toLowerCase() !== eventTopic) {
|
if (!isHexString(topics[0], 32) || topics[0].toLowerCase() !== eventTopic) {
|
||||||
logger.throwArgumentError("fragment/topic mismatch", "topics[0]", topics[0]);
|
throwArgumentError("fragment/topic mismatch", "topics[0]", topics[0]);
|
||||||
}
|
}
|
||||||
topics = topics.slice(1);
|
topics = topics.slice(1);
|
||||||
}
|
}
|
||||||
@ -846,8 +845,8 @@ export class Interface {
|
|||||||
// Given a transaction, find the matching function fragment (if any) and
|
// Given a transaction, find the matching function fragment (if any) and
|
||||||
// determine all its properties and call parameters
|
// determine all its properties and call parameters
|
||||||
parseTransaction(tx: { data: string, value?: BigNumberish }): null | TransactionDescription {
|
parseTransaction(tx: { data: string, value?: BigNumberish }): null | TransactionDescription {
|
||||||
const data = logger.getBytes(tx.data, "tx.data");
|
const data = getBytes(tx.data, "tx.data");
|
||||||
const value = logger.getBigInt((tx.value != null) ? tx.value: 0, "tx.value");
|
const value = getBigInt((tx.value != null) ? tx.value: 0, "tx.value");
|
||||||
|
|
||||||
const fragment = this.getFunction(hexlify(data.slice(0, 4)));
|
const fragment = this.getFunction(hexlify(data.slice(0, 4)));
|
||||||
|
|
||||||
@ -887,7 +886,7 @@ export class Interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static from(value: ReadonlyArray<Fragment | string | JsonFragment> | string | Interface) {
|
static from(value: ReadonlyArray<Fragment | string | JsonFragment> | string | Interface): Interface {
|
||||||
// Already an Interface, which is immutable
|
// Already an Interface, which is immutable
|
||||||
if (value instanceof Interface) { return value; }
|
if (value instanceof Interface) { return value; }
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { keccak256 } from "../crypto/keccak.js";
|
import { keccak256 } from "../crypto/keccak.js";
|
||||||
import { logger } from "../utils/logger.js";
|
import { getBytes, throwArgumentError } from "../utils/index.js";
|
||||||
|
|
||||||
|
|
||||||
const BN_0 = BigInt(0);
|
const BN_0 = BigInt(0);
|
||||||
@ -19,7 +19,7 @@ function getChecksumAddress(address: string): string {
|
|||||||
expanded[i] = chars[i].charCodeAt(0);
|
expanded[i] = chars[i].charCodeAt(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const hashed = logger.getBytes(keccak256(expanded));
|
const hashed = getBytes(keccak256(expanded));
|
||||||
|
|
||||||
for (let i = 0; i < 40; i += 2) {
|
for (let i = 0; i < 40; i += 2) {
|
||||||
if ((hashed[i >> 1] >> 4) >= 8) {
|
if ((hashed[i >> 1] >> 4) >= 8) {
|
||||||
@ -84,7 +84,7 @@ function fromBase36(value: string): bigint {
|
|||||||
export function getAddress(address: string): string {
|
export function getAddress(address: string): string {
|
||||||
|
|
||||||
if (typeof(address) !== "string") {
|
if (typeof(address) !== "string") {
|
||||||
logger.throwArgumentError("invalid address", "address", address);
|
throwArgumentError("invalid address", "address", address);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (address.match(/^(0x)?[0-9a-fA-F]{40}$/)) {
|
if (address.match(/^(0x)?[0-9a-fA-F]{40}$/)) {
|
||||||
@ -96,7 +96,7 @@ export function getAddress(address: string): string {
|
|||||||
|
|
||||||
// It is a checksummed address with a bad checksum
|
// It is a checksummed address with a bad checksum
|
||||||
if (address.match(/([A-F].*[a-f])|([a-f].*[A-F])/) && result !== address) {
|
if (address.match(/([A-F].*[a-f])|([a-f].*[A-F])/) && result !== address) {
|
||||||
logger.throwArgumentError("bad address checksum", "address", address);
|
throwArgumentError("bad address checksum", "address", address);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -106,7 +106,7 @@ export function getAddress(address: string): string {
|
|||||||
if (address.match(/^XE[0-9]{2}[0-9A-Za-z]{30,31}$/)) {
|
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)) {
|
if (address.substring(2, 4) !== ibanChecksum(address)) {
|
||||||
logger.throwArgumentError("bad icap checksum", "address", address);
|
throwArgumentError("bad icap checksum", "address", address);
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = fromBase36(address.substring(4)).toString(16);
|
let result = fromBase36(address.substring(4)).toString(16);
|
||||||
@ -114,7 +114,7 @@ export function getAddress(address: string): string {
|
|||||||
return getChecksumAddress("0x" + result);
|
return getChecksumAddress("0x" + result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return logger.throwArgumentError("invalid address", "address", address);
|
return throwArgumentError("invalid address", "address", address);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getIcapAddress(address: string): string {
|
export function getIcapAddress(address: string): string {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { logger } from "../utils/logger.js";
|
import { throwArgumentError, throwError } from "../utils/index.js";
|
||||||
|
|
||||||
import { getAddress } from "./address.js";
|
import { getAddress } from "./address.js";
|
||||||
|
|
||||||
@ -21,9 +21,9 @@ async function checkAddress(target: any, promise: Promise<null | string>): Promi
|
|||||||
const result = await promise;
|
const result = await promise;
|
||||||
if (result == null || result === "0x0000000000000000000000000000000000000000") {
|
if (result == null || result === "0x0000000000000000000000000000000000000000") {
|
||||||
if (typeof(target) === "string") {
|
if (typeof(target) === "string") {
|
||||||
return logger.throwError("unconfigured name", "UNCONFIGURED_NAME", { value: target });
|
return throwError("unconfigured name", "UNCONFIGURED_NAME", { value: target });
|
||||||
}
|
}
|
||||||
return logger.throwArgumentError("invalid AddressLike value; did not resolve to a value address", "target", target);
|
return throwArgumentError("invalid AddressLike value; did not resolve to a value address", "target", target);
|
||||||
}
|
}
|
||||||
return getAddress(result);
|
return getAddress(result);
|
||||||
}
|
}
|
||||||
@ -36,7 +36,7 @@ export function resolveAddress(target: AddressLike, resolver?: null | NameResolv
|
|||||||
if (target.match(/^0x[0-9a-f]{40}$/i)) { return getAddress(target); }
|
if (target.match(/^0x[0-9a-f]{40}$/i)) { return getAddress(target); }
|
||||||
|
|
||||||
if (resolver == null) {
|
if (resolver == null) {
|
||||||
return logger.throwError("ENS resolution requires a provider", "UNSUPPORTED_OPERATION", {
|
return throwError("ENS resolution requires a provider", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "resolveName",
|
operation: "resolveName",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -50,5 +50,5 @@ export function resolveAddress(target: AddressLike, resolver?: null | NameResolv
|
|||||||
return checkAddress(target, target);
|
return checkAddress(target, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
return logger.throwArgumentError("unsupported addressable value", "target", target);
|
return throwArgumentError("unsupported addressable value", "target", target);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import { keccak256 } from "../crypto/keccak.js";
|
import { keccak256 } from "../crypto/keccak.js";
|
||||||
import { concat, dataSlice, encodeRlp, logger } from "../utils/index.js";
|
import {
|
||||||
|
concat, dataSlice, getBigInt, getBytes, encodeRlp, throwArgumentError
|
||||||
|
} from "../utils/index.js";
|
||||||
|
|
||||||
import { getAddress } from "./address.js";
|
import { getAddress } from "./address.js";
|
||||||
|
|
||||||
@ -9,7 +11,7 @@ import type { BigNumberish, BytesLike } from "../utils/index.js";
|
|||||||
// http://ethereum.stackexchange.com/questions/760/how-is-the-address-of-an-ethereum-contract-computed
|
// http://ethereum.stackexchange.com/questions/760/how-is-the-address-of-an-ethereum-contract-computed
|
||||||
export function getCreateAddress(tx: { from: string, nonce: BigNumberish }): string {
|
export function getCreateAddress(tx: { from: string, nonce: BigNumberish }): string {
|
||||||
const from = getAddress(tx.from);
|
const from = getAddress(tx.from);
|
||||||
const nonce = logger.getBigInt(tx.nonce, "tx.nonce");
|
const nonce = getBigInt(tx.nonce, "tx.nonce");
|
||||||
|
|
||||||
let nonceHex = nonce.toString(16);
|
let nonceHex = nonce.toString(16);
|
||||||
if (nonceHex === "0") {
|
if (nonceHex === "0") {
|
||||||
@ -25,15 +27,15 @@ export function getCreateAddress(tx: { from: string, nonce: BigNumberish }): str
|
|||||||
|
|
||||||
export function getCreate2Address(_from: string, _salt: BytesLike, _initCodeHash: BytesLike): string {
|
export function getCreate2Address(_from: string, _salt: BytesLike, _initCodeHash: BytesLike): string {
|
||||||
const from = getAddress(_from);
|
const from = getAddress(_from);
|
||||||
const salt = logger.getBytes(_salt, "salt");
|
const salt = getBytes(_salt, "salt");
|
||||||
const initCodeHash = logger.getBytes(_initCodeHash, "initCodeHash");
|
const initCodeHash = getBytes(_initCodeHash, "initCodeHash");
|
||||||
|
|
||||||
if (salt.length !== 32) {
|
if (salt.length !== 32) {
|
||||||
logger.throwArgumentError("salt must be 32 bytes", "salt", _salt);
|
throwArgumentError("salt must be 32 bytes", "salt", _salt);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (initCodeHash.length !== 32) {
|
if (initCodeHash.length !== 32) {
|
||||||
logger.throwArgumentError("initCodeHash must be 32 bytes", "initCodeHash", _initCodeHash);
|
throwArgumentError("initCodeHash must be 32 bytes", "initCodeHash", _initCodeHash);
|
||||||
}
|
}
|
||||||
|
|
||||||
return getAddress(dataSlice(keccak256(concat([ "0xff", from, salt, initCodeHash ])), 12))
|
return getAddress(dataSlice(keccak256(concat([ "0xff", from, salt, initCodeHash ])), 12))
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import { resolveAddress } from "../address/index.js";
|
|
||||||
import { Interface, Typed } from "../abi/index.js";
|
import { Interface, Typed } from "../abi/index.js";
|
||||||
import {
|
import { resolveAddress } from "../address/index.js";
|
||||||
defineProperties, isCallException, isHexString, resolveProperties, logger
|
|
||||||
} from "../utils/index.js";
|
|
||||||
import { copyRequest, Log, TransactionResponse } from "../providers/index.js";
|
import { copyRequest, Log, TransactionResponse } from "../providers/index.js";
|
||||||
|
import {
|
||||||
|
defineProperties, isCallException, isHexString, resolveProperties,
|
||||||
|
makeError, throwArgumentError, throwError
|
||||||
|
} from "../utils/index.js";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ContractEventPayload,
|
ContractEventPayload,
|
||||||
@ -132,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) {
|
||||||
logger.throwArgumentError("cannot override to", "overrides.to", overrides.to);
|
throwArgumentError("cannot override to", "overrides.to", overrides.to);
|
||||||
} else if (overrides.data) {
|
} else if (overrides.data) {
|
||||||
logger.throwArgumentError("cannot override data", "overrides.data", overrides.data);
|
throwArgumentError("cannot override data", "overrides.data", overrides.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve any from
|
// Resolve any from
|
||||||
@ -223,7 +224,7 @@ class WrappedMethod<A extends Array<any> = Array<any>, R = any, D extends R | Co
|
|||||||
async send(...args: ContractMethodArgs<A>): Promise<ContractTransactionResponse> {
|
async send(...args: ContractMethodArgs<A>): Promise<ContractTransactionResponse> {
|
||||||
const runner = this._contract.runner;
|
const runner = this._contract.runner;
|
||||||
if (!canSend(runner)) {
|
if (!canSend(runner)) {
|
||||||
return logger.throwError("contract runner does not support sending transactions", "UNSUPPORTED_OPERATION", {
|
return throwError("contract runner does not support sending transactions", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "sendTransaction"
|
operation: "sendTransaction"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -235,7 +236,7 @@ class WrappedMethod<A extends Array<any> = Array<any>, R = any, D extends R | Co
|
|||||||
async estimateGas(...args: ContractMethodArgs<A>): Promise<bigint> {
|
async estimateGas(...args: ContractMethodArgs<A>): Promise<bigint> {
|
||||||
const runner = getRunner(this._contract.runner, "estimateGas");
|
const runner = getRunner(this._contract.runner, "estimateGas");
|
||||||
if (!canEstimate(runner)) {
|
if (!canEstimate(runner)) {
|
||||||
return logger.throwError("contract runner does not support gas estimation", "UNSUPPORTED_OPERATION", {
|
return throwError("contract runner does not support gas estimation", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "estimateGas"
|
operation: "estimateGas"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -245,7 +246,7 @@ class WrappedMethod<A extends Array<any> = Array<any>, R = any, D extends R | Co
|
|||||||
async staticCallResult(...args: ContractMethodArgs<A>): Promise<Result> {
|
async staticCallResult(...args: ContractMethodArgs<A>): Promise<Result> {
|
||||||
const runner = getRunner(this._contract.runner, "call");
|
const runner = getRunner(this._contract.runner, "call");
|
||||||
if (!canCall(runner)) {
|
if (!canCall(runner)) {
|
||||||
return logger.throwError("contract runner does not support calling", "UNSUPPORTED_OPERATION", {
|
return throwError("contract runner does not support calling", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "call"
|
operation: "call"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -397,7 +398,7 @@ async function getSub(contract: BaseContract, event: ContractEventName): Promise
|
|||||||
// Make sure our runner can actually subscribe to events
|
// Make sure our runner can actually subscribe to events
|
||||||
const provider = getProvider(contract.runner);
|
const provider = getProvider(contract.runner);
|
||||||
if (!provider) {
|
if (!provider) {
|
||||||
return logger.throwError("contract runner does not support subscribing", "UNSUPPORTED_OPERATION", {
|
return throwError("contract runner does not support subscribing", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "on"
|
operation: "on"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -504,7 +505,7 @@ export class BaseContract implements Addressable, EventEmitterable<ContractEvent
|
|||||||
} else {
|
} else {
|
||||||
const resolver = getRunner(runner, "resolveName");
|
const resolver = getRunner(runner, "resolveName");
|
||||||
if (!canResolve(resolver)) {
|
if (!canResolve(resolver)) {
|
||||||
throw logger.makeError("contract runner does not support name resolution", "UNSUPPORTED_OPERATION", {
|
throw makeError("contract runner does not support name resolution", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "resolveName"
|
operation: "resolveName"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -566,7 +567,7 @@ export class BaseContract implements Addressable, EventEmitterable<ContractEvent
|
|||||||
async getDeployedCode(): Promise<null | string> {
|
async getDeployedCode(): Promise<null | string> {
|
||||||
const provider = getProvider(this.runner);
|
const provider = getProvider(this.runner);
|
||||||
if (!provider) {
|
if (!provider) {
|
||||||
return logger.throwError("runner does not support .provider", "UNSUPPORTED_OPERATION", {
|
return throwError("runner does not support .provider", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "getDeployedCode"
|
operation: "getDeployedCode"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -591,7 +592,7 @@ export class BaseContract implements Addressable, EventEmitterable<ContractEvent
|
|||||||
// Make sure we can subscribe to a provider event
|
// Make sure we can subscribe to a provider event
|
||||||
const provider = getProvider(this.runner);
|
const provider = getProvider(this.runner);
|
||||||
if (provider == null) {
|
if (provider == null) {
|
||||||
return logger.throwError("contract runner does not support .provider", "UNSUPPORTED_OPERATION", {
|
return throwError("contract runner does not support .provider", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "waitForDeployment"
|
operation: "waitForDeployment"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -637,7 +638,7 @@ export class BaseContract implements Addressable, EventEmitterable<ContractEvent
|
|||||||
|
|
||||||
const provider = getProvider(this.runner);
|
const provider = getProvider(this.runner);
|
||||||
if (!provider) {
|
if (!provider) {
|
||||||
return logger.throwError("contract runner does not have a provider", "UNSUPPORTED_OPERATION", {
|
return throwError("contract runner does not have a provider", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "queryFilter"
|
operation: "queryFilter"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
|
|
||||||
import { Interface } from "../abi/index.js";
|
import { Interface } from "../abi/index.js";
|
||||||
import { getCreateAddress } from "../address/index.js";
|
import { getCreateAddress } from "../address/index.js";
|
||||||
import { concat, defineProperties, hexlify, logger } from "../utils/index.js";
|
import {
|
||||||
|
concat, defineProperties, getBytes, hexlify,
|
||||||
|
throwArgumentError, throwError
|
||||||
|
} from "../utils/index.js";
|
||||||
|
|
||||||
import { BaseContract, copyOverrides, resolveArgs } from "./contract.js";
|
import { BaseContract, copyOverrides, resolveArgs } from "./contract.js";
|
||||||
|
|
||||||
@ -27,11 +30,11 @@ export class ContractFactory<A extends Array<any> = Array<any>, I = BaseContract
|
|||||||
|
|
||||||
// Dereference Solidity bytecode objects and allow a missing `0x`-prefix
|
// Dereference Solidity bytecode objects and allow a missing `0x`-prefix
|
||||||
if (bytecode instanceof Uint8Array) {
|
if (bytecode instanceof Uint8Array) {
|
||||||
bytecode = hexlify(logger.getBytes(bytecode));
|
bytecode = hexlify(getBytes(bytecode));
|
||||||
} else {
|
} else {
|
||||||
if (typeof(bytecode) === "object") { bytecode = bytecode.object; }
|
if (typeof(bytecode) === "object") { bytecode = bytecode.object; }
|
||||||
if (bytecode.substring(0, 2) !== "0x") { bytecode = "0x" + bytecode; }
|
if (bytecode.substring(0, 2) !== "0x") { bytecode = "0x" + bytecode; }
|
||||||
bytecode = hexlify(logger.getBytes(bytecode));
|
bytecode = hexlify(getBytes(bytecode));
|
||||||
}
|
}
|
||||||
|
|
||||||
defineProperties<ContractFactory>(this, {
|
defineProperties<ContractFactory>(this, {
|
||||||
@ -62,7 +65,7 @@ export class ContractFactory<A extends Array<any> = Array<any>, I = BaseContract
|
|||||||
const tx = await this.getDeployTransaction(...args);
|
const tx = await this.getDeployTransaction(...args);
|
||||||
|
|
||||||
if (!this.runner || typeof(this.runner.sendTransaction) !== "function") {
|
if (!this.runner || typeof(this.runner.sendTransaction) !== "function") {
|
||||||
return logger.throwError("factory runner does not support sending transactions", "UNSUPPORTED_OPERATION", {
|
return throwError("factory runner does not support sending transactions", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "sendTransaction"
|
operation: "sendTransaction"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -78,7 +81,7 @@ export class ContractFactory<A extends Array<any> = Array<any>, I = BaseContract
|
|||||||
|
|
||||||
static fromSolidity<A extends Array<any> = Array<any>, I = ContractInterface>(output: any, runner?: ContractRunner): ContractFactory<A, I> {
|
static fromSolidity<A extends Array<any> = Array<any>, I = ContractInterface>(output: any, runner?: ContractRunner): ContractFactory<A, I> {
|
||||||
if (output == null) {
|
if (output == null) {
|
||||||
logger.throwArgumentError("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 { logger } from "../utils/logger.js";
|
import { throwArgumentError, throwError } from "../utils/index.js";
|
||||||
|
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
@ -37,13 +37,13 @@ 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 logger.throwArgumentError("invalid hashing algorithm name", "algorithm", algo);
|
return throwArgumentError("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) {
|
if (algo == null) {
|
||||||
return logger.throwArgumentError("invalid hmac algorithm", "algorithm", _algo);
|
return throwArgumentError("invalid hmac algorithm", "algorithm", _algo);
|
||||||
}
|
}
|
||||||
return hmac.create(algo, key);
|
return hmac.create(algo, key);
|
||||||
}
|
}
|
||||||
@ -51,20 +51,20 @@ export function createHmac(_algo: string, key: Uint8Array): CryptoHasher {
|
|||||||
export function pbkdf2Sync(password: Uint8Array, salt: Uint8Array, iterations: number, keylen: number, _algo: "sha256" | "sha512"): Uint8Array {
|
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) {
|
if (algo == null) {
|
||||||
return logger.throwArgumentError("invalid pbkdf2 algorithm", "algorithm", _algo);
|
return throwArgumentError("invalid pbkdf2 algorithm", "algorithm", _algo);
|
||||||
}
|
}
|
||||||
return pbkdf2(algo, password, salt, { c: iterations, dkLen: keylen });
|
return pbkdf2(algo, password, salt, { c: iterations, dkLen: keylen });
|
||||||
}
|
}
|
||||||
|
|
||||||
export function randomBytes(length: number): Uint8Array {
|
export function randomBytes(length: number): Uint8Array {
|
||||||
if (crypto == null) {
|
if (crypto == null) {
|
||||||
return logger.throwError("platform does not support secure random numbers", "UNSUPPORTED_OPERATION", {
|
return throwError("platform does not support secure random numbers", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "randomBytes"
|
operation: "randomBytes"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Number.isInteger(length) || length <= 0 || length > 1024) {
|
if (!Number.isInteger(length) || length <= 0 || length > 1024) {
|
||||||
logger.throwArgumentError("invalid length", "length", length);
|
throwArgumentError("invalid length", "length", length);
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = new Uint8Array(length);
|
const result = new Uint8Array(length);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { createHmac } from "./crypto.js";
|
import { createHmac } from "./crypto.js";
|
||||||
import { hexlify, logger } from "../utils/index.js";
|
import { getBytes, hexlify } from "../utils/index.js";
|
||||||
|
|
||||||
import type { BytesLike } from "../utils/index.js";
|
import type { BytesLike } from "../utils/index.js";
|
||||||
|
|
||||||
@ -13,8 +13,8 @@ const _computeHmac = function(algorithm: "sha256" | "sha512", key: Uint8Array, d
|
|||||||
let __computeHmac = _computeHmac;
|
let __computeHmac = _computeHmac;
|
||||||
|
|
||||||
export function computeHmac(algorithm: "sha256" | "sha512", _key: BytesLike, _data: BytesLike): string {
|
export function computeHmac(algorithm: "sha256" | "sha512", _key: BytesLike, _data: BytesLike): string {
|
||||||
const key = logger.getBytes(_key, "key");
|
const key = getBytes(_key, "key");
|
||||||
const data = logger.getBytes(_data, "data");
|
const data = getBytes(_data, "data");
|
||||||
return hexlify(__computeHmac(algorithm, key, data));
|
return hexlify(__computeHmac(algorithm, key, data));
|
||||||
}
|
}
|
||||||
computeHmac._ = _computeHmac;
|
computeHmac._ = _computeHmac;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { keccak_256 } from "@noble/hashes/sha3";
|
import { keccak_256 } from "@noble/hashes/sha3";
|
||||||
|
|
||||||
import { hexlify, logger } from "../utils/index.js";
|
import { getBytes, hexlify } from "../utils/index.js";
|
||||||
|
|
||||||
import type { BytesLike } from "../utils/index.js";
|
import type { BytesLike } from "../utils/index.js";
|
||||||
|
|
||||||
@ -14,7 +14,7 @@ const _keccak256 = function(data: Uint8Array): Uint8Array {
|
|||||||
let __keccak256: (data: Uint8Array) => BytesLike = _keccak256;
|
let __keccak256: (data: Uint8Array) => BytesLike = _keccak256;
|
||||||
|
|
||||||
export function keccak256(_data: BytesLike): string {
|
export function keccak256(_data: BytesLike): string {
|
||||||
const data = logger.getBytes(_data, "data");
|
const data = getBytes(_data, "data");
|
||||||
return hexlify(__keccak256(data));
|
return hexlify(__keccak256(data));
|
||||||
}
|
}
|
||||||
keccak256._ = _keccak256;
|
keccak256._ = _keccak256;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { pbkdf2Sync } from "./crypto.js";
|
import { pbkdf2Sync } from "./crypto.js";
|
||||||
|
|
||||||
import { hexlify, logger } from "../utils/index.js";
|
import { getBytes, hexlify } from "../utils/index.js";
|
||||||
|
|
||||||
import type { BytesLike } from "../utils/index.js";
|
import type { BytesLike } from "../utils/index.js";
|
||||||
|
|
||||||
@ -14,8 +14,8 @@ const _pbkdf2 = function(password: Uint8Array, salt: Uint8Array, iterations: num
|
|||||||
let __pbkdf2 = _pbkdf2;
|
let __pbkdf2 = _pbkdf2;
|
||||||
|
|
||||||
export function pbkdf2(_password: BytesLike, _salt: BytesLike, iterations: number, keylen: number, algo: "sha256" | "sha512"): string {
|
export function pbkdf2(_password: BytesLike, _salt: BytesLike, iterations: number, keylen: number, algo: "sha256" | "sha512"): string {
|
||||||
const password = logger.getBytes(_password, "password");
|
const password = getBytes(_password, "password");
|
||||||
const salt = logger.getBytes(_salt, "salt");
|
const salt = getBytes(_salt, "salt");
|
||||||
return hexlify(__pbkdf2(password, salt, iterations, keylen, algo));
|
return hexlify(__pbkdf2(password, salt, iterations, keylen, algo));
|
||||||
}
|
}
|
||||||
pbkdf2._ = _pbkdf2;
|
pbkdf2._ = _pbkdf2;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { ripemd160 as noble_ripemd160 } from "@noble/hashes/ripemd160";
|
import { ripemd160 as noble_ripemd160 } from "@noble/hashes/ripemd160";
|
||||||
|
|
||||||
import { hexlify, logger } from "../utils/index.js";
|
import { getBytes, hexlify } from "../utils/index.js";
|
||||||
|
|
||||||
import type { BytesLike } from "../utils/index.js";
|
import type { BytesLike } from "../utils/index.js";
|
||||||
|
|
||||||
@ -14,7 +14,7 @@ const _ripemd160 = function(data: Uint8Array): Uint8Array {
|
|||||||
let __ripemd160: (data: Uint8Array) => BytesLike = _ripemd160;
|
let __ripemd160: (data: Uint8Array) => BytesLike = _ripemd160;
|
||||||
|
|
||||||
export function ripemd160(_data: BytesLike): string {
|
export function ripemd160(_data: BytesLike): string {
|
||||||
const data = logger.getBytes(_data, "data");
|
const data = getBytes(_data, "data");
|
||||||
return hexlify(__ripemd160(data));
|
return hexlify(__ripemd160(data));
|
||||||
}
|
}
|
||||||
ripemd160._ = _ripemd160;
|
ripemd160._ = _ripemd160;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { scrypt as _nobleSync, scryptAsync as _nobleAsync } from "@noble/hashes/scrypt";
|
import { scrypt as _nobleSync, scryptAsync as _nobleAsync } from "@noble/hashes/scrypt";
|
||||||
|
|
||||||
import { hexlify as H, logger } from "../utils/index.js";
|
import { getBytes, hexlify as H } from "../utils/index.js";
|
||||||
|
|
||||||
import type { BytesLike } from "../utils/index.js";
|
import type { BytesLike } from "../utils/index.js";
|
||||||
|
|
||||||
@ -22,8 +22,8 @@ let __scryptSync: (passwd: Uint8Array, salt: Uint8Array, N: number, r: number, p
|
|||||||
|
|
||||||
|
|
||||||
export async function scrypt(_passwd: BytesLike, _salt: BytesLike, N: number, r: number, p: number, dkLen: number, progress?: ProgressCallback): Promise<string> {
|
export async function scrypt(_passwd: BytesLike, _salt: BytesLike, N: number, r: number, p: number, dkLen: number, progress?: ProgressCallback): Promise<string> {
|
||||||
const passwd = logger.getBytes(_passwd, "passwd");
|
const passwd = getBytes(_passwd, "passwd");
|
||||||
const salt = logger.getBytes(_salt, "salt");
|
const salt = getBytes(_salt, "salt");
|
||||||
return H(await __scryptAsync(passwd, salt, N, r, p, dkLen, progress));
|
return H(await __scryptAsync(passwd, salt, N, r, p, dkLen, progress));
|
||||||
}
|
}
|
||||||
scrypt._ = _scryptAsync;
|
scrypt._ = _scryptAsync;
|
||||||
@ -35,8 +35,8 @@ scrypt.register = function(func: (passwd: Uint8Array, salt: Uint8Array, N: numbe
|
|||||||
Object.freeze(scrypt);
|
Object.freeze(scrypt);
|
||||||
|
|
||||||
export function scryptSync(_passwd: BytesLike, _salt: BytesLike, N: number, r: number, p: number, dkLen: number): string {
|
export function scryptSync(_passwd: BytesLike, _salt: BytesLike, N: number, r: number, p: number, dkLen: number): string {
|
||||||
const passwd = logger.getBytes(_passwd, "passwd");
|
const passwd = getBytes(_passwd, "passwd");
|
||||||
const salt = logger.getBytes(_salt, "salt");
|
const salt = getBytes(_salt, "salt");
|
||||||
return H(__scryptSync(passwd, salt, N, r, p, dkLen));
|
return H(__scryptSync(passwd, salt, N, r, p, dkLen));
|
||||||
}
|
}
|
||||||
scryptSync._ = _scryptSync;
|
scryptSync._ = _scryptSync;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { createHash } from "./crypto.js";
|
import { createHash } from "./crypto.js";
|
||||||
|
|
||||||
import { hexlify, logger } from "../utils/index.js";
|
import { getBytes, hexlify } from "../utils/index.js";
|
||||||
|
|
||||||
import type { BytesLike } from "../utils/index.js";
|
import type { BytesLike } from "../utils/index.js";
|
||||||
|
|
||||||
@ -20,7 +20,7 @@ let locked256 = false, locked512 = false;
|
|||||||
|
|
||||||
|
|
||||||
export function sha256(_data: BytesLike): string {
|
export function sha256(_data: BytesLike): string {
|
||||||
const data = logger.getBytes(_data, "data");
|
const data = getBytes(_data, "data");
|
||||||
return hexlify(__sha256(data));
|
return hexlify(__sha256(data));
|
||||||
}
|
}
|
||||||
sha256._ = _sha256;
|
sha256._ = _sha256;
|
||||||
@ -32,7 +32,7 @@ sha256.register = function(func: (data: Uint8Array) => BytesLike): void {
|
|||||||
Object.freeze(sha256);
|
Object.freeze(sha256);
|
||||||
|
|
||||||
export function sha512(_data: BytesLike): string {
|
export function sha512(_data: BytesLike): string {
|
||||||
const data = logger.getBytes(_data, "data");
|
const data = getBytes(_data, "data");
|
||||||
return hexlify(__sha512(data));
|
return hexlify(__sha512(data));
|
||||||
}
|
}
|
||||||
sha512._ = _sha512;
|
sha512._ = _sha512;
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
import { ZeroHash } from "../constants/index.js";
|
import { ZeroHash } from "../constants/index.js";
|
||||||
import {
|
import {
|
||||||
concat, dataLength, getStore, hexlify, isHexString, logger, setStore
|
concat, dataLength, getBigInt, getBytes, getNumber, getStore, hexlify,
|
||||||
|
isHexString, setStore,
|
||||||
|
assertPrivate, throwArgumentError
|
||||||
} from "../utils/index.js";
|
} from "../utils/index.js";
|
||||||
|
|
||||||
import type { BigNumberish, BytesLike, Freezable, Frozen } from "../utils/index.js";
|
import type {
|
||||||
|
BigNumberish, BytesLike, Freezable, Frozen
|
||||||
|
} from "../utils/index.js";
|
||||||
|
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
@ -45,7 +49,7 @@ 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) {
|
if (dataLength(value) !== 32) {
|
||||||
logger.throwArgumentError("invalid r", "value", value);
|
throwArgumentError("invalid r", "value", value);
|
||||||
}
|
}
|
||||||
setStore(this.#props, "r", hexlify(value));
|
setStore(this.#props, "r", hexlify(value));
|
||||||
}
|
}
|
||||||
@ -53,16 +57,16 @@ export class Signature implements Freezable<Signature> {
|
|||||||
get s(): string { return getStore(this.#props, "s"); }
|
get s(): string { return getStore(this.#props, "s"); }
|
||||||
set s(value: BytesLike) {
|
set s(value: BytesLike) {
|
||||||
if (dataLength(value) !== 32) {
|
if (dataLength(value) !== 32) {
|
||||||
logger.throwArgumentError("invalid r", "value", value);
|
throwArgumentError("invalid r", "value", value);
|
||||||
} else if (logger.getBytes(value)[0] & 0x80) {
|
} else if (getBytes(value)[0] & 0x80) {
|
||||||
logger.throwArgumentError("non-canonical s", "value", value);
|
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 = logger.getNumber(value, "value");
|
const v = getNumber(value, "value");
|
||||||
if (v !== 27 && v !== 28) { throw new Error("@TODO"); }
|
if (v !== 27 && v !== 28) { throw new Error("@TODO"); }
|
||||||
setStore(this.#props, "v", v);
|
setStore(this.#props, "v", v);
|
||||||
}
|
}
|
||||||
@ -89,7 +93,7 @@ export class Signature implements Freezable<Signature> {
|
|||||||
|
|
||||||
get yParityAndS(): string {
|
get yParityAndS(): string {
|
||||||
// The EIP-2098 compact representation
|
// The EIP-2098 compact representation
|
||||||
const yParityAndS = logger.getBytes(this.s);
|
const yParityAndS = getBytes(this.s);
|
||||||
if (this.yParity) { yParityAndS[0] |= 0x80; }
|
if (this.yParity) { yParityAndS[0] |= 0x80; }
|
||||||
return hexlify(yParityAndS);
|
return hexlify(yParityAndS);
|
||||||
}
|
}
|
||||||
@ -103,11 +107,11 @@ export class Signature implements Freezable<Signature> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constructor(guard: any, r: string, s: string, v: 27 | 28) {
|
constructor(guard: any, r: string, s: string, v: 27 | 28) {
|
||||||
logger.assertPrivate(guard, _guard, "Signature");
|
assertPrivate(guard, _guard, "Signature");
|
||||||
this.#props = { r, s, v, networkV: null };
|
this.#props = { r, s, v, networkV: null };
|
||||||
}
|
}
|
||||||
|
|
||||||
[Symbol.for('nodejs.util.inspect.custom')]() {
|
[Symbol.for('nodejs.util.inspect.custom')](): string {
|
||||||
return `Signature { r: "${ this.r }", s: "${ this.s }", yParity: ${ this.yParity }, networkV: ${ this.networkV } }`;
|
return `Signature { r: "${ this.r }", s: "${ this.s }", yParity: ${ this.yParity }, networkV: ${ this.networkV } }`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,25 +145,25 @@ export class Signature implements Freezable<Signature> {
|
|||||||
|
|
||||||
// Get the chain ID from an EIP-155 v
|
// Get the chain ID from an EIP-155 v
|
||||||
static getChainId(v: BigNumberish): bigint {
|
static getChainId(v: BigNumberish): bigint {
|
||||||
const bv = logger.getBigInt(v, "v");
|
const bv = getBigInt(v, "v");
|
||||||
|
|
||||||
// The v is not an EIP-155 v, so it is the unspecified chain ID
|
// The v is not an EIP-155 v, so it is the unspecified chain ID
|
||||||
if ((bv == BN_27) || (bv == BN_28)) { return BN_0; }
|
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) { logger.throwArgumentError("invalid EIP-155 v", "v", v); }
|
if (bv < BN_35) { throwArgumentError("invalid EIP-155 v", "v", v); }
|
||||||
|
|
||||||
return (bv - BN_35) / BN_2;
|
return (bv - BN_35) / BN_2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the EIP-155 v transformed for a given chainId
|
// Get the EIP-155 v transformed for a given chainId
|
||||||
static getChainIdV(chainId: BigNumberish, v: 27 | 28): bigint {
|
static getChainIdV(chainId: BigNumberish, v: 27 | 28): bigint {
|
||||||
return (logger.getBigInt(chainId) * BN_2) + BigInt(35 + v - 27);
|
return (getBigInt(chainId) * BN_2) + BigInt(35 + v - 27);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert an EIP-155 v into a normalized v
|
// Convert an EIP-155 v into a normalized v
|
||||||
static getNormalizedV(v: BigNumberish): 27 | 28 {
|
static getNormalizedV(v: BigNumberish): 27 | 28 {
|
||||||
const bv = logger.getBigInt(v);
|
const bv = getBigInt(v);
|
||||||
|
|
||||||
if (bv == BN_0) { return 27; }
|
if (bv == BN_0) { return 27; }
|
||||||
if (bv == BN_1) { return 28; }
|
if (bv == BN_1) { return 28; }
|
||||||
@ -170,11 +174,11 @@ export class Signature implements Freezable<Signature> {
|
|||||||
|
|
||||||
static from(sig: SignatureLike): Signature {
|
static from(sig: SignatureLike): Signature {
|
||||||
const throwError = (message: string) => {
|
const throwError = (message: string) => {
|
||||||
return logger.throwArgumentError(message, "signature", sig);
|
return throwArgumentError(message, "signature", sig);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (typeof(sig) === "string") {
|
if (typeof(sig) === "string") {
|
||||||
const bytes = logger.getBytes(sig, "signature");
|
const bytes = getBytes(sig, "signature");
|
||||||
if (bytes.length === 64) {
|
if (bytes.length === 64) {
|
||||||
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);
|
||||||
@ -210,19 +214,19 @@ export class Signature implements Freezable<Signature> {
|
|||||||
|
|
||||||
if (yParityAndS != null) {
|
if (yParityAndS != null) {
|
||||||
if (!isHexString(yParityAndS, 32)) { throwError("invalid yParityAndS"); }
|
if (!isHexString(yParityAndS, 32)) { throwError("invalid yParityAndS"); }
|
||||||
const bytes = logger.getBytes(yParityAndS);
|
const bytes = getBytes(yParityAndS);
|
||||||
bytes[0] &= 0x7f;
|
bytes[0] &= 0x7f;
|
||||||
return hexlify(bytes);
|
return hexlify(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
return throwError("missing s");
|
return throwError("missing s");
|
||||||
})(sig.s, sig.yParityAndS);
|
})(sig.s, sig.yParityAndS);
|
||||||
if (logger.getBytes(s)[0] & 0x80) { throwError("non-canonical s"); }
|
if (getBytes(s)[0] & 0x80) { throwError("non-canonical s"); }
|
||||||
|
|
||||||
// Get v; by any means necessary (we check consistency below)
|
// 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 } {
|
||||||
if (_v != null) {
|
if (_v != null) {
|
||||||
const v = logger.getBigInt(_v);
|
const v = getBigInt(_v);
|
||||||
return {
|
return {
|
||||||
networkV: ((v >= BN_35) ? v: undefined),
|
networkV: ((v >= BN_35) ? v: undefined),
|
||||||
v: Signature.getNormalizedV(v)
|
v: Signature.getNormalizedV(v)
|
||||||
@ -231,7 +235,7 @@ export class Signature implements Freezable<Signature> {
|
|||||||
|
|
||||||
if (yParityAndS != null) {
|
if (yParityAndS != null) {
|
||||||
if (!isHexString(yParityAndS, 32)) { throwError("invalid yParityAndS"); }
|
if (!isHexString(yParityAndS, 32)) { throwError("invalid yParityAndS"); }
|
||||||
return { v: ((logger.getBytes(yParityAndS)[0] & 0x80) ? 28: 27) };
|
return { v: ((getBytes(yParityAndS)[0] & 0x80) ? 28: 27) };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (yParity != null) {
|
if (yParity != null) {
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
|
|
||||||
import * as secp256k1 from "@noble/secp256k1";
|
import * as secp256k1 from "@noble/secp256k1";
|
||||||
|
|
||||||
import { concat, hexlify, toHex, logger } from "../utils/index.js";
|
import {
|
||||||
|
concat, getBytes, getBytesCopy, hexlify, toHex, throwArgumentError
|
||||||
|
} from "../utils/index.js";
|
||||||
|
|
||||||
import { computeHmac } from "./hmac.js";
|
import { computeHmac } from "./hmac.js";
|
||||||
import { Signature } from "./signature.js";
|
import { Signature } from "./signature.js";
|
||||||
@ -15,7 +17,7 @@ import type { SignatureLike } from "./index.js";
|
|||||||
|
|
||||||
// Make noble-secp256k1 sync
|
// Make noble-secp256k1 sync
|
||||||
secp256k1.utils.hmacSha256Sync = function(key: Uint8Array, ...messages: Array<Uint8Array>): Uint8Array {
|
secp256k1.utils.hmacSha256Sync = function(key: Uint8Array, ...messages: Array<Uint8Array>): Uint8Array {
|
||||||
return logger.getBytes(computeHmac("sha256", key, concat(messages)));
|
return getBytes(computeHmac("sha256", key, concat(messages)));
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SigningKey {
|
export class SigningKey {
|
||||||
@ -40,7 +42,7 @@ export class SigningKey {
|
|||||||
logger.assertArgument(() => (dataLength(digest) === 32), "invalid digest length", "digest", digest);
|
logger.assertArgument(() => (dataLength(digest) === 32), "invalid digest length", "digest", digest);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const [ sigDer, recid ] = secp256k1.signSync(logger.getBytesCopy(digest), logger.getBytesCopy(this.#privateKey), {
|
const [ sigDer, recid ] = secp256k1.signSync(getBytesCopy(digest), getBytesCopy(this.#privateKey), {
|
||||||
recovered: true,
|
recovered: true,
|
||||||
canonical: true
|
canonical: true
|
||||||
});
|
});
|
||||||
@ -56,11 +58,11 @@ export class SigningKey {
|
|||||||
|
|
||||||
computeShardSecret(other: BytesLike): string {
|
computeShardSecret(other: BytesLike): string {
|
||||||
const pubKey = SigningKey.computePublicKey(other);
|
const pubKey = SigningKey.computePublicKey(other);
|
||||||
return hexlify(secp256k1.getSharedSecret(logger.getBytesCopy(this.#privateKey), pubKey));
|
return hexlify(secp256k1.getSharedSecret(getBytesCopy(this.#privateKey), pubKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
static computePublicKey(key: BytesLike, compressed?: boolean): string {
|
static computePublicKey(key: BytesLike, compressed?: boolean): string {
|
||||||
let bytes = logger.getBytes(key, "key");
|
let bytes = getBytes(key, "key");
|
||||||
|
|
||||||
if (bytes.length === 32) {
|
if (bytes.length === 32) {
|
||||||
const pubKey = secp256k1.getPublicKey(bytes, !!compressed);
|
const pubKey = secp256k1.getPublicKey(bytes, !!compressed);
|
||||||
@ -80,12 +82,12 @@ export class SigningKey {
|
|||||||
|
|
||||||
static recoverPublicKey(digest: BytesLike, signature: SignatureLike): string {
|
static recoverPublicKey(digest: BytesLike, signature: SignatureLike): string {
|
||||||
const sig = Signature.from(signature);
|
const sig = Signature.from(signature);
|
||||||
const der = secp256k1.Signature.fromCompact(logger.getBytesCopy(concat([ sig.r, sig.s ]))).toDERRawBytes();
|
const der = secp256k1.Signature.fromCompact(getBytesCopy(concat([ sig.r, sig.s ]))).toDERRawBytes();
|
||||||
|
|
||||||
const pubKey = secp256k1.recoverPublicKey(logger.getBytesCopy(digest), der, sig.yParity);
|
const pubKey = secp256k1.recoverPublicKey(getBytesCopy(digest), der, sig.yParity);
|
||||||
if (pubKey != null) { return hexlify(pubKey); }
|
if (pubKey != null) { return hexlify(pubKey); }
|
||||||
|
|
||||||
return logger.throwArgumentError("invalid signautre for digest", "signature", signature);
|
return throwArgumentError("invalid signautre for digest", "signature", signature);
|
||||||
}
|
}
|
||||||
|
|
||||||
static _addPoints(p0: BytesLike, p1: BytesLike, compressed?: boolean): string {
|
static _addPoints(p0: BytesLike, p1: BytesLike, compressed?: boolean): string {
|
||||||
|
@ -22,7 +22,7 @@ export {
|
|||||||
|
|
||||||
export {
|
export {
|
||||||
ZeroAddress,
|
ZeroAddress,
|
||||||
NegativeOne, Zero, One, Two, WeiPerEther, MaxUint256, MinInt256, MaxInt256,
|
NegativeOne, Zero, One, Two, WeiPerEther, MaxUint256, MinInt256, MaxInt256, N,
|
||||||
ZeroHash,
|
ZeroHash,
|
||||||
EtherSymbol, MessagePrefix
|
EtherSymbol, MessagePrefix
|
||||||
} from "./constants/index.js";
|
} from "./constants/index.js";
|
||||||
@ -47,7 +47,7 @@ export {
|
|||||||
|
|
||||||
export {
|
export {
|
||||||
id,
|
id,
|
||||||
//isValidName, namehash, dnsEncode
|
isValidName, namehash, dnsEncode,
|
||||||
hashMessage,
|
hashMessage,
|
||||||
solidityPacked, solidityPackedKeccak256, solidityPackedSha256,
|
solidityPacked, solidityPackedKeccak256, solidityPackedSha256,
|
||||||
TypedDataEncoder
|
TypedDataEncoder
|
||||||
@ -65,7 +65,7 @@ export {
|
|||||||
isCallException, isError,
|
isCallException, isError,
|
||||||
FetchRequest, FetchResponse,
|
FetchRequest, FetchResponse,
|
||||||
FixedFormat, FixedNumber, formatFixed, parseFixed,
|
FixedFormat, FixedNumber, formatFixed, parseFixed,
|
||||||
assertArgument, Logger, logger,
|
assertArgument,
|
||||||
fromTwos, toTwos, mask, toArray, toBigInt, toHex, toNumber,
|
fromTwos, toTwos, mask, toArray, toBigInt, toHex, toNumber,
|
||||||
formatEther, parseEther, formatUnits, parseUnits,
|
formatEther, parseEther, formatUnits, parseUnits,
|
||||||
_toEscapedUtf8String, toUtf8Bytes, toUtf8CodePoints, toUtf8String,
|
_toEscapedUtf8String, toUtf8Bytes, toUtf8CodePoints, toUtf8String,
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
|
||||||
import { keccak256 } from "../crypto/keccak.js";
|
import { keccak256 } from "../crypto/keccak.js";
|
||||||
import { concat, hexlify, logger, toUtf8Bytes, toUtf8String } from "../utils/index.js";
|
import {
|
||||||
|
concat, hexlify, throwArgumentError, toUtf8Bytes, toUtf8String
|
||||||
|
} from "../utils/index.js";
|
||||||
|
|
||||||
|
|
||||||
//import { ens_normalize } from "./ens-normalize/lib";
|
//import { ens_normalize } from "./ens-normalize/lib";
|
||||||
@ -55,7 +57,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") {
|
if (typeof(name) !== "string") {
|
||||||
logger.throwArgumentError("invalid ENS name; not a string", "name", name);
|
throwArgumentError("invalid ENS name; not a string", "name", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
let result: string | Uint8Array = Zeros;
|
let result: string | Uint8Array = Zeros;
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import {
|
import {
|
||||||
concat, dataLength, hexlify, logger, toArray, toTwos, toUtf8Bytes, zeroPadBytes, zeroPadValue
|
keccak256 as _keccak256, sha256 as _sha256
|
||||||
|
} from "../crypto/index.js";
|
||||||
|
import {
|
||||||
|
concat, dataLength, getBytes, hexlify, toArray, toTwos, toUtf8Bytes, zeroPadBytes, zeroPadValue,
|
||||||
|
throwArgumentError
|
||||||
} from "../utils/index.js";
|
} from "../utils/index.js";
|
||||||
import { keccak256 as _keccak256 } from "../crypto/keccak.js";
|
|
||||||
import { sha256 as _sha256 } from "../crypto/sha2.js";
|
|
||||||
|
|
||||||
|
|
||||||
const regexBytes = new RegExp("^bytes([0-9]+)$");
|
const regexBytes = new RegExp("^bytes([0-9]+)$");
|
||||||
@ -13,16 +15,16 @@ const regexArray = new RegExp("^(.*)\\[([0-9]*)\\]$");
|
|||||||
function _pack(type: string, value: any, isArray?: boolean): Uint8Array {
|
function _pack(type: string, value: any, isArray?: boolean): Uint8Array {
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case "address":
|
case "address":
|
||||||
if (isArray) { return logger.getBytes(zeroPadValue(value, 32)); }
|
if (isArray) { return getBytes(zeroPadValue(value, 32)); }
|
||||||
return logger.getBytes(value);
|
return getBytes(value);
|
||||||
case "string":
|
case "string":
|
||||||
return toUtf8Bytes(value);
|
return toUtf8Bytes(value);
|
||||||
case "bytes":
|
case "bytes":
|
||||||
return logger.getBytes(value);
|
return getBytes(value);
|
||||||
case "bool":
|
case "bool":
|
||||||
value = (!!value ? "0x01": "0x00");
|
value = (!!value ? "0x01": "0x00");
|
||||||
if (isArray) { return logger.getBytes(zeroPadValue(value, 32)); }
|
if (isArray) { return getBytes(zeroPadValue(value, 32)); }
|
||||||
return logger.getBytes(value);
|
return getBytes(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
let match = type.match(regexNumber);
|
let match = type.match(regexNumber);
|
||||||
@ -30,14 +32,14 @@ function _pack(type: string, value: any, isArray?: boolean): Uint8Array {
|
|||||||
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) {
|
if ((match[2] && String(size) !== match[2]) || (size % 8 !== 0) || size === 0 || size > 256) {
|
||||||
return logger.throwArgumentError("invalid number type", "type", type)
|
return throwArgumentError("invalid number type", "type", type)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isArray) { size = 256; }
|
if (isArray) { size = 256; }
|
||||||
|
|
||||||
value = toTwos(value, size);
|
value = toTwos(value, size);
|
||||||
|
|
||||||
return logger.getBytes(zeroPadValue(toArray(value), size / 8));
|
return getBytes(zeroPadValue(toArray(value), size / 8));
|
||||||
}
|
}
|
||||||
|
|
||||||
match = type.match(regexBytes);
|
match = type.match(regexBytes);
|
||||||
@ -45,12 +47,12 @@ function _pack(type: string, value: any, isArray?: boolean): Uint8Array {
|
|||||||
const size = parseInt(match[1]);
|
const size = parseInt(match[1]);
|
||||||
|
|
||||||
if (String(size) !== match[1] || size === 0 || size > 32) {
|
if (String(size) !== match[1] || size === 0 || size > 32) {
|
||||||
return logger.throwArgumentError("invalid bytes type", "type", type)
|
return throwArgumentError("invalid bytes type", "type", type)
|
||||||
}
|
}
|
||||||
if (dataLength(value) !== size) {
|
if (dataLength(value) !== size) {
|
||||||
return logger.throwArgumentError(`invalid value for ${ type }`, "value", value)
|
return throwArgumentError(`invalid value for ${ type }`, "value", value)
|
||||||
}
|
}
|
||||||
if (isArray) { return logger.getBytes(zeroPadBytes(value, 32)); }
|
if (isArray) { return getBytes(zeroPadBytes(value, 32)); }
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,23 +61,23 @@ function _pack(type: string, value: any, isArray?: boolean): Uint8Array {
|
|||||||
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) {
|
if (count != value.length) {
|
||||||
logger.throwArgumentError(`invalid array length for ${ type }`, "value", value)
|
throwArgumentError(`invalid array length for ${ type }`, "value", value)
|
||||||
}
|
}
|
||||||
const result: Array<Uint8Array> = [];
|
const result: Array<Uint8Array> = [];
|
||||||
value.forEach(function(value) {
|
value.forEach(function(value) {
|
||||||
result.push(_pack(baseType, value, true));
|
result.push(_pack(baseType, value, true));
|
||||||
});
|
});
|
||||||
return logger.getBytes(concat(result));
|
return getBytes(concat(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
return logger.throwArgumentError("invalid type", "type", type)
|
return throwArgumentError("invalid type", "type", type)
|
||||||
}
|
}
|
||||||
|
|
||||||
// @TODO: Array Enum
|
// @TODO: Array Enum
|
||||||
|
|
||||||
export function solidityPacked(types: ReadonlyArray<string>, values: ReadonlyArray<any>) {
|
export function solidityPacked(types: ReadonlyArray<string>, values: ReadonlyArray<any>): string {
|
||||||
if (types.length != values.length) {
|
if (types.length != values.length) {
|
||||||
logger.throwArgumentError("wrong number of values; expected ${ types.length }", "values", values)
|
throwArgumentError("wrong number of values; expected ${ types.length }", "values", values)
|
||||||
}
|
}
|
||||||
const tight: Array<Uint8Array> = [];
|
const tight: Array<Uint8Array> = [];
|
||||||
types.forEach(function(type, index) {
|
types.forEach(function(type, index) {
|
||||||
@ -98,7 +100,7 @@ export function solidityPacked(types: ReadonlyArray<string>, values: ReadonlyArr
|
|||||||
*
|
*
|
||||||
* @see https://docs.soliditylang.org/en/v0.8.14/abi-spec.html#non-standard-packed-mode
|
* @see https://docs.soliditylang.org/en/v0.8.14/abi-spec.html#non-standard-packed-mode
|
||||||
*/
|
*/
|
||||||
export function solidityPackedKeccak256(types: ReadonlyArray<string>, values: ReadonlyArray<any>) {
|
export function solidityPackedKeccak256(types: ReadonlyArray<string>, values: ReadonlyArray<any>): string {
|
||||||
return _keccak256(solidityPacked(types, values));
|
return _keccak256(solidityPacked(types, values));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,6 +112,6 @@ export function solidityPackedKeccak256(types: ReadonlyArray<string>, values: Re
|
|||||||
export function test(foo: number | string): void {
|
export function test(foo: number | string): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function solidityPackedSha256(types: ReadonlyArray<string>, values: ReadonlyArray<any>) {
|
export function solidityPackedSha256(types: ReadonlyArray<string>, values: ReadonlyArray<any>): string {
|
||||||
return _sha256(solidityPacked(types, values));
|
return _sha256(solidityPacked(types, values));
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,11 @@
|
|||||||
import { getAddress } from "../address/index.js";
|
import { getAddress } from "../address/index.js";
|
||||||
import { keccak256 } from "../crypto/index.js";
|
import { keccak256 } from "../crypto/index.js";
|
||||||
import {
|
import {
|
||||||
concat, defineProperties, hexlify, isHexString, mask, toHex, toTwos, zeroPadValue
|
concat, defineProperties, getBigInt, getBytes, hexlify, isHexString, mask, toHex, toTwos, zeroPadValue,
|
||||||
|
throwArgumentError
|
||||||
} from "../utils/index.js";
|
} from "../utils/index.js";
|
||||||
|
|
||||||
import { id } from "./id.js";
|
import { id } from "./id.js";
|
||||||
import { logger } from "../utils/logger.js";
|
|
||||||
|
|
||||||
import type { BigNumberish, BytesLike } from "../utils/index.js";
|
import type { BigNumberish, BytesLike } from "../utils/index.js";
|
||||||
|
|
||||||
@ -32,8 +32,8 @@ export interface TypedDataField {
|
|||||||
type: string;
|
type: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
function hexPadRight(value: BytesLike) {
|
function hexPadRight(value: BytesLike): string {
|
||||||
const bytes = logger.getBytes(value);
|
const bytes = getBytes(value);
|
||||||
const padOffset = bytes.length % 32
|
const padOffset = bytes.length % 32
|
||||||
if (padOffset) {
|
if (padOffset) {
|
||||||
return concat([ bytes, padding.slice(padOffset) ]);
|
return concat([ bytes, padding.slice(padOffset) ]);
|
||||||
@ -59,7 +59,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") {
|
if (typeof(value) !== "string") {
|
||||||
logger.throwArgumentError(`invalid domain value for ${ JSON.stringify(key) }`, `domain.${ key }`, value);
|
throwArgumentError(`invalid domain value for ${ JSON.stringify(key) }`, `domain.${ key }`, value);
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
@ -69,18 +69,18 @@ const domainChecks: Record<string, (value: any) => any> = {
|
|||||||
name: checkString("name"),
|
name: checkString("name"),
|
||||||
version: checkString("version"),
|
version: checkString("version"),
|
||||||
chainId: function(value: any) {
|
chainId: function(value: any) {
|
||||||
return logger.getBigInt(value, "domain.chainId");
|
return getBigInt(value, "domain.chainId");
|
||||||
},
|
},
|
||||||
verifyingContract: function(value: any) {
|
verifyingContract: function(value: any) {
|
||||||
try {
|
try {
|
||||||
return getAddress(value).toLowerCase();
|
return getAddress(value).toLowerCase();
|
||||||
} catch (error) { }
|
} catch (error) { }
|
||||||
return logger.throwArgumentError(`invalid domain value "verifyingContract"`, "domain.verifyingContract", value);
|
return throwArgumentError(`invalid domain value "verifyingContract"`, "domain.verifyingContract", value);
|
||||||
},
|
},
|
||||||
salt: function(value: any) {
|
salt: function(value: any) {
|
||||||
const bytes = logger.getBytes(value, "domain.salt");
|
const bytes = getBytes(value, "domain.salt");
|
||||||
if (bytes.length !== 32) {
|
if (bytes.length !== 32) {
|
||||||
logger.throwArgumentError(`invalid domain value "salt"`, "domain.salt", value);
|
throwArgumentError(`invalid domain value "salt"`, "domain.salt", value);
|
||||||
}
|
}
|
||||||
return hexlify(bytes);
|
return hexlify(bytes);
|
||||||
}
|
}
|
||||||
@ -95,17 +95,17 @@ function getBaseEncoder(type: string): null | ((value: any) => string) {
|
|||||||
|
|
||||||
const width = parseInt(match[2] || "256");
|
const width = parseInt(match[2] || "256");
|
||||||
if (width % 8 !== 0 || width > 256 || (match[2] && match[2] !== String(width))) {
|
if (width % 8 !== 0 || width > 256 || (match[2] && match[2] !== String(width))) {
|
||||||
logger.throwArgumentError("invalid numeric width", "type", type);
|
throwArgumentError("invalid numeric width", "type", type);
|
||||||
}
|
}
|
||||||
|
|
||||||
const boundsUpper = mask(BN_MAX_UINT256, signed ? (width - 1): width);
|
const 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;
|
||||||
|
|
||||||
return function(_value: BigNumberish) {
|
return function(_value: BigNumberish) {
|
||||||
const value = logger.getBigInt(_value, "value");
|
const value = getBigInt(_value, "value");
|
||||||
|
|
||||||
if (value < boundsLower || value > boundsUpper) {
|
if (value < boundsLower || value > boundsUpper) {
|
||||||
logger.throwArgumentError(`value out-of-bounds for ${ type }`, "value", value);
|
throwArgumentError(`value out-of-bounds for ${ type }`, "value", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return toHex(toTwos(value, 256), 32);
|
return toHex(toTwos(value, 256), 32);
|
||||||
@ -119,13 +119,13 @@ function getBaseEncoder(type: string): null | ((value: any) => string) {
|
|||||||
if (match) {
|
if (match) {
|
||||||
const width = parseInt(match[1]);
|
const width = parseInt(match[1]);
|
||||||
if (width === 0 || width > 32 || match[1] !== String(width)) {
|
if (width === 0 || width > 32 || match[1] !== String(width)) {
|
||||||
logger.throwArgumentError("invalid bytes width", "type", type);
|
throwArgumentError("invalid bytes width", "type", type);
|
||||||
}
|
}
|
||||||
|
|
||||||
return function(value: BytesLike) {
|
return function(value: BytesLike) {
|
||||||
const bytes = logger.getBytes(value);
|
const bytes = getBytes(value);
|
||||||
if (bytes.length !== width) {
|
if (bytes.length !== width) {
|
||||||
logger.throwArgumentError(`invalid length for ${ type }`, "value", value);
|
throwArgumentError(`invalid length for ${ type }`, "value", value);
|
||||||
}
|
}
|
||||||
return hexPadRight(value);
|
return hexPadRight(value);
|
||||||
};
|
};
|
||||||
@ -193,14 +193,14 @@ export class TypedDataEncoder {
|
|||||||
|
|
||||||
// Check each field has a unique name
|
// Check each field has a unique name
|
||||||
if (uniqueNames.has(field.name)) {
|
if (uniqueNames.has(field.name)) {
|
||||||
logger.throwArgumentError(`duplicate variable name ${ JSON.stringify(field.name) } in ${ JSON.stringify(name) }`, "types", types);
|
throwArgumentError(`duplicate variable name ${ JSON.stringify(field.name) } in ${ JSON.stringify(name) }`, "types", types);
|
||||||
}
|
}
|
||||||
uniqueNames.add(field.name);
|
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) {
|
if (baseType === name) {
|
||||||
logger.throwArgumentError(`circular type reference to ${ JSON.stringify(baseType) }`, "types", types);
|
throwArgumentError(`circular type reference to ${ JSON.stringify(baseType) }`, "types", types);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is this a base encoding type?
|
// Is this a base encoding type?
|
||||||
@ -208,7 +208,7 @@ export class TypedDataEncoder {
|
|||||||
if (encoder) { continue; }
|
if (encoder) { continue; }
|
||||||
|
|
||||||
if (!parents.has(baseType)) {
|
if (!parents.has(baseType)) {
|
||||||
logger.throwArgumentError(`unknown type ${ JSON.stringify(baseType) }`, "types", types);
|
throwArgumentError(`unknown type ${ JSON.stringify(baseType) }`, "types", types);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add linkage
|
// Add linkage
|
||||||
@ -221,9 +221,9 @@ export class TypedDataEncoder {
|
|||||||
const primaryTypes = Array.from(parents.keys()).filter((n) => ((parents.get(n) as Array<string>).length === 0));
|
const primaryTypes = Array.from(parents.keys()).filter((n) => ((parents.get(n) as Array<string>).length === 0));
|
||||||
|
|
||||||
if (primaryTypes.length === 0) {
|
if (primaryTypes.length === 0) {
|
||||||
logger.throwArgumentError("missing primary type", "types", types);
|
throwArgumentError("missing primary type", "types", types);
|
||||||
} else if (primaryTypes.length > 1) {
|
} else if (primaryTypes.length > 1) {
|
||||||
logger.throwArgumentError(`ambiguous primary types or unused types: ${ primaryTypes.map((t) => (JSON.stringify(t))).join(", ") }`, "types", types);
|
throwArgumentError(`ambiguous primary types or unused types: ${ primaryTypes.map((t) => (JSON.stringify(t))).join(", ") }`, "types", types);
|
||||||
}
|
}
|
||||||
|
|
||||||
defineProperties<TypedDataEncoder>(this, { primaryType: primaryTypes[0] });
|
defineProperties<TypedDataEncoder>(this, { primaryType: primaryTypes[0] });
|
||||||
@ -231,7 +231,7 @@ export class TypedDataEncoder {
|
|||||||
// 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)) {
|
if (found.has(type)) {
|
||||||
logger.throwArgumentError(`circular type reference to ${ JSON.stringify(type) }`, "types", types);
|
throwArgumentError(`circular type reference to ${ JSON.stringify(type) }`, "types", types);
|
||||||
}
|
}
|
||||||
|
|
||||||
found.add(type);
|
found.add(type);
|
||||||
@ -285,7 +285,7 @@ export class TypedDataEncoder {
|
|||||||
const length = parseInt(match[3]);
|
const length = parseInt(match[3]);
|
||||||
return (value: Array<any>) => {
|
return (value: Array<any>) => {
|
||||||
if (length >= 0 && value.length !== length) {
|
if (length >= 0 && value.length !== length) {
|
||||||
logger.throwArgumentError("array length mismatch; expected length ${ arrayLength }", "value", value);
|
throwArgumentError("array length mismatch; expected length ${ arrayLength }", "value", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = value.map(subEncoder);
|
let result = value.map(subEncoder);
|
||||||
@ -312,13 +312,13 @@ export class TypedDataEncoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return logger.throwArgumentError(`unknown type: ${ type }`, "type", type);
|
return throwArgumentError(`unknown type: ${ type }`, "type", type);
|
||||||
}
|
}
|
||||||
|
|
||||||
encodeType(name: string): string {
|
encodeType(name: string): string {
|
||||||
const result = this.#fullTypes.get(name);
|
const result = this.#fullTypes.get(name);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return logger.throwArgumentError(`unknown type: ${ JSON.stringify(name) }`, "name", name);
|
return throwArgumentError(`unknown type: ${ JSON.stringify(name) }`, "name", name);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -352,7 +352,7 @@ export class TypedDataEncoder {
|
|||||||
const subtype = match[1];
|
const subtype = match[1];
|
||||||
const length = parseInt(match[3]);
|
const length = parseInt(match[3]);
|
||||||
if (length >= 0 && value.length !== length) {
|
if (length >= 0 && value.length !== length) {
|
||||||
logger.throwArgumentError("array length mismatch; expected length ${ arrayLength }", "value", value);
|
throwArgumentError("array length mismatch; expected length ${ arrayLength }", "value", value);
|
||||||
}
|
}
|
||||||
return value.map((v: any) => this._visit(subtype, v, callback));
|
return value.map((v: any) => this._visit(subtype, v, callback));
|
||||||
}
|
}
|
||||||
@ -366,7 +366,7 @@ export class TypedDataEncoder {
|
|||||||
}, <Record<string, any>>{});
|
}, <Record<string, any>>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
return logger.throwArgumentError(`unknown type: ${ type }`, "type", type);
|
return throwArgumentError(`unknown type: ${ type }`, "type", type);
|
||||||
}
|
}
|
||||||
|
|
||||||
visit(value: Record<string, any>, callback: (type: string, data: any) => any): any {
|
visit(value: Record<string, any>, callback: (type: string, data: any) => any): any {
|
||||||
@ -390,7 +390,7 @@ export class TypedDataEncoder {
|
|||||||
for (const name in domain) {
|
for (const name in domain) {
|
||||||
const type = domainFieldTypes[name];
|
const type = domainFieldTypes[name];
|
||||||
if (!type) {
|
if (!type) {
|
||||||
logger.throwArgumentError(`invalid typed-data domain key: ${ JSON.stringify(name) }`, "domain", domain);
|
throwArgumentError(`invalid typed-data domain key: ${ JSON.stringify(name) }`, "domain", domain);
|
||||||
}
|
}
|
||||||
domainFields.push({ name, type });
|
domainFields.push({ name, type });
|
||||||
}
|
}
|
||||||
@ -476,7 +476,7 @@ export class TypedDataEncoder {
|
|||||||
|
|
||||||
const typesWithDomain = Object.assign({ }, types);
|
const typesWithDomain = Object.assign({ }, types);
|
||||||
if (typesWithDomain.EIP712Domain) {
|
if (typesWithDomain.EIP712Domain) {
|
||||||
logger.throwArgumentError("types must not contain EIP712Domain type", "types.EIP712Domain", types);
|
throwArgumentError("types must not contain EIP712Domain type", "types.EIP712Domain", types);
|
||||||
} else {
|
} else {
|
||||||
typesWithDomain.EIP712Domain = domainTypes;
|
typesWithDomain.EIP712Domain = domainTypes;
|
||||||
}
|
}
|
||||||
@ -492,12 +492,12 @@ export class TypedDataEncoder {
|
|||||||
|
|
||||||
// bytes
|
// bytes
|
||||||
if (type.match(/^bytes(\d*)/)) {
|
if (type.match(/^bytes(\d*)/)) {
|
||||||
return hexlify(logger.getBytes(value));
|
return hexlify(getBytes(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
// uint or int
|
// uint or int
|
||||||
if (type.match(/^u?int/)) {
|
if (type.match(/^u?int/)) {
|
||||||
return logger.getBigInt(value).toString();
|
return getBigInt(value).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@ -507,12 +507,12 @@ export class TypedDataEncoder {
|
|||||||
return !!value;
|
return !!value;
|
||||||
case "string":
|
case "string":
|
||||||
if (typeof(value) !== "string") {
|
if (typeof(value) !== "string") {
|
||||||
logger.throwArgumentError(`invalid string`, "value", value);
|
throwArgumentError(`invalid string`, "value", value);
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return logger.throwArgumentError("unsupported type", "type", type);
|
return throwArgumentError("unsupported type", "type", type);
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -7,14 +7,15 @@
|
|||||||
// of Signer/ENS name to address so we can sync respond to listenerCount.
|
// of Signer/ENS name to address so we can sync respond to listenerCount.
|
||||||
|
|
||||||
import { resolveAddress } from "../address/index.js";
|
import { resolveAddress } from "../address/index.js";
|
||||||
import { concat, dataLength, dataSlice, hexlify, isHexString } from "../utils/data.js";
|
import {
|
||||||
import { isCallException } from "../utils/errors.js";
|
concat, dataLength, dataSlice, hexlify, isHexString,
|
||||||
import { FetchRequest } from "../utils/fetch.js";
|
getBigInt, getBytes, getNumber,
|
||||||
import { toArray, toQuantity } from "../utils/maths.js";
|
isCallException, makeError, throwError, throwArgumentError,
|
||||||
import { defineProperties, EventPayload, resolveProperties } from "../utils/index.js";
|
FetchRequest,
|
||||||
import { toUtf8String } from "../utils/index.js";;
|
toArray, toQuantity,
|
||||||
|
defineProperties, EventPayload, resolveProperties,
|
||||||
import { logger } from "../utils/logger.js";
|
toUtf8String
|
||||||
|
} from "../utils/index.js";
|
||||||
|
|
||||||
import { EnsResolver } from "./ens-resolver.js";
|
import { EnsResolver } from "./ens-resolver.js";
|
||||||
import { Network } from "./network.js";
|
import { Network } from "./network.js";
|
||||||
@ -193,7 +194,7 @@ async function getSubscription(_event: ProviderEvent, provider: AbstractProvider
|
|||||||
return { filter, tag: getTag("event", filter), type: "event" };
|
return { filter, tag: getTag("event", filter), type: "event" };
|
||||||
}
|
}
|
||||||
|
|
||||||
return logger.throwArgumentError("unknown ProviderEvent", "event", _event);
|
return throwArgumentError("unknown ProviderEvent", "event", _event);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTime(): number { return (new Date()).getTime(); }
|
function getTime(): number { return (new Date()).getTime(); }
|
||||||
@ -428,7 +429,7 @@ export class AbstractProvider implements Provider {
|
|||||||
|
|
||||||
// 4xx indicates the result is not present; stop
|
// 4xx indicates the result is not present; stop
|
||||||
if (resp.statusCode >= 400 && resp.statusCode < 500) {
|
if (resp.statusCode >= 400 && resp.statusCode < 500) {
|
||||||
return logger.throwError(`response not found during CCIP fetch: ${ errorMessage }`, "OFFCHAIN_FAULT", {
|
return throwError(`response not found during CCIP fetch: ${ errorMessage }`, "OFFCHAIN_FAULT", {
|
||||||
reason: "404_MISSING_RESOURCE",
|
reason: "404_MISSING_RESOURCE",
|
||||||
transaction: tx, info: { url, errorMessage }
|
transaction: tx, info: { url, errorMessage }
|
||||||
});
|
});
|
||||||
@ -438,7 +439,7 @@ export class AbstractProvider implements Provider {
|
|||||||
errorMessages.push(errorMessage);
|
errorMessages.push(errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
return logger.throwError(`error encountered during CCIP fetch: ${ errorMessages.map((m) => JSON.stringify(m)).join(", ") }`, "OFFCHAIN_FAULT", {
|
return throwError(`error encountered during CCIP fetch: ${ errorMessages.map((m) => JSON.stringify(m)).join(", ") }`, "OFFCHAIN_FAULT", {
|
||||||
reason: "500_SERVER_ERROR",
|
reason: "500_SERVER_ERROR",
|
||||||
transaction: tx, info: { urls, errorMessages }
|
transaction: tx, info: { urls, errorMessages }
|
||||||
});
|
});
|
||||||
@ -449,7 +450,7 @@ export class AbstractProvider implements Provider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_detectNetwork(): Promise<Frozen<Network>> {
|
_detectNetwork(): Promise<Frozen<Network>> {
|
||||||
return logger.throwError("sub-classes must implement this", "UNSUPPORTED_OPERATION", {
|
return throwError("sub-classes must implement this", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "_detectNetwork"
|
operation: "_detectNetwork"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -457,7 +458,7 @@ export class AbstractProvider implements Provider {
|
|||||||
// Sub-classes should override this and handle PerformActionRequest requests, calling
|
// Sub-classes should override this and handle PerformActionRequest requests, calling
|
||||||
// the super for any unhandled actions.
|
// the super for any unhandled actions.
|
||||||
async _perform<T = any>(req: PerformActionRequest): Promise<T> {
|
async _perform<T = any>(req: PerformActionRequest): Promise<T> {
|
||||||
return logger.throwError(`unsupported method: ${ req.method }`, "UNSUPPORTED_OPERATION", {
|
return throwError(`unsupported method: ${ req.method }`, "UNSUPPORTED_OPERATION", {
|
||||||
operation: req.method,
|
operation: req.method,
|
||||||
info: req
|
info: req
|
||||||
});
|
});
|
||||||
@ -465,7 +466,7 @@ export class AbstractProvider implements Provider {
|
|||||||
|
|
||||||
// State
|
// State
|
||||||
async getBlockNumber(): Promise<number> {
|
async getBlockNumber(): Promise<number> {
|
||||||
return logger.getNumber(await this.#perform({ method: "getBlockNumber" }), "%response");
|
return getNumber(await this.#perform({ method: "getBlockNumber" }), "%response");
|
||||||
}
|
}
|
||||||
|
|
||||||
// @TODO: Make this string | Promsie<string> so no await needed if sync is possible
|
// @TODO: Make this string | Promsie<string> so no await needed if sync is possible
|
||||||
@ -502,7 +503,7 @@ export class AbstractProvider implements Provider {
|
|||||||
return this.getBlockNumber().then((b) => toQuantity(b + blockTag));
|
return this.getBlockNumber().then((b) => toQuantity(b + blockTag));
|
||||||
}
|
}
|
||||||
|
|
||||||
return logger.throwArgumentError("invalid blockTag", "blockTag", blockTag);
|
return throwArgumentError("invalid blockTag", "blockTag", blockTag);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getNetwork(): Promise<Frozen<Network>> {
|
async getNetwork(): Promise<Frozen<Network>> {
|
||||||
@ -544,7 +545,7 @@ export class AbstractProvider implements Provider {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, we do not allow changes to the underlying network
|
// Otherwise, we do not allow changes to the underlying network
|
||||||
logger.throwError(`network changed: ${ expected.chainId } => ${ actual.chainId } `, "NETWORK_ERROR", {
|
throwError(`network changed: ${ expected.chainId } => ${ actual.chainId } `, "NETWORK_ERROR", {
|
||||||
event: "changed"
|
event: "changed"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -559,7 +560,7 @@ export class AbstractProvider implements Provider {
|
|||||||
gasPrice: ((async () => {
|
gasPrice: ((async () => {
|
||||||
try {
|
try {
|
||||||
const gasPrice = await this.#perform({ method: "getGasPrice" });
|
const gasPrice = await this.#perform({ method: "getGasPrice" });
|
||||||
return logger.getBigInt(gasPrice, "%response");
|
return getBigInt(gasPrice, "%response");
|
||||||
} catch (error) { }
|
} catch (error) { }
|
||||||
return null
|
return null
|
||||||
})())
|
})())
|
||||||
@ -598,14 +599,14 @@ export class AbstractProvider implements Provider {
|
|||||||
|
|
||||||
async estimateGas(_tx: TransactionRequest) {
|
async estimateGas(_tx: TransactionRequest) {
|
||||||
const transaction = await this._getTransaction(_tx);
|
const transaction = await this._getTransaction(_tx);
|
||||||
return logger.getBigInt(await this.#perform({
|
return getBigInt(await this.#perform({
|
||||||
method: "estimateGas", transaction
|
method: "estimateGas", transaction
|
||||||
}), "%response");
|
}), "%response");
|
||||||
}
|
}
|
||||||
|
|
||||||
async #call(tx: PerformActionTransaction, blockTag: string, attempt: number): Promise<string> {
|
async #call(tx: PerformActionTransaction, blockTag: string, attempt: number): Promise<string> {
|
||||||
if (attempt >= MAX_CCIP_REDIRECTS) {
|
if (attempt >= MAX_CCIP_REDIRECTS) {
|
||||||
logger.throwError("CCIP read exceeded maximum redirections", "OFFCHAIN_FAULT", {
|
throwError("CCIP read exceeded maximum redirections", "OFFCHAIN_FAULT", {
|
||||||
reason: "TOO_MANY_REDIRECTS",
|
reason: "TOO_MANY_REDIRECTS",
|
||||||
transaction: Object.assign({ }, tx, { blockTag, enableCcipRead: true })
|
transaction: Object.assign({ }, tx, { blockTag, enableCcipRead: true })
|
||||||
});
|
});
|
||||||
@ -628,7 +629,7 @@ export class AbstractProvider implements Provider {
|
|||||||
try {
|
try {
|
||||||
ccipArgs = parseOffchainLookup(dataSlice(error.data, 4));
|
ccipArgs = parseOffchainLookup(dataSlice(error.data, 4));
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
return logger.throwError(error.message, "OFFCHAIN_FAULT", {
|
return throwError(error.message, "OFFCHAIN_FAULT", {
|
||||||
reason: "BAD_DATA",
|
reason: "BAD_DATA",
|
||||||
transaction, info: { data }
|
transaction, info: { data }
|
||||||
});
|
});
|
||||||
@ -636,7 +637,7 @@ export class AbstractProvider implements Provider {
|
|||||||
|
|
||||||
// Check the sender of the OffchainLookup matches the transaction
|
// Check the sender of the OffchainLookup matches the transaction
|
||||||
if (ccipArgs.sender.toLowerCase() !== txSender.toLowerCase()) {
|
if (ccipArgs.sender.toLowerCase() !== txSender.toLowerCase()) {
|
||||||
return logger.throwError("CCIP Read sender mismatch", "CALL_EXCEPTION", {
|
return throwError("CCIP Read sender mismatch", "CALL_EXCEPTION", {
|
||||||
data, transaction,
|
data, transaction,
|
||||||
errorSignature: "OffchainLookup(address,string[],bytes,bytes4,bytes)",
|
errorSignature: "OffchainLookup(address,string[],bytes,bytes4,bytes)",
|
||||||
errorName: "OffchainLookup",
|
errorName: "OffchainLookup",
|
||||||
@ -646,7 +647,7 @@ export class AbstractProvider implements Provider {
|
|||||||
|
|
||||||
const ccipResult = await this.ccipReadFetch(transaction, ccipArgs.calldata, ccipArgs.urls);
|
const ccipResult = await this.ccipReadFetch(transaction, ccipArgs.calldata, ccipArgs.urls);
|
||||||
if (ccipResult == null) {
|
if (ccipResult == null) {
|
||||||
return logger.throwError("CCIP Read failed to fetch data", "OFFCHAIN_FAULT", {
|
return throwError("CCIP Read failed to fetch data", "OFFCHAIN_FAULT", {
|
||||||
reason: "FETCH_FAILED",
|
reason: "FETCH_FAILED",
|
||||||
transaction, info: { data: error.data, errorArgs: ccipArgs.errorArgs }
|
transaction, info: { data: error.data, errorArgs: ccipArgs.errorArgs }
|
||||||
});
|
});
|
||||||
@ -684,11 +685,11 @@ export class AbstractProvider implements Provider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getBalance(address: AddressLike, blockTag?: BlockTag) {
|
async getBalance(address: AddressLike, blockTag?: BlockTag) {
|
||||||
return logger.getBigInt(await this.#getAccountValue({ method: "getBalance" }, address, blockTag), "%response");
|
return getBigInt(await this.#getAccountValue({ method: "getBalance" }, address, blockTag), "%response");
|
||||||
}
|
}
|
||||||
|
|
||||||
async getTransactionCount(address: AddressLike, blockTag?: BlockTag) {
|
async getTransactionCount(address: AddressLike, blockTag?: BlockTag) {
|
||||||
return logger.getNumber(await this.#getAccountValue({ method: "getTransactionCount" }, address, blockTag), "%response");
|
return getNumber(await this.#getAccountValue({ method: "getTransactionCount" }, address, blockTag), "%response");
|
||||||
}
|
}
|
||||||
|
|
||||||
async getCode(address: AddressLike, blockTag?: BlockTag) {
|
async getCode(address: AddressLike, blockTag?: BlockTag) {
|
||||||
@ -696,7 +697,7 @@ export class AbstractProvider implements Provider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getStorageAt(address: AddressLike, _position: BigNumberish, blockTag?: BlockTag) {
|
async getStorageAt(address: AddressLike, _position: BigNumberish, blockTag?: BlockTag) {
|
||||||
const position = logger.getBigInt(_position, "position");
|
const position = getBigInt(_position, "position");
|
||||||
return hexlify(await this.#getAccountValue({ method: "getStorageAt", position }, address, blockTag));
|
return hexlify(await this.#getAccountValue({ method: "getStorageAt", position }, address, blockTag));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -852,7 +853,7 @@ export class AbstractProvider implements Provider {
|
|||||||
|
|
||||||
// ENS
|
// ENS
|
||||||
_getProvider(chainId: number): AbstractProvider {
|
_getProvider(chainId: number): AbstractProvider {
|
||||||
return logger.throwError("provider cannot connect to target network", "UNSUPPORTED_OPERATION", {
|
return throwError("provider cannot connect to target network", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "_getProvider()"
|
operation: "_getProvider()"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -919,7 +920,7 @@ export class AbstractProvider implements Provider {
|
|||||||
if (timer == null) { return; }
|
if (timer == null) { return; }
|
||||||
timer = null;
|
timer = null;
|
||||||
this.off("block", listener);
|
this.off("block", listener);
|
||||||
reject(logger.makeError("timeout", "TIMEOUT", { reason: "timeout" }));
|
reject(makeError("timeout", "TIMEOUT", { reason: "timeout" }));
|
||||||
}, timeout);
|
}, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1153,7 +1154,7 @@ export class AbstractProvider implements Provider {
|
|||||||
pause(dropWhilePaused?: boolean): void {
|
pause(dropWhilePaused?: boolean): void {
|
||||||
if (this.#pausedState != null) {
|
if (this.#pausedState != null) {
|
||||||
if (this.#pausedState == !!dropWhilePaused) { return; }
|
if (this.#pausedState == !!dropWhilePaused) { return; }
|
||||||
return logger.throwError("cannot change pause type; resume first", "UNSUPPORTED_OPERATION", {
|
return throwError("cannot change pause type; resume first", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "pause"
|
operation: "pause"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1201,8 +1202,8 @@ function _parseString(result: string, start: number): null | string {
|
|||||||
function _parseBytes(result: string, start: number): null | string {
|
function _parseBytes(result: string, start: number): null | string {
|
||||||
if (result === "0x") { return null; }
|
if (result === "0x") { return null; }
|
||||||
try {
|
try {
|
||||||
const offset = logger.getNumber(dataSlice(result, start, start + 32));
|
const offset = getNumber(dataSlice(result, start, start + 32));
|
||||||
const length = logger.getNumber(dataSlice(result, offset, offset + 32));
|
const length = getNumber(dataSlice(result, offset, offset + 32));
|
||||||
|
|
||||||
return dataSlice(result, offset + 32, offset + 32 + length);
|
return dataSlice(result, offset + 32, offset + 32 + length);
|
||||||
} catch (error) { }
|
} catch (error) { }
|
||||||
@ -1241,7 +1242,7 @@ function encodeBytes(datas: Array<BytesLike>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < datas.length; i++) {
|
for (let i = 0; i < datas.length; i++) {
|
||||||
const data = logger.getBytes(datas[i]);
|
const data = getBytes(datas[i]);
|
||||||
|
|
||||||
// Update the bytes offset
|
// Update the bytes offset
|
||||||
result[i] = numPad(byteCount);
|
result[i] = numPad(byteCount);
|
||||||
@ -1274,8 +1275,8 @@ function parseOffchainLookup(data: string): CcipArgs {
|
|||||||
// Read the URLs from the response
|
// Read the URLs from the response
|
||||||
try {
|
try {
|
||||||
const urls: Array<string> = [];
|
const urls: Array<string> = [];
|
||||||
const urlsOffset = logger.getNumber(dataSlice(data, 32, 64));
|
const urlsOffset = getNumber(dataSlice(data, 32, 64));
|
||||||
const urlsLength = logger.getNumber(dataSlice(data, urlsOffset, urlsOffset + 32));
|
const urlsLength = getNumber(dataSlice(data, urlsOffset, urlsOffset + 32));
|
||||||
const urlsData = dataSlice(data, urlsOffset + 32);
|
const urlsData = dataSlice(data, urlsOffset + 32);
|
||||||
for (let u = 0; u < urlsLength; u++) {
|
for (let u = 0; u < urlsLength; u++) {
|
||||||
const url = _parseString(urlsData, u * 32);
|
const url = _parseString(urlsData, u * 32);
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import { logger } from "../utils/logger.js";
|
|
||||||
import { Transaction } from "../transaction/index.js";
|
import { Transaction } from "../transaction/index.js";
|
||||||
import { defineProperties, resolveProperties } from "../utils/index.js";
|
import {
|
||||||
|
defineProperties, resolveProperties,
|
||||||
|
throwArgumentError, throwError
|
||||||
|
} from "../utils/index.js";
|
||||||
|
|
||||||
import type { TypedDataDomain, TypedDataField } from "../hash/index.js";
|
import type { TypedDataDomain, TypedDataField } from "../hash/index.js";
|
||||||
import type { TransactionLike } from "../transaction/index.js";
|
import type { TransactionLike } from "../transaction/index.js";
|
||||||
@ -23,7 +25,7 @@ export abstract class AbstractSigner<P extends null | Provider = null | Provider
|
|||||||
|
|
||||||
#checkProvider(operation: string): Provider {
|
#checkProvider(operation: string): Provider {
|
||||||
if (this.provider) { return this.provider; }
|
if (this.provider) { return this.provider; }
|
||||||
return logger.throwError("missing provider", "UNSUPPORTED_OPERATION", { operation });
|
return throwError("missing provider", "UNSUPPORTED_OPERATION", { operation });
|
||||||
}
|
}
|
||||||
|
|
||||||
async getNonce(blockTag?: BlockTag): Promise<number> {
|
async getNonce(blockTag?: BlockTag): Promise<number> {
|
||||||
@ -39,7 +41,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) {
|
if (to == null) {
|
||||||
return logger.throwArgumentError("transaction to ENS name not configured", "tx.to", pop.to);
|
return throwArgumentError("transaction to ENS name not configured", "tx.to", pop.to);
|
||||||
}
|
}
|
||||||
return to;
|
return to;
|
||||||
});
|
});
|
||||||
@ -52,7 +54,7 @@ export abstract class AbstractSigner<P extends null | Provider = null | Provider
|
|||||||
this.resolveName(from)
|
this.resolveName(from)
|
||||||
]).then(([ address, from ]) => {
|
]).then(([ address, from ]) => {
|
||||||
if (!from || address.toLowerCase() !== from.toLowerCase()) {
|
if (!from || address.toLowerCase() !== from.toLowerCase()) {
|
||||||
return logger.throwArgumentError("transaction from mismatch", "tx.from", from);
|
return throwArgumentError("transaction from mismatch", "tx.from", from);
|
||||||
}
|
}
|
||||||
return address;
|
return address;
|
||||||
});
|
});
|
||||||
@ -123,7 +125,7 @@ export class VoidSigner extends AbstractSigner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#throwUnsupported(suffix: string, operation: string): never {
|
#throwUnsupported(suffix: string, operation: string): never {
|
||||||
return logger.throwError(`VoidSigner cannot sign ${ suffix }`, "UNSUPPORTED_OPERATION", {
|
return throwError(`VoidSigner cannot sign ${ suffix }`, "UNSUPPORTED_OPERATION", {
|
||||||
operation
|
operation
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import { ZeroHash } from "../constants/hashes.js";
|
import { ZeroHash } from "../constants/hashes.js";
|
||||||
import { dnsEncode, namehash } from "../hash/index.js";
|
import { dnsEncode, namehash } from "../hash/index.js";
|
||||||
import {
|
import {
|
||||||
defineProperties, encodeBase58, toArray, toNumber, toUtf8Bytes, toUtf8String
|
concat, dataSlice, getBytes, hexlify, zeroPadValue,
|
||||||
|
defineProperties, encodeBase58, getBigInt, toArray,
|
||||||
|
toNumber, toUtf8Bytes, toUtf8String,
|
||||||
|
throwArgumentError, throwError,
|
||||||
|
FetchRequest
|
||||||
} from "../utils/index.js";
|
} from "../utils/index.js";
|
||||||
import { concat, dataSlice, hexlify, zeroPadValue } from "../utils/data.js";
|
|
||||||
import { FetchRequest } from "../utils/fetch.js";
|
|
||||||
import { logger } from "../utils/logger.js";
|
|
||||||
|
|
||||||
import type { BigNumberish, BytesLike, EthersError } from "../utils/index.js";
|
import type { BigNumberish, BytesLike, EthersError } from "../utils/index.js";
|
||||||
|
|
||||||
@ -64,7 +65,7 @@ function encodeBytes(datas: Array<BytesLike>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < datas.length; i++) {
|
for (let i = 0; i < datas.length; i++) {
|
||||||
const data = logger.getBytes(datas[i]);
|
const data = getBytes(datas[i]);
|
||||||
|
|
||||||
// Update the bytes offset
|
// Update the bytes offset
|
||||||
result[i] = numPad(byteCount);
|
result[i] = numPad(byteCount);
|
||||||
@ -86,7 +87,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 {
|
||||||
logger.throwArgumentError("unsupported IPFS format", "link", link);
|
throwArgumentError("unsupported IPFS format", "link", link);
|
||||||
}
|
}
|
||||||
|
|
||||||
return `https:/\/gateway.ipfs.io/ipfs/${ link }`;
|
return `https:/\/gateway.ipfs.io/ipfs/${ link }`;
|
||||||
@ -170,7 +171,7 @@ export class EnsResolver {
|
|||||||
to: this.address,
|
to: this.address,
|
||||||
data: "0x01ffc9a79061b92300000000000000000000000000000000000000000000000000000000"
|
data: "0x01ffc9a79061b92300000000000000000000000000000000000000000000000000000000"
|
||||||
}).then((result) => {
|
}).then((result) => {
|
||||||
return (logger.getBigInt(result) === BN_1);
|
return (getBigInt(result) === BN_1);
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
if (error.code === "CALL_EXCEPTION") { return false; }
|
if (error.code === "CALL_EXCEPTION") { return false; }
|
||||||
// Rethrow the error: link is down, etc. Let future attempts retry.
|
// Rethrow the error: link is down, etc. Let future attempts retry.
|
||||||
@ -203,8 +204,8 @@ export class EnsResolver {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
let data = await this.provider.call(tx);
|
let data = await this.provider.call(tx);
|
||||||
if ((logger.getBytes(data).length % 32) === 4) {
|
if ((getBytes(data).length % 32) === 4) {
|
||||||
return logger.throwError("resolver threw error", "CALL_EXCEPTION", {
|
return throwError("resolver threw error", "CALL_EXCEPTION", {
|
||||||
transaction: tx, data
|
transaction: tx, data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -256,7 +257,7 @@ export class EnsResolver {
|
|||||||
|
|
||||||
if (address != null) { return address; }
|
if (address != null) { return address; }
|
||||||
|
|
||||||
return logger.throwError(`invalid coin data`, "UNSUPPORTED_OPERATION", {
|
return throwError(`invalid coin data`, "UNSUPPORTED_OPERATION", {
|
||||||
operation: `getAddress(${ coinType })`,
|
operation: `getAddress(${ coinType })`,
|
||||||
info: { coinType, data }
|
info: { coinType, data }
|
||||||
});
|
});
|
||||||
@ -268,7 +269,7 @@ export class EnsResolver {
|
|||||||
|
|
||||||
// The nodehash consumes the first slot, so the string pointer targets
|
// The nodehash consumes the first slot, so the string pointer targets
|
||||||
// offset 64, with the length at offset 64 and data starting at offset 96
|
// offset 64, with the length at offset 64 and data starting at offset 96
|
||||||
const calldata = logger.getBytes(concat([ numPad(64), numPad(keyBytes.length), keyBytes ]));
|
const calldata = getBytes(concat([ numPad(64), numPad(keyBytes.length), keyBytes ]));
|
||||||
|
|
||||||
const hexBytes = parseBytes((await this._fetch("0x59d1d43c", bytesPad(calldata))) || "0x", 0);
|
const hexBytes = parseBytes((await this._fetch("0x59d1d43c", bytesPad(calldata))) || "0x", 0);
|
||||||
if (hexBytes == null || hexBytes === "0x") { return null; }
|
if (hexBytes == null || hexBytes === "0x") { return null; }
|
||||||
@ -299,7 +300,7 @@ export class EnsResolver {
|
|||||||
return `bzz:/\/${ swarm[1] }`;
|
return `bzz:/\/${ swarm[1] }`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return logger.throwError(`invalid or unsupported content hash data`, "UNSUPPORTED_OPERATION", {
|
return throwError(`invalid or unsupported content hash data`, "UNSUPPORTED_OPERATION", {
|
||||||
operation: "getContentHash()",
|
operation: "getContentHash()",
|
||||||
info: { data: hexBytes }
|
info: { data: hexBytes }
|
||||||
});
|
});
|
||||||
@ -377,7 +378,7 @@ export class EnsResolver {
|
|||||||
|
|
||||||
} else if (scheme === "erc1155") {
|
} else if (scheme === "erc1155") {
|
||||||
// balanceOf(address owner, uint256 tokenId)
|
// balanceOf(address owner, uint256 tokenId)
|
||||||
const balance = logger.getBigInt(await this.provider.call({
|
const balance = getBigInt(await this.provider.call({
|
||||||
to: addr, data: concat([ "0x00fdd58e", zeroPadValue(owner, 32), tokenId ])
|
to: addr, data: concat([ "0x00fdd58e", zeroPadValue(owner, 32), tokenId ])
|
||||||
}));
|
}));
|
||||||
if (!balance) {
|
if (!balance) {
|
||||||
@ -479,7 +480,7 @@ export class EnsResolver {
|
|||||||
|
|
||||||
// No ENS...
|
// No ENS...
|
||||||
if (!ensPlugin) {
|
if (!ensPlugin) {
|
||||||
return logger.throwError("network does not support ENS", "UNSUPPORTED_OPERATION", {
|
return throwError("network does not support ENS", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "getResolver", info: { network: network.name }
|
operation: "getResolver", info: { network: network.name }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -16,9 +16,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { getAddress, getCreateAddress } from "../address/index.js";
|
import { getAddress, getCreateAddress } from "../address/index.js";
|
||||||
import { dataLength, dataSlice, isHexString } from "../utils/data.js";
|
import {
|
||||||
import { toQuantity } from "../utils/maths.js";
|
dataLength, dataSlice, getBigInt, getNumber, isHexString, toQuantity,
|
||||||
import { logger } from "../utils/logger.js";
|
throwArgumentError, throwError
|
||||||
|
} from "../utils/index.js";
|
||||||
import { Signature } from "../crypto/signature.js";
|
import { Signature } from "../crypto/signature.js";
|
||||||
import { accessListify } from "../transaction/index.js";
|
import { accessListify } from "../transaction/index.js";
|
||||||
|
|
||||||
@ -168,7 +169,7 @@ export class Formatter {
|
|||||||
// An address from a call result; may be zero-padded
|
// An address from a call result; may be zero-padded
|
||||||
callAddress(value: any): string {
|
callAddress(value: any): string {
|
||||||
if (dataLength(value) !== 32 || dataSlice(value, 0, 12) !== "0x000000000000000000000000") {
|
if (dataLength(value) !== 32 || dataSlice(value, 0, 12) !== "0x000000000000000000000000") {
|
||||||
logger.throwArgumentError("invalid call address", "value", value);
|
throwArgumentError("invalid call address", "value", value);
|
||||||
}
|
}
|
||||||
return this.address(dataSlice(value, 12));
|
return this.address(dataSlice(value, 12));
|
||||||
}
|
}
|
||||||
@ -177,7 +178,7 @@ export class Formatter {
|
|||||||
contractAddress(value: any): string {
|
contractAddress(value: any): string {
|
||||||
return getCreateAddress({
|
return getCreateAddress({
|
||||||
from: this.address(value.from),
|
from: this.address(value.from),
|
||||||
nonce: logger.getNumber(value.nonce, "value.nonce")
|
nonce: getNumber(value.nonce, "value.nonce")
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,7 +197,7 @@ export class Formatter {
|
|||||||
return toQuantity(value);
|
return toQuantity(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return logger.throwArgumentError("invalid blockTag", "value", value);
|
return throwArgumentError("invalid blockTag", "value", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Block objects
|
// Block objects
|
||||||
@ -279,20 +280,20 @@ export class Formatter {
|
|||||||
if (value === 0 || value === 1) {
|
if (value === 0 || value === 1) {
|
||||||
// Make sure if both are specified, they match
|
// Make sure if both are specified, they match
|
||||||
if (receipt.status != null && receipt.status !== value) {
|
if (receipt.status != null && receipt.status !== value) {
|
||||||
return logger.throwError("alt-root-status/status mismatch", "BAD_DATA", {
|
return throwError("alt-root-status/status mismatch", "BAD_DATA", {
|
||||||
value: { root: receipt.root, status: receipt.status }
|
value: { root: receipt.root, status: receipt.status }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
receipt.status = value;
|
receipt.status = value;
|
||||||
delete receipt.root;
|
delete receipt.root;
|
||||||
} else {
|
} else {
|
||||||
return logger.throwError("invalid alt-root-status", "BAD_DATA", {
|
return throwError("invalid alt-root-status", "BAD_DATA", {
|
||||||
value: receipt.root
|
value: receipt.root
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (!isHexString(receipt.root, 32)) {
|
} else if (!isHexString(receipt.root, 32)) {
|
||||||
// Must be a valid bytes32
|
// Must be a valid bytes32
|
||||||
return logger.throwError("invalid receipt root hash", "BAD_DATA", {
|
return throwError("invalid receipt root hash", "BAD_DATA", {
|
||||||
value: receipt.root
|
value: receipt.root
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -356,13 +357,13 @@ export class Formatter {
|
|||||||
|
|
||||||
// Requires a value which is a value BigNumber
|
// Requires a value which is a value BigNumber
|
||||||
bigNumber(value: any): bigint {
|
bigNumber(value: any): bigint {
|
||||||
return logger.getBigInt(value, "value");
|
return getBigInt(value, "value");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint256(value: any): bigint {
|
uint256(value: any): bigint {
|
||||||
const result = this.bigNumber(value);
|
const result = this.bigNumber(value);
|
||||||
if (result < 0 || result > BN_MAX_UINT256) {
|
if (result < 0 || result > BN_MAX_UINT256) {
|
||||||
logger.throwArgumentError("invalid uint256", "value", value);
|
throwArgumentError("invalid uint256", "value", value);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -375,7 +376,7 @@ export class Formatter {
|
|||||||
case false: case "false":
|
case false: case "false":
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return logger.throwArgumentError(`invalid boolean; ${ JSON.stringify(value) }`, "value", value);
|
return throwArgumentError(`invalid boolean; ${ JSON.stringify(value) }`, "value", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Requires a value which is a valid hexstring. If dataOrLength is true,
|
// Requires a value which is a valid hexstring. If dataOrLength is true,
|
||||||
@ -393,7 +394,7 @@ export class Formatter {
|
|||||||
|
|
||||||
data(value: string): string {
|
data(value: string): string {
|
||||||
if (dataLength(value) == null) {
|
if (dataLength(value) == null) {
|
||||||
logger.throwArgumentError("", "value", value);
|
throwArgumentError("", "value", value);
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
@ -401,14 +402,14 @@ export class Formatter {
|
|||||||
// Requires a network-native hash
|
// Requires a network-native hash
|
||||||
hash(value: any): string {
|
hash(value: any): string {
|
||||||
if (dataLength(value) !== 32) {
|
if (dataLength(value) !== 32) {
|
||||||
logger.throwArgumentError("", "value", value);
|
throwArgumentError("", "value", value);
|
||||||
}
|
}
|
||||||
return this.#format.data(value);
|
return this.#format.data(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Requires a valid number, within the IEEE 754 safe range
|
// Requires a valid number, within the IEEE 754 safe range
|
||||||
number(value: any): number {
|
number(value: any): number {
|
||||||
return logger.getNumber(value);
|
return getNumber(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Requires an object which matches a fleet of other formatters
|
// Requires an object which matches a fleet of other formatters
|
||||||
@ -433,7 +434,7 @@ export class Formatter {
|
|||||||
if (nv !== undefined) { result[key] = nv; }
|
if (nv !== undefined) { result[key] = nv; }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const message = (error instanceof Error) ? error.message: "not-an-error";
|
const message = (error instanceof Error) ? error.message: "not-an-error";
|
||||||
logger.throwError(`invalid value for value.${ key } (${ message })`, "BAD_DATA", { value })
|
throwError(`invalid value for value.${ key } (${ message })`, "BAD_DATA", { value })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { logger } from "../utils/logger.js";
|
import {
|
||||||
import { getStore, setStore } from "../utils/storage.js";
|
getStore, getBigInt, setStore, throwArgumentError
|
||||||
|
} from "../utils/index.js";
|
||||||
|
|
||||||
import { Formatter } from "./formatter.js";
|
import { Formatter } from "./formatter.js";
|
||||||
import { EnsPlugin, GasCostPlugin } from "./plugins-network.js";
|
import { EnsPlugin, GasCostPlugin } from "./plugins-network.js";
|
||||||
@ -96,7 +97,7 @@ export class Network implements Freezable<Network> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
constructor(name: string, _chainId: BigNumberish, formatter?: Formatter) {
|
constructor(name: string, _chainId: BigNumberish, formatter?: Formatter) {
|
||||||
const chainId = logger.getBigInt(_chainId);
|
const chainId = getBigInt(_chainId);
|
||||||
if (formatter == null) { formatter = defaultFormatter; }
|
if (formatter == null) { formatter = defaultFormatter; }
|
||||||
const plugins = new Map();
|
const plugins = new Map();
|
||||||
this.#props = { name, chainId, formatter, plugins };
|
this.#props = { name, chainId, formatter, plugins };
|
||||||
@ -110,7 +111,7 @@ export class Network implements Freezable<Network> {
|
|||||||
set name(value: string) { setStore(this.#props, "name", value); }
|
set name(value: string) { setStore(this.#props, "name", value); }
|
||||||
|
|
||||||
get chainId(): bigint { return getStore(this.#props, "chainId"); }
|
get chainId(): bigint { return getStore(this.#props, "chainId"); }
|
||||||
set chainId(value: BigNumberish) { setStore(this.#props, "chainId", logger.getBigInt(value, "chainId")); }
|
set chainId(value: BigNumberish) { setStore(this.#props, "chainId", getBigInt(value, "chainId")); }
|
||||||
|
|
||||||
get formatter(): Formatter { return getStore(this.#props, "formatter"); }
|
get formatter(): Formatter { return getStore(this.#props, "formatter"); }
|
||||||
set formatter(value: Formatter) { setStore(this.#props, "formatter", value); }
|
set formatter(value: Formatter) { setStore(this.#props, "formatter", value); }
|
||||||
@ -192,7 +193,7 @@ export class Network implements Freezable<Network> {
|
|||||||
return new Network("unknown", network);
|
return new Network("unknown", network);
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.throwArgumentError("unknown network", "network", network);
|
throwArgumentError("unknown network", "network", network);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clonable with network-like abilities
|
// Clonable with network-like abilities
|
||||||
@ -206,7 +207,7 @@ export class Network implements Freezable<Network> {
|
|||||||
// Networkish
|
// Networkish
|
||||||
if (typeof(network) === "object") {
|
if (typeof(network) === "object") {
|
||||||
if (typeof(network.name) !== "string" || typeof(network.chainId) !== "number") {
|
if (typeof(network.name) !== "string" || typeof(network.chainId) !== "number") {
|
||||||
logger.throwArgumentError("invalid network object name or chainId", "network", network);
|
throwArgumentError("invalid network object name or chainId", "network", network);
|
||||||
}
|
}
|
||||||
|
|
||||||
const custom = new Network(<string>(network.name), <number>(network.chainId));
|
const custom = new Network(<string>(network.name), <number>(network.chainId));
|
||||||
@ -222,14 +223,14 @@ export class Network implements Freezable<Network> {
|
|||||||
return custom;
|
return custom;
|
||||||
}
|
}
|
||||||
|
|
||||||
return logger.throwArgumentError("invalid network", "network", network);
|
return throwArgumentError("invalid network", "network", network);
|
||||||
}
|
}
|
||||||
|
|
||||||
static register(nameOrChainId: string | number | bigint, networkFunc: () => Network): void {
|
static register(nameOrChainId: string | number | bigint, networkFunc: () => Network): void {
|
||||||
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) {
|
||||||
logger.throwArgumentError(`conflicting network for ${ JSON.stringify(existing.name) }`, "nameOrChainId", nameOrChainId);
|
throwArgumentError(`conflicting network for ${ JSON.stringify(existing.name) }`, "nameOrChainId", nameOrChainId);
|
||||||
}
|
}
|
||||||
Networks.set(nameOrChainId, networkFunc);
|
Networks.set(nameOrChainId, networkFunc);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { defineProperties } from "../utils/properties.js";
|
import { defineProperties } from "../utils/properties.js";
|
||||||
|
|
||||||
import { logger } from "../utils/logger.js";
|
import { throwArgumentError } from "../utils/index.js";
|
||||||
|
|
||||||
//import { BigNumberish } from "../math/index.js";
|
//import { BigNumberish } from "../math/index.js";
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ export class GasCostPlugin extends NetworkPlugin {
|
|||||||
let value = (costs || { })[name];
|
let value = (costs || { })[name];
|
||||||
if (value == null) { value = nullish; }
|
if (value == null) { value = nullish; }
|
||||||
if (typeof(value) !== "number") {
|
if (typeof(value) !== "number") {
|
||||||
logger.throwArgumentError(`invalud value for ${ name }`, "costs", costs);
|
throwArgumentError(`invalud value for ${ name }`, "costs", costs);
|
||||||
}
|
}
|
||||||
props[name] = value;
|
props[name] = value;
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
|
|
||||||
import { defineProperties } from "../utils/properties.js";
|
import {
|
||||||
import { FetchRequest } from "../utils/fetch.js";
|
defineProperties, FetchRequest, throwArgumentError, throwError
|
||||||
|
} from "../utils/index.js";
|
||||||
|
|
||||||
import { showThrottleMessage } from "./community.js";
|
import { showThrottleMessage } from "./community.js";
|
||||||
import { logger } from "../utils/logger.js";
|
|
||||||
import { Network } from "./network.js";
|
import { Network } from "./network.js";
|
||||||
import { JsonRpcProvider } from "./provider-jsonrpc.js";
|
import { JsonRpcProvider } from "./provider-jsonrpc.js";
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ function getHost(name: string): string {
|
|||||||
return "opt-kovan.g.alchemy.com";
|
return "opt-kovan.g.alchemy.com";
|
||||||
}
|
}
|
||||||
|
|
||||||
return logger.throwArgumentError("unsupported network", "network", name);
|
return throwArgumentError("unsupported network", "network", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AlchemyProvider extends JsonRpcProvider implements CommunityResourcable {
|
export class AlchemyProvider extends JsonRpcProvider implements CommunityResourcable {
|
||||||
@ -79,14 +79,14 @@ export class AlchemyProvider extends JsonRpcProvider implements CommunityResourc
|
|||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
if (error) {
|
if (error) {
|
||||||
logger.throwError("an error occurred during transaction executions", "CALL_EXCEPTION", {
|
throwError("an error occurred during transaction executions", "CALL_EXCEPTION", {
|
||||||
data
|
data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
return logger.throwError("could not parse trace result", "BAD_DATA", { value: trace });
|
return throwError("could not parse trace result", "BAD_DATA", { value: trace });
|
||||||
}
|
}
|
||||||
|
|
||||||
return await super._perform(req);
|
return await super._perform(req);
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { defineProperties } from "../utils/properties.js";
|
import {
|
||||||
import { FetchRequest } from "../utils/fetch.js";
|
defineProperties, FetchRequest, throwArgumentError
|
||||||
|
} from "../utils/index.js";
|
||||||
|
|
||||||
import { AbstractProvider } from "./abstract-provider.js";
|
import { AbstractProvider } from "./abstract-provider.js";
|
||||||
import { showThrottleMessage } from "./community.js";
|
import { showThrottleMessage } from "./community.js";
|
||||||
import { logger } from "../utils/logger.js";
|
|
||||||
import { Network } from "./network.js";
|
import { Network } from "./network.js";
|
||||||
import { JsonRpcProvider } from "./provider-jsonrpc.js";
|
import { JsonRpcProvider } from "./provider-jsonrpc.js";
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ function getHost(name: string): string {
|
|||||||
case "arbitrum":
|
case "arbitrum":
|
||||||
return "rpc.ankr.com/arbitrum";
|
return "rpc.ankr.com/arbitrum";
|
||||||
}
|
}
|
||||||
return logger.throwArgumentError("unsupported network", "network", name);
|
return throwArgumentError("unsupported network", "network", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
import { throwArgumentError } from "../utils/index.js";
|
||||||
|
|
||||||
import { logger } from "../utils/logger.js";
|
|
||||||
import { Network } from "./network.js";
|
import { Network } from "./network.js";
|
||||||
import { JsonRpcProvider } from "./provider-jsonrpc.js";
|
import { JsonRpcProvider } from "./provider-jsonrpc.js";
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ export class CloudflareProvider extends JsonRpcProvider {
|
|||||||
constructor(_network: Networkish = "homestead") {
|
constructor(_network: Networkish = "homestead") {
|
||||||
const network = Network.from(_network);
|
const network = Network.from(_network);
|
||||||
if (network.name !== "homestead") {
|
if (network.name !== "homestead") {
|
||||||
return logger.throwArgumentError("unsupported network", "network", _network);
|
return throwArgumentError("unsupported network", "network", _network);
|
||||||
}
|
}
|
||||||
super("https:/\/cloudflare-eth.com/", network, { staticNetwork: network });
|
super("https:/\/cloudflare-eth.com/", network, { staticNetwork: network });
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import { hexlify, isHexString } from "../utils/data.js";
|
import {
|
||||||
import { toQuantity } from "../utils/maths.js";
|
defineProperties,
|
||||||
import { isError } from "../utils/errors.js";
|
hexlify, toQuantity,
|
||||||
import { defineProperties } from "../utils/properties.js";
|
FetchRequest,
|
||||||
import { toUtf8String } from "../utils/utf8.js";
|
throwArgumentError, throwError,
|
||||||
import { FetchRequest } from "../utils/fetch.js";
|
toUtf8String
|
||||||
|
} from "../utils/index.js";
|
||||||
if (false) { console.log(isHexString, isError); } // @TODO
|
|
||||||
|
|
||||||
import { AbstractProvider } from "./abstract-provider.js";
|
import { AbstractProvider } from "./abstract-provider.js";
|
||||||
import { Network } from "./network.js";
|
import { Network } from "./network.js";
|
||||||
@ -17,8 +16,6 @@ import type { Networkish } from "./network.js";
|
|||||||
//import type { } from "./pagination";
|
//import type { } from "./pagination";
|
||||||
import type { TransactionRequest } from "./provider.js";
|
import type { TransactionRequest } from "./provider.js";
|
||||||
|
|
||||||
import { logger } from "../utils/logger.js";
|
|
||||||
|
|
||||||
|
|
||||||
const defaultApiKey = "9D13ZE7XSBTJ94N9BNJ2MA33VMAY2YPIRB";
|
const defaultApiKey = "9D13ZE7XSBTJ94N9BNJ2MA33VMAY2YPIRB";
|
||||||
|
|
||||||
@ -82,7 +79,7 @@ export class EtherscanProvider extends AbstractProvider {
|
|||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
return logger.throwArgumentError("unsupported network", "network", this.network);
|
return throwArgumentError("unsupported network", "network", this.network);
|
||||||
}
|
}
|
||||||
|
|
||||||
getUrl(module: string, params: Record<string, string>): string {
|
getUrl(module: string, params: Record<string, string>): string {
|
||||||
@ -358,7 +355,7 @@ export class EtherscanProvider extends AbstractProvider {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return logger.throwError("getBlock by blockHash not supported by Etherscan", "UNSUPPORTED_OPERATION", {
|
return throwError("getBlock by blockHash not supported by Etherscan", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "getBlock(blockHash)"
|
operation: "getBlock(blockHash)"
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
|
|
||||||
import { hexlify } from "../utils/data.js";
|
import {
|
||||||
|
getBigInt, getNumber, hexlify, throwError, throwArgumentError
|
||||||
|
} from "../utils/index.js";
|
||||||
|
|
||||||
import { AbstractProvider } from "./abstract-provider.js";
|
import { AbstractProvider } from "./abstract-provider.js";
|
||||||
import { logger } from "../utils/logger.js";
|
|
||||||
import { Network } from "./network.js"
|
import { Network } from "./network.js"
|
||||||
|
|
||||||
import type { Frozen } from "../utils/index.js";
|
import type { Frozen } from "../utils/index.js";
|
||||||
@ -23,7 +24,7 @@ function shuffle<T = any>(array: Array<T>): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function stall(duration: number) {
|
function stall(duration: number): Promise<void> {
|
||||||
return new Promise((resolve) => { setTimeout(resolve, duration); });
|
return new Promise((resolve) => { setTimeout(resolve, duration); });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,15 +135,15 @@ type RunningState = {
|
|||||||
function normalize(network: Frozen<Network>, value: any, req: PerformActionRequest): string {
|
function normalize(network: Frozen<Network>, value: any, req: PerformActionRequest): string {
|
||||||
switch (req.method) {
|
switch (req.method) {
|
||||||
case "chainId":
|
case "chainId":
|
||||||
return logger.getBigInt(value).toString();
|
return getBigInt(value).toString();
|
||||||
case "getBlockNumber":
|
case "getBlockNumber":
|
||||||
return logger.getNumber(value).toString();
|
return getNumber(value).toString();
|
||||||
case "getGasPrice":
|
case "getGasPrice":
|
||||||
return logger.getBigInt(value).toString();
|
return getBigInt(value).toString();
|
||||||
case "getBalance":
|
case "getBalance":
|
||||||
return logger.getBigInt(value).toString();
|
return getBigInt(value).toString();
|
||||||
case "getTransactionCount":
|
case "getTransactionCount":
|
||||||
return logger.getNumber(value).toString();
|
return getNumber(value).toString();
|
||||||
case "getCode":
|
case "getCode":
|
||||||
return hexlify(value);
|
return hexlify(value);
|
||||||
case "getStorageAt":
|
case "getStorageAt":
|
||||||
@ -159,12 +160,12 @@ function normalize(network: Frozen<Network>, value: any, req: PerformActionReque
|
|||||||
case "call":
|
case "call":
|
||||||
return hexlify(value);
|
return hexlify(value);
|
||||||
case "estimateGas":
|
case "estimateGas":
|
||||||
return logger.getBigInt(value).toString();
|
return getBigInt(value).toString();
|
||||||
case "getLogs":
|
case "getLogs":
|
||||||
return JSON.stringify(value.map((v: any) => network.formatter.log(v)));
|
return JSON.stringify(value.map((v: any) => network.formatter.log(v)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return logger.throwError("unsupported method", "UNSUPPORTED_OPERATION", {
|
return throwError("unsupported method", "UNSUPPORTED_OPERATION", {
|
||||||
operation: `_perform(${ JSON.stringify(req.method) })`
|
operation: `_perform(${ JSON.stringify(req.method) })`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -220,7 +221,7 @@ function getMedian(results: Array<TallyResult>): bigint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getFuzzyMode(quorum: number, results: Array<TallyResult>): undefined | number {
|
function getFuzzyMode(quorum: number, results: Array<TallyResult>): undefined | number {
|
||||||
if (quorum === 1) { return logger.getNumber(getMedian(results), "%internal"); }
|
if (quorum === 1) { return getNumber(getMedian(results), "%internal"); }
|
||||||
|
|
||||||
const tally: Map<number, { result: number, weight: number }> = new Map();
|
const tally: Map<number, { result: number, weight: number }> = new Map();
|
||||||
const add = (result: number, weight: number) => {
|
const add = (result: number, weight: number) => {
|
||||||
@ -230,7 +231,7 @@ function getFuzzyMode(quorum: number, results: Array<TallyResult>): undefined |
|
|||||||
};
|
};
|
||||||
|
|
||||||
for (const { weight, result } of results) {
|
for (const { weight, result } of results) {
|
||||||
const r = logger.getNumber(result);
|
const r = getNumber(result);
|
||||||
add(r - 1, weight);
|
add(r - 1, weight);
|
||||||
add(r, weight);
|
add(r, weight);
|
||||||
add(r + 1, weight);
|
add(r + 1, weight);
|
||||||
@ -282,7 +283,7 @@ export class FallbackProvider extends AbstractProvider {
|
|||||||
this.eventWorkers = 1;
|
this.eventWorkers = 1;
|
||||||
|
|
||||||
if (this.quorum > this.#configs.reduce((a, c) => (a + c.weight), 0)) {
|
if (this.quorum > this.#configs.reduce((a, c) => (a + c.weight), 0)) {
|
||||||
logger.throwArgumentError("quorum exceed provider wieght", "quorum", this.quorum);
|
throwArgumentError("quorum exceed provider wieght", "quorum", this.quorum);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,8 +292,8 @@ export class FallbackProvider extends AbstractProvider {
|
|||||||
return this.#configs.slice();
|
return this.#configs.slice();
|
||||||
}
|
}
|
||||||
|
|
||||||
async _detectNetwork() {
|
async _detectNetwork(): Promise<Frozen<Network>> {
|
||||||
return Network.from(logger.getBigInt(await this._perform({ method: "chainId" }))).freeze();
|
return Network.from(getBigInt(await this._perform({ method: "chainId" }))).freeze();
|
||||||
}
|
}
|
||||||
|
|
||||||
// @TODO: Add support to select providers to be the event subscriber
|
// @TODO: Add support to select providers to be the event subscriber
|
||||||
@ -382,7 +383,7 @@ export class FallbackProvider extends AbstractProvider {
|
|||||||
if (chainId == null) {
|
if (chainId == null) {
|
||||||
chainId = network.chainId;
|
chainId = network.chainId;
|
||||||
} else if (network.chainId !== chainId) {
|
} else if (network.chainId !== chainId) {
|
||||||
logger.throwError("cannot mix providers on different networks", "UNSUPPORTED_OPERATION", {
|
throwError("cannot mix providers on different networks", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "new FallbackProvider"
|
operation: "new FallbackProvider"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -417,9 +418,9 @@ export class FallbackProvider extends AbstractProvider {
|
|||||||
case "getBlockNumber": {
|
case "getBlockNumber": {
|
||||||
// We need to get the bootstrap block height
|
// We need to get the bootstrap block height
|
||||||
if (this.#height === -2) {
|
if (this.#height === -2) {
|
||||||
const height = Math.ceil(logger.getNumber(getMedian(this.#configs.map((c) => ({
|
const height = Math.ceil(getNumber(getMedian(this.#configs.map((c) => ({
|
||||||
result: c.blockNumber,
|
result: c.blockNumber,
|
||||||
normal: logger.getNumber(c.blockNumber).toString(),
|
normal: getNumber(c.blockNumber).toString(),
|
||||||
weight: c.weight
|
weight: c.weight
|
||||||
}))), "%internal"));
|
}))), "%internal"));
|
||||||
this.#height = height;
|
this.#height = height;
|
||||||
@ -461,7 +462,7 @@ export class FallbackProvider extends AbstractProvider {
|
|||||||
throw new Error("TODO");
|
throw new Error("TODO");
|
||||||
}
|
}
|
||||||
|
|
||||||
return logger.throwError("unsupported method", "UNSUPPORTED_OPERATION", {
|
return throwError("unsupported method", "UNSUPPORTED_OPERATION", {
|
||||||
operation: `_perform(${ JSON.stringify((<any>req).method) })`
|
operation: `_perform(${ JSON.stringify((<any>req).method) })`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { defineProperties } from "../utils/properties.js";
|
import {
|
||||||
import { FetchRequest } from "../utils/fetch.js";
|
defineProperties, FetchRequest, throwArgumentError
|
||||||
|
} from "../utils/index.js";
|
||||||
|
|
||||||
import { showThrottleMessage } from "./community.js";
|
import { showThrottleMessage } from "./community.js";
|
||||||
import { logger } from "../utils/logger.js";
|
|
||||||
import { Network } from "./network.js";
|
import { Network } from "./network.js";
|
||||||
import { JsonRpcProvider } from "./provider-jsonrpc.js";
|
import { JsonRpcProvider } from "./provider-jsonrpc.js";
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ function getHost(name: string): string {
|
|||||||
return "arbitrum-rinkeby.infura.io";
|
return "arbitrum-rinkeby.infura.io";
|
||||||
}
|
}
|
||||||
|
|
||||||
return logger.throwArgumentError("unsupported network", "network", name);
|
return throwArgumentError("unsupported network", "network", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,13 +4,13 @@
|
|||||||
// https://playground.open-rpc.org/?schemaUrl=https://raw.githubusercontent.com/ethereum/eth1.0-apis/assembled-spec/openrpc.json&uiSchema%5BappBar%5D%5Bui:splitView%5D=true&uiSchema%5BappBar%5D%5Bui:input%5D=false&uiSchema%5BappBar%5D%5Bui:examplesDropdown%5D=false
|
// https://playground.open-rpc.org/?schemaUrl=https://raw.githubusercontent.com/ethereum/eth1.0-apis/assembled-spec/openrpc.json&uiSchema%5BappBar%5D%5Bui:splitView%5D=true&uiSchema%5BappBar%5D%5Bui:input%5D=false&uiSchema%5BappBar%5D%5Bui:examplesDropdown%5D=false
|
||||||
|
|
||||||
import { resolveAddress } from "../address/index.js";
|
import { resolveAddress } from "../address/index.js";
|
||||||
import { hexlify } from "../utils/data.js";
|
|
||||||
import { FetchRequest } from "../utils/fetch.js";
|
|
||||||
import { toQuantity } from "../utils/maths.js";
|
|
||||||
import { defineProperties } from "../utils/properties.js";
|
|
||||||
import { TypedDataEncoder } from "../hash/typed-data.js";
|
import { TypedDataEncoder } from "../hash/typed-data.js";
|
||||||
import { toUtf8Bytes } from "../utils/utf8.js";
|
|
||||||
import { accessListify } from "../transaction/index.js";
|
import { accessListify } from "../transaction/index.js";
|
||||||
|
import {
|
||||||
|
defineProperties, getBigInt, hexlify, toQuantity, toUtf8Bytes,
|
||||||
|
throwArgumentError, throwError,
|
||||||
|
FetchRequest
|
||||||
|
} from "../utils/index.js";
|
||||||
|
|
||||||
import { AbstractProvider, UnmanagedSubscriber } from "./abstract-provider.js";
|
import { AbstractProvider, UnmanagedSubscriber } from "./abstract-provider.js";
|
||||||
import { AbstractSigner } from "./abstract-signer.js";
|
import { AbstractSigner } from "./abstract-signer.js";
|
||||||
@ -25,8 +25,6 @@ import type { Networkish } from "./network.js";
|
|||||||
import type { Provider, TransactionRequest, TransactionResponse } from "./provider.js";
|
import type { Provider, TransactionRequest, TransactionResponse } from "./provider.js";
|
||||||
import type { Signer } from "./signer.js";
|
import type { Signer } from "./signer.js";
|
||||||
|
|
||||||
import { logger } from "../utils/logger.js";
|
|
||||||
|
|
||||||
|
|
||||||
//function copy<T = any>(value: T): T {
|
//function copy<T = any>(value: T): T {
|
||||||
// return JSON.parse(JSON.stringify(value));
|
// return JSON.parse(JSON.stringify(value));
|
||||||
@ -149,7 +147,7 @@ export class JsonRpcSigner extends AbstractSigner<JsonRpcApiProvider> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
connect(provider: null | Provider): Signer {
|
connect(provider: null | Provider): Signer {
|
||||||
return logger.throwError("cannot reconnect JsonRpcSigner", "UNSUPPORTED_OPERATION", {
|
return throwError("cannot reconnect JsonRpcSigner", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "signer.connect"
|
operation: "signer.connect"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -196,7 +194,7 @@ export class JsonRpcSigner extends AbstractSigner<JsonRpcApiProvider> {
|
|||||||
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()) {
|
if (from == null || from.toLowerCase() !== this.address.toLowerCase()) {
|
||||||
logger.throwArgumentError("from address mismatch", "transaction", _tx);
|
throwArgumentError("from address mismatch", "transaction", _tx);
|
||||||
}
|
}
|
||||||
tx.from = from;
|
tx.from = from;
|
||||||
})());
|
})());
|
||||||
@ -263,7 +261,7 @@ export class JsonRpcSigner extends AbstractSigner<JsonRpcApiProvider> {
|
|||||||
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()) {
|
if (from == null || from.toLowerCase() !== this.address.toLowerCase()) {
|
||||||
return logger.throwArgumentError("from address mismatch", "transaction", _tx);
|
return throwArgumentError("from address mismatch", "transaction", _tx);
|
||||||
}
|
}
|
||||||
tx.from = from;
|
tx.from = from;
|
||||||
} else {
|
} else {
|
||||||
@ -288,7 +286,7 @@ export class JsonRpcSigner extends AbstractSigner<JsonRpcApiProvider> {
|
|||||||
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) {
|
if (address == null) {
|
||||||
return logger.throwArgumentError("TypedData does not support null address", "value", value);
|
return throwArgumentError("TypedData does not support null address", "value", value);
|
||||||
}
|
}
|
||||||
return address;
|
return address;
|
||||||
});
|
});
|
||||||
@ -337,7 +335,7 @@ 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 && staticNetwork !== network) {
|
if (staticNetwork && staticNetwork !== network) {
|
||||||
logger.throwArgumentError("staticNetwork MUST match network object", "options", options);
|
throwArgumentError("staticNetwork MUST match network object", "options", options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -445,7 +443,7 @@ export class JsonRpcApiProvider extends AbstractProvider {
|
|||||||
|
|
||||||
// Sub-classes MUST override this
|
// Sub-classes MUST override this
|
||||||
_send(payload: JsonRpcPayload | Array<JsonRpcPayload>): Promise<Array<JsonRpcResult | JsonRpcError>> {
|
_send(payload: JsonRpcPayload | Array<JsonRpcPayload>): Promise<Array<JsonRpcResult | JsonRpcError>> {
|
||||||
return logger.throwError("sub-classes must override _send", "UNSUPPORTED_OPERATION", {
|
return throwError("sub-classes must override _send", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "jsonRpcApiProvider._send"
|
operation: "jsonRpcApiProvider._send"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -481,7 +479,7 @@ export class JsonRpcApiProvider extends AbstractProvider {
|
|||||||
const network = this._getOption("staticNetwork");
|
const network = this._getOption("staticNetwork");
|
||||||
if (network) { return network; }
|
if (network) { return network; }
|
||||||
|
|
||||||
return Network.from(logger.getBigInt(await this._perform({ method: "chainId" })));
|
return Network.from(getBigInt(await this._perform({ method: "chainId" })));
|
||||||
}
|
}
|
||||||
|
|
||||||
_getSubscriber(sub: Subscription): Subscriber {
|
_getSubscriber(sub: Subscription): Subscriber {
|
||||||
@ -510,7 +508,7 @@ export class JsonRpcApiProvider extends AbstractProvider {
|
|||||||
if ((<any>tx)[key] == null) { return; }
|
if ((<any>tx)[key] == null) { return; }
|
||||||
let dstKey = key;
|
let dstKey = key;
|
||||||
if (key === "gasLimit") { dstKey = "gas"; }
|
if (key === "gasLimit") { dstKey = "gas"; }
|
||||||
(<any>result)[dstKey] = toQuantity(logger.getBigInt((<any>tx)[key], `tx.${ key }`));
|
(<any>result)[dstKey] = toQuantity(getBigInt((<any>tx)[key], `tx.${ key }`));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Make sure addresses and data are lowercase
|
// Make sure addresses and data are lowercase
|
||||||
@ -693,7 +691,7 @@ export class JsonRpcApiProvider extends AbstractProvider {
|
|||||||
// is fair), so we delete type if it is 0 and a non-EIP-1559 network
|
// is fair), so we delete type if it is 0 and a non-EIP-1559 network
|
||||||
if (req.method === "call" || req.method === "estimateGas") {
|
if (req.method === "call" || req.method === "estimateGas") {
|
||||||
let tx = req.transaction;
|
let tx = req.transaction;
|
||||||
if (tx && tx.type != null && logger.getBigInt(tx.type)) {
|
if (tx && tx.type != null && getBigInt(tx.type)) {
|
||||||
// If there are no EIP-1559 properties, it might be non-EIP-a559
|
// If there are no EIP-1559 properties, it might be non-EIP-a559
|
||||||
if (tx.maxFeePerGas == null && tx.maxPriorityFeePerGas == null) {
|
if (tx.maxFeePerGas == null && tx.maxPriorityFeePerGas == null) {
|
||||||
const feeData = await this.getFeeData();
|
const feeData = await this.getFeeData();
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { UnmanagedSubscriber } from "./abstract-provider.js";
|
import { UnmanagedSubscriber } from "./abstract-provider.js";
|
||||||
import { assertArgument, logger } from "../utils/logger.js";
|
import { assertArgument, makeError, throwError } from "../utils/index.js";
|
||||||
import { JsonRpcApiProvider } from "./provider-jsonrpc.js";
|
import { JsonRpcApiProvider } from "./provider-jsonrpc.js";
|
||||||
|
|
||||||
import type { Subscriber, Subscription } from "./abstract-provider.js";
|
import type { Subscriber, Subscription } from "./abstract-provider.js";
|
||||||
@ -65,7 +65,7 @@ export class SocketSubscriber implements Subscriber {
|
|||||||
// and resume
|
// and resume
|
||||||
pause(dropWhilePaused?: boolean): void {
|
pause(dropWhilePaused?: boolean): void {
|
||||||
if (!dropWhilePaused) {
|
if (!dropWhilePaused) {
|
||||||
logger.throwError("preserve logs while paused not supported by SocketSubscriber yet", "UNSUPPORTED_OPERATION", {
|
throwError("preserve logs while paused not supported by SocketSubscriber yet", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "pause(false)"
|
operation: "pause(false)"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -228,7 +228,7 @@ export class SocketProvider extends JsonRpcApiProvider {
|
|||||||
|
|
||||||
if ("error" in result) {
|
if ("error" in result) {
|
||||||
const { message, code, data } = result.error;
|
const { message, code, data } = result.error;
|
||||||
const error = logger.makeError(message || "unkonwn error", "SERVER_ERROR", {
|
const error = makeError(message || "unkonwn error", "SERVER_ERROR", {
|
||||||
request: `ws:${ JSON.stringify(callback.payload) }`,
|
request: `ws:${ JSON.stringify(callback.payload) }`,
|
||||||
info: { code, data }
|
info: { code, data }
|
||||||
});
|
});
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
//import { resolveAddress } from "@ethersproject/address";
|
//import { resolveAddress } from "@ethersproject/address";
|
||||||
import { hexlify } from "../utils/data.js";
|
import {
|
||||||
import { logger } from "../utils/logger.js";
|
defineProperties, getBigInt, getNumber, hexlify, throwError
|
||||||
import { defineProperties } from "../utils/properties.js";
|
} from "../utils/index.js";
|
||||||
import { accessListify } from "../transaction/index.js";
|
import { accessListify } from "../transaction/index.js";
|
||||||
|
|
||||||
|
|
||||||
import type { AddressLike, NameResolver } from "../address/index.js";
|
import type { AddressLike, NameResolver } from "../address/index.js";
|
||||||
import type { BigNumberish, EventEmitterable, Frozen, Listener } from "../utils/index.js";
|
import type { BigNumberish, EventEmitterable, Frozen, Listener } from "../utils/index.js";
|
||||||
import type { Signature } from "../crypto/index.js";
|
import type { Signature } from "../crypto/index.js";
|
||||||
@ -127,13 +126,13 @@ export function copyRequest(req: CallRequest): PreparedRequest {
|
|||||||
const bigIntKeys = "chainId,gasLimit,gasPrice,maxFeePerGas, maxPriorityFeePerGas,value".split(/,/);
|
const bigIntKeys = "chainId,gasLimit,gasPrice,maxFeePerGas, maxPriorityFeePerGas,value".split(/,/);
|
||||||
for (const key in bigIntKeys) {
|
for (const key in bigIntKeys) {
|
||||||
if (!(key in req) || (<any>req)[key] == null) { continue; }
|
if (!(key in req) || (<any>req)[key] == null) { continue; }
|
||||||
result[key] = logger.getBigInt((<any>req)[key], `request.${ key }`);
|
result[key] = getBigInt((<any>req)[key], `request.${ key }`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const numberKeys = "type,nonce".split(/,/);
|
const numberKeys = "type,nonce".split(/,/);
|
||||||
for (const key in numberKeys) {
|
for (const key in numberKeys) {
|
||||||
if (!(key in req) || (<any>req)[key] == null) { continue; }
|
if (!(key in req) || (<any>req)[key] == null) { continue; }
|
||||||
result[key] = logger.getNumber((<any>req)[key], `request.${ key }`);
|
result[key] = getNumber((<any>req)[key], `request.${ key }`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.accessList) {
|
if (req.accessList) {
|
||||||
@ -585,7 +584,7 @@ export class TransactionReceipt implements TransactionReceiptParams, Iterable<Lo
|
|||||||
|
|
||||||
reorderedEvent(other?: TransactionResponse): OrphanFilter {
|
reorderedEvent(other?: TransactionResponse): OrphanFilter {
|
||||||
if (other && !other.isMined()) {
|
if (other && !other.isMined()) {
|
||||||
return logger.throwError("unmined 'other' transction cannot be orphaned", "UNSUPPORTED_OPERATION", {
|
return throwError("unmined 'other' transction cannot be orphaned", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "reorderedEvent(other)" });
|
operation: "reorderedEvent(other)" });
|
||||||
}
|
}
|
||||||
return createReorderedTransactionFilter(this, other);
|
return createReorderedTransactionFilter(this, other);
|
||||||
@ -775,7 +774,7 @@ export class TransactionResponse implements TransactionLike<string>, Transaction
|
|||||||
|
|
||||||
removedEvent(): OrphanFilter {
|
removedEvent(): OrphanFilter {
|
||||||
if (!this.isMined()) {
|
if (!this.isMined()) {
|
||||||
return logger.throwError("unmined transaction canot be orphaned", "UNSUPPORTED_OPERATION", {
|
return throwError("unmined transaction canot be orphaned", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "removeEvent()" });
|
operation: "removeEvent()" });
|
||||||
}
|
}
|
||||||
return createRemovedTransactionFilter(this);
|
return createRemovedTransactionFilter(this);
|
||||||
@ -783,11 +782,11 @@ export class TransactionResponse implements TransactionLike<string>, Transaction
|
|||||||
|
|
||||||
reorderedEvent(other?: TransactionResponse): OrphanFilter {
|
reorderedEvent(other?: TransactionResponse): OrphanFilter {
|
||||||
if (!this.isMined()) {
|
if (!this.isMined()) {
|
||||||
return logger.throwError("unmined transaction canot be orphaned", "UNSUPPORTED_OPERATION", {
|
return throwError("unmined transaction canot be orphaned", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "removeEvent()" });
|
operation: "removeEvent()" });
|
||||||
}
|
}
|
||||||
if (other && !other.isMined()) {
|
if (other && !other.isMined()) {
|
||||||
return logger.throwError("unmined 'other' transaction canot be orphaned", "UNSUPPORTED_OPERATION", {
|
return throwError("unmined 'other' transaction canot be orphaned", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "removeEvent()" });
|
operation: "removeEvent()" });
|
||||||
}
|
}
|
||||||
return createReorderedTransactionFilter(this, other);
|
return createReorderedTransactionFilter(this, other);
|
||||||
@ -1006,7 +1005,7 @@ export interface Provider extends ContractRunner, EventEmitterable<ProviderEvent
|
|||||||
waitForBlock(blockTag?: BlockTag): Promise<Block<string>>;
|
waitForBlock(blockTag?: BlockTag): Promise<Block<string>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @TODO: I think I can drop T
|
||||||
function fail<T>(): T {
|
function fail<T>(): T {
|
||||||
throw new Error("this provider should not be used");
|
throw new Error("this provider should not be used");
|
||||||
}
|
}
|
||||||
@ -1014,64 +1013,64 @@ function fail<T>(): T {
|
|||||||
class DummyProvider implements Provider {
|
class DummyProvider implements Provider {
|
||||||
get provider(): this { return this; }
|
get provider(): this { return this; }
|
||||||
|
|
||||||
async getNetwork() { return fail<Frozen<Network>>(); }
|
async getNetwork(): Promise<Frozen<Network>> { return fail<Frozen<Network>>(); }
|
||||||
async getFeeData() { return fail<FeeData>(); }
|
async getFeeData(): Promise<FeeData> { return fail<FeeData>(); }
|
||||||
|
|
||||||
async estimateGas(tx: TransactionRequest) { return fail<bigint>(); }
|
async estimateGas(tx: TransactionRequest): Promise<bigint> { return fail<bigint>(); }
|
||||||
async call(tx: CallRequest) { return fail<string>(); }
|
async call(tx: CallRequest): Promise<string> { return fail<string>(); }
|
||||||
|
|
||||||
async resolveName(name: string) { return fail<null | string>(); }
|
async resolveName(name: string): Promise<null | string> { return fail<null | string>(); }
|
||||||
|
|
||||||
// State
|
// State
|
||||||
async getBlockNumber() { return fail<number>(); }
|
async getBlockNumber(): Promise<number> { return fail<number>(); }
|
||||||
|
|
||||||
// Account
|
// Account
|
||||||
async getBalance(address: AddressLike, blockTag?: BlockTag) {
|
async getBalance(address: AddressLike, blockTag?: BlockTag): Promise<bigint> {
|
||||||
return fail<bigint>();
|
return fail<bigint>();
|
||||||
}
|
}
|
||||||
async getTransactionCount(address: AddressLike, blockTag?: BlockTag) {
|
async getTransactionCount(address: AddressLike, blockTag?: BlockTag): Promise<number> {
|
||||||
return fail<number>();
|
return fail<number>();
|
||||||
}
|
}
|
||||||
|
|
||||||
async getCode(address: AddressLike, blockTag?: BlockTag) {
|
async getCode(address: AddressLike, blockTag?: BlockTag): Promise<string> {
|
||||||
return fail<string>();
|
return fail<string>();
|
||||||
}
|
}
|
||||||
async getStorageAt(address: AddressLike, position: BigNumberish, blockTag?: BlockTag) {
|
async getStorageAt(address: AddressLike, position: BigNumberish, blockTag?: BlockTag): Promise<string> {
|
||||||
return fail<string>();
|
return fail<string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write
|
// Write
|
||||||
async broadcastTransaction(signedTx: string) { return fail<TransactionResponse>(); }
|
async broadcastTransaction(signedTx: string): Promise<TransactionResponse> { return fail<TransactionResponse>(); }
|
||||||
|
|
||||||
// Queries
|
// Queries
|
||||||
async getBlock(blockHashOrBlockTag: BlockTag | string){
|
async getBlock(blockHashOrBlockTag: BlockTag | string): Promise<null | Block<string>>{
|
||||||
return fail<null | Block<string>>();
|
return fail<null | Block<string>>();
|
||||||
}
|
}
|
||||||
async getBlockWithTransactions(blockHashOrBlockTag: BlockTag | string) {
|
async getBlockWithTransactions(blockHashOrBlockTag: BlockTag | string): Promise<null | Block<TransactionResponse>> {
|
||||||
return fail<null | Block<TransactionResponse>>();
|
return fail<null | Block<TransactionResponse>>();
|
||||||
}
|
}
|
||||||
async getTransaction(hash: string) {
|
async getTransaction(hash: string): Promise<null | TransactionResponse> {
|
||||||
return fail<null | TransactionResponse>();
|
return fail<null | TransactionResponse>();
|
||||||
}
|
}
|
||||||
async getTransactionReceipt(hash: string) {
|
async getTransactionReceipt(hash: string): Promise<null | TransactionReceipt> {
|
||||||
return fail<null | TransactionReceipt>();
|
return fail<null | TransactionReceipt>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bloom-filter Queries
|
// Bloom-filter Queries
|
||||||
async getLogs(filter: Filter | FilterByBlockHash) {
|
async getLogs(filter: Filter | FilterByBlockHash): Promise<Array<Log>> {
|
||||||
return fail<Array<Log>>();
|
return fail<Array<Log>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ENS
|
// ENS
|
||||||
async lookupAddress(address: string) {
|
async lookupAddress(address: string): Promise<null | string> {
|
||||||
return fail<null | string>();
|
return fail<null | string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
async waitForTransaction(hash: string, confirms?: number, timeout?: number) {
|
async waitForTransaction(hash: string, confirms?: number, timeout?: number): Promise<null | TransactionReceipt> {
|
||||||
return fail<null | TransactionReceipt>();
|
return fail<null | TransactionReceipt>();
|
||||||
}
|
}
|
||||||
|
|
||||||
async waitForBlock(blockTag?: BlockTag) {
|
async waitForBlock(blockTag?: BlockTag): Promise<Block<string>> {
|
||||||
return fail<Block<string>>();
|
return fail<Block<string>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
|
import { getNumber } from "../utils/index.js";
|
||||||
|
|
||||||
import type { Subscriber } from "./abstract-provider.js";
|
import type { Subscriber } from "./abstract-provider.js";
|
||||||
import { logger } from "../utils/logger.js";
|
|
||||||
|
|
||||||
|
|
||||||
//#TODO: Temp
|
//#TODO: Temp
|
||||||
@ -25,7 +26,7 @@ export class BlockConnectionSubscriber implements Subscriber {
|
|||||||
|
|
||||||
start(): void {
|
start(): void {
|
||||||
this.#filterId = this.#provider._subscribe([ "newHeads" ], (result: any) => {
|
this.#filterId = this.#provider._subscribe([ "newHeads" ], (result: any) => {
|
||||||
const blockNumber = logger.getNumber(result.number);
|
const blockNumber = getNumber(result.number);
|
||||||
const initial = (this.#blockNumber === -2) ? blockNumber: (this.#blockNumber + 1)
|
const initial = (this.#blockNumber === -2) ? blockNumber: (this.#blockNumber + 1)
|
||||||
for (let b = initial; b <= blockNumber; b++) {
|
for (let b = initial; b <= blockNumber; b++) {
|
||||||
this.#provider.emit("block", b);
|
this.#provider.emit("block", b);
|
||||||
|
@ -2,7 +2,7 @@ import { isHexString } from "../utils/data.js";
|
|||||||
|
|
||||||
import type { AbstractProvider, Subscriber } from "./abstract-provider.js";
|
import type { AbstractProvider, Subscriber } from "./abstract-provider.js";
|
||||||
import type { EventFilter, OrphanFilter, ProviderEvent } from "./provider.js";
|
import type { EventFilter, OrphanFilter, ProviderEvent } from "./provider.js";
|
||||||
import { logger } from "../utils/logger.js";
|
import { throwError } from "../utils/index.js";
|
||||||
|
|
||||||
function copy(obj: any): any {
|
function copy(obj: any): any {
|
||||||
return JSON.parse(JSON.stringify(obj));
|
return JSON.parse(JSON.stringify(obj));
|
||||||
@ -12,7 +12,7 @@ export function getPollingSubscriber(provider: AbstractProvider, event: Provider
|
|||||||
if (event === "block") { return new PollingBlockSubscriber(provider); }
|
if (event === "block") { return new PollingBlockSubscriber(provider); }
|
||||||
if (isHexString(event, 32)) { return new PollingTransactionSubscriber(provider, event); }
|
if (isHexString(event, 32)) { return new PollingTransactionSubscriber(provider, event); }
|
||||||
|
|
||||||
return logger.throwError("unsupported polling event", "UNSUPPORTED_OPERATION", {
|
return throwError("unsupported polling event", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "getPollingSubscriber", info: { event }
|
operation: "getPollingSubscriber", info: { event }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
import { getAddress } from "../address/index.js";
|
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, getStore, hexlify, logger, setStore, toArray, zeroPadValue
|
concat, decodeRlp, encodeRlp, getBytes, getStore, getBigInt, getNumber, hexlify,
|
||||||
|
setStore, throwArgumentError, toArray, zeroPadValue
|
||||||
} from "../utils/index.js";
|
} from "../utils/index.js";
|
||||||
|
|
||||||
import { accessListify } from "./accesslist.js";
|
import { accessListify } from "./accesslist.js";
|
||||||
@ -55,7 +56,7 @@ function handleData(value: string, param: string): string {
|
|||||||
try {
|
try {
|
||||||
return hexlify(value);
|
return hexlify(value);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return logger.throwArgumentError("invalid data", param, value);
|
return throwArgumentError("invalid data", param, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,27 +64,27 @@ function handleAccessList(value: any, param: string): AccessList {
|
|||||||
try {
|
try {
|
||||||
return accessListify(value);
|
return accessListify(value);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return logger.throwArgumentError("invalid accessList", param, value);
|
return throwArgumentError("invalid accessList", param, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleNumber(_value: string, param: string): number {
|
function handleNumber(_value: string, param: string): number {
|
||||||
if (_value === "0x") { return 0; }
|
if (_value === "0x") { return 0; }
|
||||||
return logger.getNumber(_value, param);
|
return getNumber(_value, param);
|
||||||
}
|
}
|
||||||
|
|
||||||
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 = logger.getBigInt(_value, param);
|
const value = getBigInt(_value, param);
|
||||||
if (value > BN_MAX_UINT) { logger.throwArgumentError("value exceeds uint size", param, value); }
|
if (value > BN_MAX_UINT) { throwArgumentError("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 = logger.getBigInt(_value, "value");
|
const value = getBigInt(_value, "value");
|
||||||
const result = toArray(value);
|
const result = toArray(value);
|
||||||
if (result.length > 32) {
|
if (result.length > 32) {
|
||||||
logger.throwArgumentError(`value too large`, `tx.${ name }`, value);
|
throwArgumentError(`value too large`, `tx.${ name }`, value);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -96,7 +97,7 @@ 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)) {
|
if (!Array.isArray(fields) || (fields.length !== 9 && fields.length !== 6)) {
|
||||||
return logger.throwArgumentError("invalid field count for legacy transaction", "data", data);
|
return throwArgumentError("invalid field count for legacy transaction", "data", data);
|
||||||
}
|
}
|
||||||
|
|
||||||
const tx: TransactionLike = {
|
const tx: TransactionLike = {
|
||||||
@ -130,7 +131,7 @@ function _parseLegacy(data: Uint8Array): TransactionLike {
|
|||||||
|
|
||||||
// Signed Legacy Transaction
|
// Signed Legacy Transaction
|
||||||
if (chainId === BN_0 && (v < BN_27 || v > BN_28)) {
|
if (chainId === BN_0 && (v < BN_27 || v > BN_28)) {
|
||||||
logger.throwArgumentError("non-canonical legacy v", "v", fields[6]);
|
throwArgumentError("non-canonical legacy v", "v", fields[6]);
|
||||||
}
|
}
|
||||||
|
|
||||||
tx.signature = Signature.from({
|
tx.signature = Signature.from({
|
||||||
@ -158,12 +159,12 @@ function _serializeLegacy(tx: Transaction, sig?: Signature): string {
|
|||||||
let chainId = BN_0;
|
let chainId = BN_0;
|
||||||
if (tx.chainId != null) {
|
if (tx.chainId != null) {
|
||||||
// A chainId was provided; if non-zero we'll use EIP-155
|
// A chainId was provided; if non-zero we'll use EIP-155
|
||||||
chainId = logger.getBigInt(tx.chainId, "tx.chainId");
|
chainId = getBigInt(tx.chainId, "tx.chainId");
|
||||||
|
|
||||||
// We have a chainId in the tx and an EIP-155 v in the signature,
|
// 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) {
|
if (sig && sig.networkV != null && sig.legacyChainId !== chainId) {
|
||||||
logger.throwArgumentError("tx.chainId/sig.v mismatch", "sig", sig);
|
throwArgumentError("tx.chainId/sig.v mismatch", "sig", sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (sig) {
|
} else if (sig) {
|
||||||
@ -189,7 +190,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) {
|
||||||
logger.throwArgumentError("tx.chainId/sig.v mismatch", "sig", sig);
|
throwArgumentError("tx.chainId/sig.v mismatch", "sig", sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
fields.push(toArray(v));
|
fields.push(toArray(v));
|
||||||
@ -205,7 +206,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 logger.throwArgumentError("invalid yParity", "yParity", fields[0]);
|
return throwArgumentError("invalid yParity", "yParity", fields[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const r = zeroPadValue(fields[1], 32);
|
const r = zeroPadValue(fields[1], 32);
|
||||||
@ -216,10 +217,10 @@ function _parseEipSignature(tx: TransactionLike, fields: Array<string>, serializ
|
|||||||
}
|
}
|
||||||
|
|
||||||
function _parseEip1559(data: Uint8Array): TransactionLike {
|
function _parseEip1559(data: Uint8Array): TransactionLike {
|
||||||
const fields: any = decodeRlp(logger.getBytes(data).slice(1));
|
const fields: any = decodeRlp(getBytes(data).slice(1));
|
||||||
|
|
||||||
if (!Array.isArray(fields) || (fields.length !== 9 && fields.length !== 12)) {
|
if (!Array.isArray(fields) || (fields.length !== 9 && fields.length !== 12)) {
|
||||||
logger.throwArgumentError("invalid field count for transaction type: 2", "data", hexlify(data));
|
throwArgumentError("invalid field count for transaction type: 2", "data", hexlify(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
const maxPriorityFeePerGas = handleUint(fields[2], "maxPriorityFeePerGas");
|
const maxPriorityFeePerGas = handleUint(fields[2], "maxPriorityFeePerGas");
|
||||||
@ -271,10 +272,10 @@ function _serializeEip1559(tx: TransactionLike, sig?: Signature): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function _parseEip2930(data: Uint8Array): TransactionLike {
|
function _parseEip2930(data: Uint8Array): TransactionLike {
|
||||||
const fields: any = decodeRlp(logger.getBytes(data).slice(1));
|
const fields: any = decodeRlp(getBytes(data).slice(1));
|
||||||
|
|
||||||
if (!Array.isArray(fields) || (fields.length !== 8 && fields.length !== 11)) {
|
if (!Array.isArray(fields) || (fields.length !== 8 && fields.length !== 11)) {
|
||||||
logger.throwArgumentError("invalid field count for transaction type: 1", "data", hexlify(data));
|
throwArgumentError("invalid field count for transaction type: 1", "data", hexlify(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
const tx: TransactionLike = {
|
const tx: TransactionLike = {
|
||||||
@ -397,10 +398,10 @@ export class Transaction implements Freezable<Transaction>, TransactionLike<stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
get nonce(): number { return getStore(this.#props, "nonce"); }
|
get nonce(): number { return getStore(this.#props, "nonce"); }
|
||||||
set nonce(value: BigNumberish) { setStore(this.#props, "nonce", logger.getNumber(value, "value")); }
|
set nonce(value: BigNumberish) { setStore(this.#props, "nonce", getNumber(value, "value")); }
|
||||||
|
|
||||||
get gasLimit(): bigint { return getStore(this.#props, "gasLimit"); }
|
get gasLimit(): bigint { return getStore(this.#props, "gasLimit"); }
|
||||||
set gasLimit(value: BigNumberish) { setStore(this.#props, "gasLimit", logger.getBigInt(value)); }
|
set gasLimit(value: BigNumberish) { setStore(this.#props, "gasLimit", getBigInt(value)); }
|
||||||
|
|
||||||
get gasPrice(): null | bigint {
|
get gasPrice(): null | bigint {
|
||||||
const value = getStore(this.#props, "gasPrice");
|
const value = getStore(this.#props, "gasPrice");
|
||||||
@ -408,7 +409,7 @@ export class Transaction implements Freezable<Transaction>, TransactionLike<stri
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
set gasPrice(value: null | BigNumberish) {
|
set gasPrice(value: null | BigNumberish) {
|
||||||
setStore(this.#props, "gasPrice", (value == null) ? null: logger.getBigInt(value, "gasPrice"));
|
setStore(this.#props, "gasPrice", (value == null) ? null: getBigInt(value, "gasPrice"));
|
||||||
}
|
}
|
||||||
|
|
||||||
get maxPriorityFeePerGas(): null | bigint {
|
get maxPriorityFeePerGas(): null | bigint {
|
||||||
@ -417,7 +418,7 @@ export class Transaction implements Freezable<Transaction>, TransactionLike<stri
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
set maxPriorityFeePerGas(value: null | BigNumberish) {
|
set maxPriorityFeePerGas(value: null | BigNumberish) {
|
||||||
setStore(this.#props, "maxPriorityFeePerGas", (value == null) ? null: logger.getBigInt(value, "maxPriorityFeePerGas"));
|
setStore(this.#props, "maxPriorityFeePerGas", (value == null) ? null: getBigInt(value, "maxPriorityFeePerGas"));
|
||||||
}
|
}
|
||||||
|
|
||||||
get maxFeePerGas(): null | bigint {
|
get maxFeePerGas(): null | bigint {
|
||||||
@ -426,7 +427,7 @@ export class Transaction implements Freezable<Transaction>, TransactionLike<stri
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
set maxFeePerGas(value: null | BigNumberish) {
|
set maxFeePerGas(value: null | BigNumberish) {
|
||||||
setStore(this.#props, "maxFeePerGas", (value == null) ? null: logger.getBigInt(value, "maxFeePerGas"));
|
setStore(this.#props, "maxFeePerGas", (value == null) ? null: getBigInt(value, "maxFeePerGas"));
|
||||||
}
|
}
|
||||||
|
|
||||||
get data(): string { return getStore(this.#props, "data"); }
|
get data(): string { return getStore(this.#props, "data"); }
|
||||||
@ -434,11 +435,11 @@ export class Transaction implements Freezable<Transaction>, TransactionLike<stri
|
|||||||
|
|
||||||
get value(): bigint { return getStore(this.#props, "value"); }
|
get value(): bigint { return getStore(this.#props, "value"); }
|
||||||
set value(value: BigNumberish) {
|
set value(value: BigNumberish) {
|
||||||
setStore(this.#props, "value", logger.getBigInt(value, "value"));
|
setStore(this.#props, "value", getBigInt(value, "value"));
|
||||||
}
|
}
|
||||||
|
|
||||||
get chainId(): bigint { return getStore(this.#props, "chainId"); }
|
get chainId(): bigint { return getStore(this.#props, "chainId"); }
|
||||||
set chainId(value: BigNumberish) { setStore(this.#props, "chainId", logger.getBigInt(value)); }
|
set chainId(value: BigNumberish) { setStore(this.#props, "chainId", getBigInt(value)); }
|
||||||
|
|
||||||
get signature(): null | Signature { return getStore(this.#props, "sig") || null; }
|
get signature(): null | Signature { return getStore(this.#props, "sig") || null; }
|
||||||
set signature(value: null | SignatureLike) {
|
set signature(value: null | SignatureLike) {
|
||||||
@ -624,7 +625,7 @@ export class Transaction implements Freezable<Transaction>, TransactionLike<stri
|
|||||||
|
|
||||||
static from(tx: string | TransactionLike<string>): Transaction {
|
static from(tx: string | TransactionLike<string>): Transaction {
|
||||||
if (typeof(tx) === "string") {
|
if (typeof(tx) === "string") {
|
||||||
const payload = logger.getBytes(tx);
|
const payload = getBytes(tx);
|
||||||
|
|
||||||
if (payload[0] >= 0x7f) { // @TODO: > vs >= ??
|
if (payload[0] >= 0x7f) { // @TODO: > vs >= ??
|
||||||
return Transaction.from(_parseLegacy(payload));
|
return Transaction.from(_parseLegacy(payload));
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
|
|
||||||
import { logger } from "./logger.js";
|
import { getBytes } from "./data.js";
|
||||||
|
import { throwArgumentError } from "./errors.js";
|
||||||
import { toBigInt, toHex } from "./maths.js";
|
import { toBigInt, toHex } from "./maths.js";
|
||||||
|
|
||||||
import type { BytesLike } from "./index.js";
|
import type { BytesLike } from "./index.js";
|
||||||
@ -17,7 +18,7 @@ function getAlpha(letter: string): bigint {
|
|||||||
}
|
}
|
||||||
const result = Lookup[letter];
|
const result = Lookup[letter];
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
logger.throwArgumentError(`invalid base58 value`, "letter", letter);
|
throwArgumentError(`invalid base58 value`, "letter", letter);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -30,7 +31,7 @@ const BN_58 = BigInt(58);
|
|||||||
* Encode %%value%% as Base58-encoded data.
|
* Encode %%value%% as Base58-encoded data.
|
||||||
*/
|
*/
|
||||||
export function encodeBase58(_value: BytesLike): string {
|
export function encodeBase58(_value: BytesLike): string {
|
||||||
let value = toBigInt(logger.getBytes(_value));
|
let value = toBigInt(getBytes(_value));
|
||||||
let result = "";
|
let result = "";
|
||||||
while (value) {
|
while (value) {
|
||||||
result = Alphabet[Number(value % BN_58)] + result;
|
result = Alphabet[Number(value % BN_58)] + result;
|
||||||
@ -42,11 +43,11 @@ export function encodeBase58(_value: BytesLike): string {
|
|||||||
/**
|
/**
|
||||||
* Decode the Base58-encoded %%value%%.
|
* Decode the Base58-encoded %%value%%.
|
||||||
*/
|
*/
|
||||||
export function decodeBase58(value: string): string {
|
export function decodeBase58(value: string): Uint8Array {
|
||||||
let result = BN_0;
|
let result = BN_0;
|
||||||
for (let i = 0; i < value.length; i++) {
|
for (let i = 0; i < value.length; i++) {
|
||||||
result *= BN_58;
|
result *= BN_58;
|
||||||
result += getAlpha(value[i]);
|
result += getAlpha(value[i]);
|
||||||
}
|
}
|
||||||
return toHex(result);
|
return getBytes(toHex(result));
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
// utils/base64-browser
|
// utils/base64-browser
|
||||||
|
|
||||||
import { logger } from "./logger.js";
|
import { getBytes } from "./data.js";
|
||||||
|
|
||||||
import type { BytesLike } from "./data.js";
|
import type { BytesLike } from "./data.js";
|
||||||
|
|
||||||
@ -12,11 +12,11 @@ export function decodeBase64(textData: string): Uint8Array {
|
|||||||
for (let i = 0; i < textData.length; i++) {
|
for (let i = 0; i < textData.length; i++) {
|
||||||
data[i] = textData.charCodeAt(i);
|
data[i] = textData.charCodeAt(i);
|
||||||
}
|
}
|
||||||
return logger.getBytes(data);
|
return getBytes(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function encodeBase64(_data: BytesLike): string {
|
export function encodeBase64(_data: BytesLike): string {
|
||||||
const data = logger.getBytes(_data);
|
const data = getBytes(_data);
|
||||||
let textData = "";
|
let textData = "";
|
||||||
for (let i = 0; i < data.length; i++) {
|
for (let i = 0; i < data.length; i++) {
|
||||||
textData += String.fromCharCode(data[i]);
|
textData += String.fromCharCode(data[i]);
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { logger } from "./logger.js";
|
import { getBytes, getBytesCopy } from "./data.js";
|
||||||
|
|
||||||
import type { BytesLike } from "./data.js";
|
import type { BytesLike } from "./data.js";
|
||||||
|
|
||||||
|
|
||||||
export function decodeBase64(textData: string): Uint8Array {
|
export function decodeBase64(textData: string): Uint8Array {
|
||||||
return logger.getBytesCopy(Buffer.from(textData, "base64"));
|
return getBytesCopy(Buffer.from(textData, "base64"));
|
||||||
};
|
};
|
||||||
|
|
||||||
export function encodeBase64(data: BytesLike): string {
|
export function encodeBase64(data: BytesLike): string {
|
||||||
return Buffer.from(logger.getBytes(data)).toString("base64");
|
return Buffer.from(getBytes(data)).toString("base64");
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,37 @@
|
|||||||
import { logger } from "./logger.js";
|
import { throwArgumentError, throwError } from "./errors.js";
|
||||||
|
|
||||||
|
|
||||||
export type BytesLike = string | Uint8Array;
|
export type BytesLike = string | Uint8Array;
|
||||||
|
|
||||||
|
function _getBytes(value: BytesLike, name?: string, copy?: boolean): Uint8Array {
|
||||||
|
if (value instanceof Uint8Array) {
|
||||||
|
if (copy) { return new Uint8Array(value); }
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
export function isHexString(value: any, length?: number | boolean): value is string {
|
if (typeof(value) === "string" && value.match(/^0x([0-9a-f][0-9a-f])*$/i)) {
|
||||||
|
const result = new Uint8Array((value.length - 2) / 2);
|
||||||
|
let offset = 2;
|
||||||
|
for (let i = 0; i < result.length; i++) {
|
||||||
|
result[i] = parseInt(value.substring(offset, offset + 2), 16);
|
||||||
|
offset += 2;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return throwArgumentError("invalid BytesLike value", name || "value", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getBytes(value: BytesLike, name?: string): Uint8Array {
|
||||||
|
return _getBytes(value, name, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getBytesCopy(value: BytesLike, name?: string): Uint8Array {
|
||||||
|
return _getBytes(value, name, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function isHexString(value: any, length?: number | boolean): value is `0x${ string }` {
|
||||||
if (typeof(value) !== "string" || !value.match(/^0x[0-9A-Fa-f]*$/)) {
|
if (typeof(value) !== "string" || !value.match(/^0x[0-9A-Fa-f]*$/)) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -20,7 +48,7 @@ export function isBytesLike(value: any): value is BytesLike {
|
|||||||
|
|
||||||
const HexCharacters: string = "0123456789abcdef";
|
const HexCharacters: string = "0123456789abcdef";
|
||||||
export function hexlify(data: BytesLike): string {
|
export function hexlify(data: BytesLike): string {
|
||||||
const bytes = logger.getBytes(data);
|
const bytes = getBytes(data);
|
||||||
|
|
||||||
let result = "0x";
|
let result = "0x";
|
||||||
for (let i = 0; i < bytes.length; i++) {
|
for (let i = 0; i < bytes.length; i++) {
|
||||||
@ -36,12 +64,12 @@ export function concat(datas: ReadonlyArray<BytesLike>): string {
|
|||||||
|
|
||||||
export function dataLength(data: BytesLike): number {
|
export function dataLength(data: BytesLike): number {
|
||||||
if (isHexString(data, true)) { return (data.length - 2) / 2; }
|
if (isHexString(data, true)) { return (data.length - 2) / 2; }
|
||||||
return logger.getBytes(data).length;
|
return getBytes(data).length;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function dataSlice(data: BytesLike, start?: number, end?: number): string {
|
export function dataSlice(data: BytesLike, start?: number, end?: number): string {
|
||||||
const bytes = logger.getBytes(data);
|
const bytes = getBytes(data);
|
||||||
if (end != null && end > bytes.length) { logger.throwError("cannot slice beyond data bounds", "BUFFER_OVERRUN", {
|
if (end != null && end > bytes.length) { throwError("cannot slice beyond data bounds", "BUFFER_OVERRUN", {
|
||||||
buffer: bytes, length: bytes.length, offset: end
|
buffer: bytes, length: bytes.length, offset: end
|
||||||
}); }
|
}); }
|
||||||
return hexlify(bytes.slice((start == null) ? 0: start, (end == null) ? bytes.length: end));
|
return hexlify(bytes.slice((start == null) ? 0: start, (end == null) ? bytes.length: end));
|
||||||
@ -55,9 +83,9 @@ export function stripZerosLeft(data: BytesLike): string {
|
|||||||
|
|
||||||
|
|
||||||
function zeroPad(data: BytesLike, length: number, left: boolean): string {
|
function zeroPad(data: BytesLike, length: number, left: boolean): string {
|
||||||
const bytes = logger.getBytes(data);
|
const bytes = getBytes(data);
|
||||||
if (length < bytes.length) {
|
if (length < bytes.length) {
|
||||||
logger.throwError("padding exceeds data length", "BUFFER_OVERRUN", {
|
throwError("padding exceeds data length", "BUFFER_OVERRUN", {
|
||||||
buffer: new Uint8Array(bytes),
|
buffer: new Uint8Array(bytes),
|
||||||
length: length,
|
length: length,
|
||||||
offset: length + 1
|
offset: length + 1
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
//export type TransactionReceipt {
|
//export type TransactionReceipt {
|
||||||
//}
|
//}
|
||||||
|
import { version } from "../_version.js";
|
||||||
|
|
||||||
|
import { defineReadOnly } from "./properties.js";
|
||||||
|
|
||||||
export type ErrorSignature = {
|
export type ErrorSignature = {
|
||||||
r: string;
|
r: string;
|
||||||
@ -10,6 +13,13 @@ export type ErrorSignature = {
|
|||||||
|
|
||||||
export type ErrorAccessList = Array<{ address: string, storageKeys: Array<string> }>;
|
export type ErrorAccessList = Array<{ address: string, storageKeys: Array<string> }>;
|
||||||
|
|
||||||
|
export type ErrorInfo<T> = Omit<T, "code" | "name" | "message">;
|
||||||
|
|
||||||
|
// The type of error to use for various error codes
|
||||||
|
const ErrorConstructors: Record<string, { new (...args: Array<any>): Error }> = { };
|
||||||
|
ErrorConstructors.INVALID_ARGUMENT = TypeError;
|
||||||
|
ErrorConstructors.NUMERIC_FAULT = RangeError;
|
||||||
|
ErrorConstructors.BUFFER_OVERRUN = RangeError;
|
||||||
/*
|
/*
|
||||||
export interface ErrorTransaction {
|
export interface ErrorTransaction {
|
||||||
type?: number;
|
type?: number;
|
||||||
@ -237,6 +247,12 @@ export interface ActionRejectedError extends EthersError<"ACTION_REJECTED"> {
|
|||||||
|
|
||||||
// Coding; converts an ErrorCode its Typed Error
|
// Coding; converts an ErrorCode its Typed Error
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A conditional type that transforms the [[ErrorCode]] T into
|
||||||
|
* its EthersError type.
|
||||||
|
*
|
||||||
|
* @flatworm-skip-docs
|
||||||
|
*/
|
||||||
export type CodedEthersError<T> =
|
export type CodedEthersError<T> =
|
||||||
T extends "UNKNOWN_ERROR" ? UnknownError:
|
T extends "UNKNOWN_ERROR" ? UnknownError:
|
||||||
T extends "NOT_IMPLEMENTED" ? NotImplementedError:
|
T extends "NOT_IMPLEMENTED" ? NotImplementedError:
|
||||||
@ -267,6 +283,8 @@ export type CodedEthersError<T> =
|
|||||||
|
|
||||||
never;
|
never;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* try {
|
* try {
|
||||||
* // code....
|
* // code....
|
||||||
@ -283,3 +301,111 @@ export function isError<K extends ErrorCode, T extends CodedEthersError<K>>(erro
|
|||||||
export function isCallException(error: any): error is CallExceptionError {
|
export function isCallException(error: any): error is CallExceptionError {
|
||||||
return isError(error, "CALL_EXCEPTION");
|
return isError(error, "CALL_EXCEPTION");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function makeError<K extends ErrorCode, T extends CodedEthersError<K>>(message: string, code: K, info?: ErrorInfo<T>): T {
|
||||||
|
{
|
||||||
|
const details: Array<string> = [];
|
||||||
|
if (info) {
|
||||||
|
for (const key in info) {
|
||||||
|
const value = <any>(info[<keyof ErrorInfo<T>>key]);
|
||||||
|
try {
|
||||||
|
details.push(key + "=" + JSON.stringify(value));
|
||||||
|
} catch (error) {
|
||||||
|
details.push(key + "=[could not serialize object]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
details.push(`code=${ code }`);
|
||||||
|
details.push(`version=${ version }`);
|
||||||
|
|
||||||
|
if (details.length) {
|
||||||
|
message += " (" + details.join(", ") + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const create = ErrorConstructors[code] || Error;
|
||||||
|
const error = <T>(new create(message));
|
||||||
|
defineReadOnly(error, "code", code);
|
||||||
|
if (info) {
|
||||||
|
for (const key in info) {
|
||||||
|
defineReadOnly(error, <keyof T>key, <any>(info[<keyof ErrorInfo<T>>key]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return <T>error;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function throwError<K extends ErrorCode, T extends CodedEthersError<K>>(message: string, code: K, info?: ErrorInfo<T>): never {
|
||||||
|
throw makeError(message, code, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function throwArgumentError(message: string, name: string, value: any): never {
|
||||||
|
return throwError(message, "INVALID_ARGUMENT", {
|
||||||
|
argument: name,
|
||||||
|
value: value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function assertArgument(check: unknown, message: string, name: string, value: unknown): asserts check {
|
||||||
|
if (!check) { throwArgumentError(message, name, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function assertArgumentCount(count: number, expectedCount: number, message: string = ""): void {
|
||||||
|
if (message) { message = ": " + message; }
|
||||||
|
|
||||||
|
if (count < expectedCount) {
|
||||||
|
throwError("missing arguemnt" + message, "MISSING_ARGUMENT", {
|
||||||
|
count: count,
|
||||||
|
expectedCount: expectedCount
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > expectedCount) {
|
||||||
|
throwError("too many arguemnts" + message, "UNEXPECTED_ARGUMENT", {
|
||||||
|
count: count,
|
||||||
|
expectedCount: expectedCount
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const _normalizeForms = ["NFD", "NFC", "NFKD", "NFKC"].reduce((accum, form) => {
|
||||||
|
try {
|
||||||
|
// General test for normalize
|
||||||
|
/* c8 ignore start */
|
||||||
|
if ("test".normalize(form) !== "test") { throw new Error("bad"); };
|
||||||
|
/* c8 ignore stop */
|
||||||
|
|
||||||
|
if (form === "NFD") {
|
||||||
|
const check = String.fromCharCode(0xe9).normalize("NFD");
|
||||||
|
const expected = String.fromCharCode(0x65, 0x0301)
|
||||||
|
/* c8 ignore start */
|
||||||
|
if (check !== expected) { throw new Error("broken") }
|
||||||
|
/* c8 ignore stop */
|
||||||
|
}
|
||||||
|
|
||||||
|
accum.push(form);
|
||||||
|
} catch(error) { }
|
||||||
|
|
||||||
|
return accum;
|
||||||
|
}, <Array<string>>[]);
|
||||||
|
|
||||||
|
export function assertNormalize(form: string): void {
|
||||||
|
if (_normalizeForms.indexOf(form) === -1) {
|
||||||
|
throwError("platform missing String.prototype.normalize", "UNSUPPORTED_OPERATION", {
|
||||||
|
operation: "String.prototype.normalize", info: { form }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function assertPrivate(givenGuard: any, guard: any, className: string = ""): void {
|
||||||
|
if (givenGuard !== guard) {
|
||||||
|
let method = className, operation = "new";
|
||||||
|
if (className) {
|
||||||
|
method += ".";
|
||||||
|
operation += " " + className;
|
||||||
|
}
|
||||||
|
throwError(`private constructor; use ${ method }from* methods`, "UNSUPPORTED_OPERATION", {
|
||||||
|
operation
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { decodeBase64, encodeBase64 } from "./base64.js";
|
import { decodeBase64, encodeBase64 } from "./base64.js";
|
||||||
import { hexlify } from "./data.js";
|
import { hexlify } from "./data.js";
|
||||||
import { assertArgument, logger } from "./logger.js";
|
import { assertArgument, throwArgumentError, throwError } from "./errors.js";
|
||||||
import { defineProperties } from "./properties.js";
|
import { defineProperties } from "./properties.js";
|
||||||
import { toUtf8Bytes, toUtf8String } from "./utf8.js"
|
import { toUtf8Bytes, toUtf8String } from "./utf8.js"
|
||||||
|
|
||||||
@ -114,7 +114,7 @@ export class FetchCancelSignal {
|
|||||||
|
|
||||||
addListener(listener: () => void): void {
|
addListener(listener: () => void): void {
|
||||||
if (this.#cancelled) {
|
if (this.#cancelled) {
|
||||||
logger.throwError("singal already cancelled", "UNSUPPORTED_OPERATION", {
|
throwError("singal already cancelled", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "fetchCancelSignal.addCancelListener"
|
operation: "fetchCancelSignal.addCancelListener"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -125,7 +125,7 @@ export class FetchCancelSignal {
|
|||||||
|
|
||||||
checkSignal(): void {
|
checkSignal(): void {
|
||||||
if (!this.cancelled) { return; }
|
if (!this.cancelled) { return; }
|
||||||
logger.throwError("cancelled", "CANCELLED", { });
|
throwError("cancelled", "CANCELLED", { });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,7 +251,7 @@ export class FetchRequest implements Iterable<[ key: string, value: string ]> {
|
|||||||
}
|
}
|
||||||
setCredentials(username: string, password: string): void {
|
setCredentials(username: string, password: string): void {
|
||||||
if (username.match(/:/)) {
|
if (username.match(/:/)) {
|
||||||
logger.throwArgumentError("invalid basic authentication username", "username", "[REDACTED]");
|
throwArgumentError("invalid basic authentication username", "username", "[REDACTED]");
|
||||||
}
|
}
|
||||||
this.#creds = `${ username }:${ password }`;
|
this.#creds = `${ username }:${ password }`;
|
||||||
}
|
}
|
||||||
@ -319,7 +319,7 @@ export class FetchRequest implements Iterable<[ key: string, value: string ]> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (getTime() > expires) {
|
if (getTime() > expires) {
|
||||||
return logger.throwError("timeout", "TIMEOUT", {
|
return throwError("timeout", "TIMEOUT", {
|
||||||
operation: "request.send", reason: "timeout", request: _request
|
operation: "request.send", reason: "timeout", request: _request
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -409,7 +409,7 @@ export class FetchRequest implements Iterable<[ key: string, value: string ]> {
|
|||||||
|
|
||||||
send(): Promise<FetchResponse> {
|
send(): Promise<FetchResponse> {
|
||||||
if (this.#signal != null) {
|
if (this.#signal != null) {
|
||||||
return logger.throwError("request already sent", "UNSUPPORTED_OPERATION", { operation: "fetchRequest.send" });
|
return throwError("request already sent", "UNSUPPORTED_OPERATION", { operation: "fetchRequest.send" });
|
||||||
}
|
}
|
||||||
this.#signal = new FetchCancelSignal(this);
|
this.#signal = new FetchCancelSignal(this);
|
||||||
return this.#send(0, getTime() + this.timeout, 0, this, new FetchResponse(0, "", { }, null, this));
|
return this.#send(0, getTime() + this.timeout, 0, this, new FetchResponse(0, "", { }, null, this));
|
||||||
@ -417,7 +417,7 @@ export class FetchRequest implements Iterable<[ key: string, value: string ]> {
|
|||||||
|
|
||||||
cancel(): void {
|
cancel(): void {
|
||||||
if (this.#signal == null) {
|
if (this.#signal == null) {
|
||||||
return logger.throwError("request has not been sent", "UNSUPPORTED_OPERATION", { operation: "fetchRequest.cancel" });
|
return throwError("request has not been sent", "UNSUPPORTED_OPERATION", { operation: "fetchRequest.cancel" });
|
||||||
}
|
}
|
||||||
const signal = fetchSignals.get(this);
|
const signal = fetchSignals.get(this);
|
||||||
if (!signal) { throw new Error("missing signal; should not happen"); }
|
if (!signal) { throw new Error("missing signal; should not happen"); }
|
||||||
@ -438,7 +438,7 @@ export class FetchRequest implements Iterable<[ key: string, value: string ]> {
|
|||||||
// - downgrading the security (e.g. https => http)
|
// - downgrading the security (e.g. https => http)
|
||||||
// - to non-HTTP (or non-HTTPS) protocols [this could be relaxed?]
|
// - to non-HTTP (or non-HTTPS) protocols [this could be relaxed?]
|
||||||
if (this.method !== "GET" || (current === "https" && target === "http") || !location.match(/^https?:/)) {
|
if (this.method !== "GET" || (current === "https" && target === "http") || !location.match(/^https?:/)) {
|
||||||
return logger.throwError(`unsupported redirect`, "UNSUPPORTED_OPERATION", {
|
return throwError(`unsupported redirect`, "UNSUPPORTED_OPERATION", {
|
||||||
operation: `redirect(${ this.method } ${ JSON.stringify(this.url) } => ${ JSON.stringify(location) })`
|
operation: `redirect(${ this.method } ${ JSON.stringify(this.url) } => ${ JSON.stringify(location) })`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -536,7 +536,7 @@ export class FetchResponse implements Iterable<[ key: string, value: string ]> {
|
|||||||
|
|
||||||
get statusCode(): number { return this.#statusCode; }
|
get statusCode(): number { return this.#statusCode; }
|
||||||
get statusMessage(): string { return this.#statusMessage; }
|
get statusMessage(): string { return this.#statusMessage; }
|
||||||
get headers() { return this.#headers; }
|
get headers(): Record<string, string> { return this.#headers; }
|
||||||
get body(): null | Readonly<Uint8Array> {
|
get body(): null | Readonly<Uint8Array> {
|
||||||
return (this.#body == null) ? null: new Uint8Array(this.#body);
|
return (this.#body == null) ? null: new Uint8Array(this.#body);
|
||||||
}
|
}
|
||||||
@ -544,7 +544,7 @@ export class FetchResponse implements Iterable<[ key: string, value: string ]> {
|
|||||||
try {
|
try {
|
||||||
return (this.#body == null) ? "": toUtf8String(this.#body);
|
return (this.#body == null) ? "": toUtf8String(this.#body);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return logger.throwError("response body is not valid UTF-8 data", "UNSUPPORTED_OPERATION", {
|
return throwError("response body is not valid UTF-8 data", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "bodyText", info: { response: this }
|
operation: "bodyText", info: { response: this }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -553,7 +553,7 @@ export class FetchResponse implements Iterable<[ key: string, value: string ]> {
|
|||||||
try {
|
try {
|
||||||
return JSON.parse(this.bodyText);
|
return JSON.parse(this.bodyText);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return logger.throwError("response body is not valid JSON", "UNSUPPORTED_OPERATION", {
|
return throwError("response body is not valid JSON", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "bodyJson", info: { response: this }
|
operation: "bodyJson", info: { response: this }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -607,7 +607,7 @@ export class FetchResponse implements Iterable<[ key: string, value: string ]> {
|
|||||||
if (stall == null) {
|
if (stall == null) {
|
||||||
stall = -1;
|
stall = -1;
|
||||||
} else if (typeof(stall) !== "number" || !Number.isInteger(stall) || stall < 0) {
|
} else if (typeof(stall) !== "number" || !Number.isInteger(stall) || stall < 0) {
|
||||||
return logger.throwArgumentError("invalid stall timeout", "stall", stall);
|
return throwArgumentError("invalid stall timeout", "stall", stall);
|
||||||
}
|
}
|
||||||
|
|
||||||
const error = new Error(message || "throttling requests");
|
const error = new Error(message || "throttling requests");
|
||||||
@ -637,7 +637,7 @@ export class FetchResponse implements Iterable<[ key: string, value: string ]> {
|
|||||||
if (message === "") {
|
if (message === "") {
|
||||||
message = `server response ${ this.statusCode } ${ this.statusMessage }`;
|
message = `server response ${ this.statusCode } ${ this.statusMessage }`;
|
||||||
}
|
}
|
||||||
logger.throwError(message, "SERVER_ERROR", {
|
throwError(message, "SERVER_ERROR", {
|
||||||
request: (this.request || "unknown request"), response: this, error
|
request: (this.request || "unknown request"), response: this, error
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { logger } from "./logger.js";
|
import { getBytes } from "./data.js";
|
||||||
import { fromTwos, toBigInt, toHex, toTwos } from "./maths.js";
|
import { throwArgumentError, throwError } from "./errors.js";
|
||||||
|
import { getBigInt, getNumber, fromTwos, toBigInt, toHex, toTwos } from "./maths.js";
|
||||||
|
|
||||||
import type { BigNumberish, BytesLike, Numeric } from "./index.js";
|
import type { BigNumberish, BytesLike, Numeric } from "./index.js";
|
||||||
|
|
||||||
@ -11,7 +12,7 @@ const NegativeOne = BigInt(-1);
|
|||||||
function throwFault(message: string, fault: string, operation: string, value?: any): never {
|
function throwFault(message: string, fault: string, operation: string, value?: any): never {
|
||||||
const params: any = { fault: fault, operation: operation };
|
const params: any = { fault: fault, operation: operation };
|
||||||
if (value !== undefined) { params.value = value; }
|
if (value !== undefined) { params.value = value; }
|
||||||
return logger.throwError(message, "NUMERIC_FAULT", params);
|
return throwError(message, "NUMERIC_FAULT", params);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constant to pull zeros from for multipliers
|
// Constant to pull zeros from for multipliers
|
||||||
@ -22,7 +23,7 @@ while (zeros.length < 256) { zeros += zeros; }
|
|||||||
function getMultiplier(decimals: number): bigint {
|
function getMultiplier(decimals: number): bigint {
|
||||||
|
|
||||||
if (typeof(decimals) !== "number" || decimals < 0 || decimals > 256 || decimals % 1 ) {
|
if (typeof(decimals) !== "number" || decimals < 0 || decimals > 256 || decimals % 1 ) {
|
||||||
logger.throwArgumentError("invalid decimal length", "decimals", decimals);
|
throwArgumentError("invalid decimal length", "decimals", decimals);
|
||||||
}
|
}
|
||||||
|
|
||||||
return BigInt("1" + zeros.substring(0, decimals));
|
return BigInt("1" + zeros.substring(0, decimals));
|
||||||
@ -31,8 +32,8 @@ function getMultiplier(decimals: number): bigint {
|
|||||||
export function formatFixed(_value: BigNumberish, _decimals?: Numeric): string {
|
export function formatFixed(_value: BigNumberish, _decimals?: Numeric): string {
|
||||||
if (_decimals == null) { _decimals = 18; }
|
if (_decimals == null) { _decimals = 18; }
|
||||||
|
|
||||||
let value = logger.getBigInt(_value, "value");
|
let value = getBigInt(_value, "value");
|
||||||
const decimals = logger.getNumber(_decimals, "decimals");
|
const decimals = getNumber(_decimals, "decimals");
|
||||||
|
|
||||||
const multiplier = getMultiplier(decimals);
|
const multiplier = getMultiplier(decimals);
|
||||||
const multiplierStr = String(multiplier);
|
const multiplierStr = String(multiplier);
|
||||||
@ -60,12 +61,12 @@ export function formatFixed(_value: BigNumberish, _decimals?: Numeric): string {
|
|||||||
|
|
||||||
export function parseFixed(value: string, _decimals: Numeric): bigint {
|
export function parseFixed(value: string, _decimals: Numeric): bigint {
|
||||||
if (_decimals == null) { _decimals = 18; }
|
if (_decimals == null) { _decimals = 18; }
|
||||||
const decimals = logger.getNumber(_decimals, "decimals");
|
const decimals = getNumber(_decimals, "decimals");
|
||||||
|
|
||||||
const multiplier = getMultiplier(decimals);
|
const multiplier = getMultiplier(decimals);
|
||||||
|
|
||||||
if (typeof(value) !== "string" || !value.match(/^-?[0-9.]+$/)) {
|
if (typeof(value) !== "string" || !value.match(/^-?[0-9.]+$/)) {
|
||||||
logger.throwArgumentError("invalid decimal value", "value", value);
|
throwArgumentError("invalid decimal value", "value", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is it negative?
|
// Is it negative?
|
||||||
@ -73,13 +74,13 @@ export function parseFixed(value: string, _decimals: Numeric): bigint {
|
|||||||
if (negative) { value = value.substring(1); }
|
if (negative) { value = value.substring(1); }
|
||||||
|
|
||||||
if (value === ".") {
|
if (value === ".") {
|
||||||
logger.throwArgumentError("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) {
|
if (comps.length > 2) {
|
||||||
logger.throwArgumentError("too many decimal points", "value", value);
|
throwArgumentError("too many decimal points", "value", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
let whole = (comps[0] || "0"), fraction = (comps[1] || "0");
|
let whole = (comps[0] || "0"), fraction = (comps[1] || "0");
|
||||||
@ -110,7 +111,6 @@ export function parseFixed(value: string, _decimals: Numeric): bigint {
|
|||||||
return wei;
|
return wei;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export class FixedFormat {
|
export class FixedFormat {
|
||||||
readonly signed: boolean;
|
readonly signed: boolean;
|
||||||
readonly width: number;
|
readonly width: number;
|
||||||
@ -121,7 +121,7 @@ export class FixedFormat {
|
|||||||
|
|
||||||
constructor(constructorGuard: any, signed: boolean, width: number, decimals: number) {
|
constructor(constructorGuard: any, signed: boolean, width: number, decimals: number) {
|
||||||
if (constructorGuard !== _constructorGuard) {
|
if (constructorGuard !== _constructorGuard) {
|
||||||
logger.throwError("cannot use FixedFormat constructor; use FixedFormat.from", "UNSUPPORTED_OPERATION", {
|
throwError("cannot use FixedFormat constructor; use FixedFormat.from", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "new FixedFormat"
|
operation: "new FixedFormat"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -156,7 +156,7 @@ export class FixedFormat {
|
|||||||
} 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) {
|
if (!match) {
|
||||||
return logger.throwArgumentError("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]);
|
||||||
@ -166,7 +166,7 @@ export class FixedFormat {
|
|||||||
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) {
|
if (typeof(value[key]) !== type) {
|
||||||
logger.throwArgumentError("invalid fixed format (" + key + " not " + type +")", "format." + key, value[key]);
|
throwArgumentError("invalid fixed format (" + key + " not " + type +")", "format." + key, value[key]);
|
||||||
}
|
}
|
||||||
return value[key];
|
return value[key];
|
||||||
}
|
}
|
||||||
@ -176,17 +176,20 @@ export class FixedFormat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (width % 8) {
|
if (width % 8) {
|
||||||
logger.throwArgumentError("invalid fixed format width (not byte aligned)", "format.width", width);
|
throwArgumentError("invalid fixed format width (not byte aligned)", "format.width", width);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (decimals > 80) {
|
if (decimals > 80) {
|
||||||
logger.throwArgumentError("invalid fixed format (decimals too large)", "format.decimals", decimals);
|
throwArgumentError("invalid fixed format (decimals too large)", "format.decimals", decimals);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new FixedFormat(_constructorGuard, signed, width, decimals);
|
return new FixedFormat(_constructorGuard, signed, width, decimals);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fixed Number class
|
||||||
|
*/
|
||||||
export class FixedNumber {
|
export class FixedNumber {
|
||||||
readonly format: FixedFormat;
|
readonly format: FixedFormat;
|
||||||
|
|
||||||
@ -197,7 +200,7 @@ export class FixedNumber {
|
|||||||
|
|
||||||
constructor(constructorGuard: any, hex: string, value: string, format?: FixedFormat) {
|
constructor(constructorGuard: any, hex: string, value: string, format?: FixedFormat) {
|
||||||
if (constructorGuard !== _constructorGuard) {
|
if (constructorGuard !== _constructorGuard) {
|
||||||
logger.throwError("cannot use FixedNumber constructor; use FixedNumber.from", "UNSUPPORTED_OPERATION", {
|
throwError("cannot use FixedNumber constructor; use FixedNumber.from", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "new FixedFormat"
|
operation: "new FixedFormat"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -213,10 +216,14 @@ export class FixedNumber {
|
|||||||
|
|
||||||
#checkFormat(other: FixedNumber): void {
|
#checkFormat(other: FixedNumber): void {
|
||||||
if (this.format.name !== other.format.name) {
|
if (this.format.name !== other.format.name) {
|
||||||
logger.throwArgumentError("incompatible format; use fixedNumber.toFormat", "other", other);
|
throwArgumentError("incompatible format; use fixedNumber.toFormat", "other", other);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new [[FixedNumber]] with the result of this added
|
||||||
|
* to %%other%%.
|
||||||
|
*/
|
||||||
addUnsafe(other: FixedNumber): FixedNumber {
|
addUnsafe(other: FixedNumber): FixedNumber {
|
||||||
this.#checkFormat(other);
|
this.#checkFormat(other);
|
||||||
const a = parseFixed(this.#value, this.format.decimals);
|
const a = parseFixed(this.#value, this.format.decimals);
|
||||||
@ -282,7 +289,7 @@ export class FixedNumber {
|
|||||||
if (comps.length === 1) { comps.push("0"); }
|
if (comps.length === 1) { comps.push("0"); }
|
||||||
|
|
||||||
if (decimals < 0 || decimals > 80 || (decimals % 1)) {
|
if (decimals < 0 || decimals > 80 || (decimals % 1)) {
|
||||||
logger.throwArgumentError("invalid decimal count", "decimals", decimals);
|
throwArgumentError("invalid decimal count", "decimals", decimals);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (comps[1].length <= decimals) { return this; }
|
if (comps[1].length <= decimals) { return this; }
|
||||||
@ -324,7 +331,7 @@ export class FixedNumber {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static fromValue(value: BigNumberish, decimals = 0, format: FixedFormat | string | number = "fixed"): FixedNumber {
|
static fromValue(value: BigNumberish, decimals: number = 0, format: FixedFormat | string | number = "fixed"): FixedNumber {
|
||||||
return FixedNumber.fromString(formatFixed(value, decimals), FixedFormat.from(format));
|
return FixedNumber.fromString(formatFixed(value, decimals), FixedFormat.from(format));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -350,7 +357,7 @@ export class FixedNumber {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static fromBytes(_value: BytesLike, format: FixedFormat | string | number = "fixed"): FixedNumber {
|
static fromBytes(_value: BytesLike, format: FixedFormat | string | number = "fixed"): FixedNumber {
|
||||||
const value = logger.getBytes(_value, "value");
|
const value = getBytes(_value, "value");
|
||||||
const fixedFormat = FixedFormat.from(format);
|
const fixedFormat = FixedFormat.from(format);
|
||||||
|
|
||||||
if (value.length > fixedFormat.width / 8) {
|
if (value.length > fixedFormat.width / 8) {
|
||||||
@ -366,7 +373,7 @@ export class FixedNumber {
|
|||||||
return new FixedNumber(_constructorGuard, hex, decimal, fixedFormat);
|
return new FixedNumber(_constructorGuard, hex, decimal, fixedFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
static from(value: any, format?: FixedFormat | string | number) {
|
static from(value: any, format?: FixedFormat | string | number): FixedNumber {
|
||||||
if (typeof(value) === "string") {
|
if (typeof(value) === "string") {
|
||||||
return FixedNumber.fromString(value, format);
|
return FixedNumber.fromString(value, format);
|
||||||
}
|
}
|
||||||
@ -384,7 +391,7 @@ export class FixedNumber {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return logger.throwArgumentError("invalid FixedNumber value", "value", value);
|
return throwArgumentError("invalid FixedNumber value", "value", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static isFixedNumber(value: any): value is FixedNumber {
|
static isFixedNumber(value: any): value is FixedNumber {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { logger } from "./logger.js";
|
import { throwError } from "./errors.js";
|
||||||
|
|
||||||
import type { FetchRequest, FetchCancelSignal, GetUrlResponse } from "./fetch.js";
|
import type { FetchRequest, FetchCancelSignal, GetUrlResponse } from "./fetch.js";
|
||||||
|
|
||||||
@ -31,14 +31,14 @@ export async function getUrl(req: FetchRequest, _signal?: FetchCancelSignal): Pr
|
|||||||
const protocol = req.url.split(":")[0].toLowerCase();
|
const protocol = req.url.split(":")[0].toLowerCase();
|
||||||
|
|
||||||
if (protocol !== "http" && protocol !== "https") {
|
if (protocol !== "http" && protocol !== "https") {
|
||||||
logger.throwError(`unsupported protocol ${ protocol }`, "UNSUPPORTED_OPERATION", {
|
throwError(`unsupported protocol ${ protocol }`, "UNSUPPORTED_OPERATION", {
|
||||||
info: { protocol },
|
info: { protocol },
|
||||||
operation: "request"
|
operation: "request"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.credentials && !req.allowInsecureAuthentication) {
|
if (req.credentials && !req.allowInsecureAuthentication) {
|
||||||
logger.throwError("insecure authorized connections unsupported", "UNSUPPORTED_OPERATION", {
|
throwError("insecure authorized connections unsupported", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "request"
|
operation: "request"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,8 @@ import http from "http";
|
|||||||
import https from "https";
|
import https from "https";
|
||||||
import { gunzipSync } from "zlib";
|
import { gunzipSync } from "zlib";
|
||||||
|
|
||||||
import { logger } from "./logger.js";
|
import { throwError } from "./errors.js";
|
||||||
|
import { getBytes } from "./data.js";
|
||||||
|
|
||||||
import type { FetchRequest, FetchCancelSignal, GetUrlResponse } from "./fetch.js";
|
import type { FetchRequest, FetchCancelSignal, GetUrlResponse } from "./fetch.js";
|
||||||
|
|
||||||
@ -12,14 +13,14 @@ export async function getUrl(req: FetchRequest, signal?: FetchCancelSignal): Pro
|
|||||||
const protocol = req.url.split(":")[0].toLowerCase();
|
const protocol = req.url.split(":")[0].toLowerCase();
|
||||||
|
|
||||||
if (protocol !== "http" && protocol !== "https") {
|
if (protocol !== "http" && protocol !== "https") {
|
||||||
logger.throwError(`unsupported protocol ${ protocol }`, "UNSUPPORTED_OPERATION", {
|
throwError(`unsupported protocol ${ protocol }`, "UNSUPPORTED_OPERATION", {
|
||||||
info: { protocol },
|
info: { protocol },
|
||||||
operation: "request"
|
operation: "request"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.credentials && !req.allowInsecureAuthentication) {
|
if (req.credentials && !req.allowInsecureAuthentication) {
|
||||||
logger.throwError("insecure authorized connections unsupported", "UNSUPPORTED_OPERATION", {
|
throwError("insecure authorized connections unsupported", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "request"
|
operation: "request"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -78,7 +79,7 @@ export async function getUrl(req: FetchRequest, signal?: FetchCancelSignal): Pro
|
|||||||
|
|
||||||
resp.on("end", () => {
|
resp.on("end", () => {
|
||||||
if (headers["content-encoding"] === "gzip" && body) {
|
if (headers["content-encoding"] === "gzip" && body) {
|
||||||
body = logger.getBytes(gunzipSync(body));
|
body = getBytes(gunzipSync(body));
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve({ statusCode, statusMessage, headers, body });
|
resolve({ statusCode, statusMessage, headers, body });
|
||||||
|
@ -19,11 +19,15 @@ export { decodeBase58, encodeBase58 } from "./base58.js";
|
|||||||
export { decodeBase64, encodeBase64 } from "./base64.js";
|
export { decodeBase64, encodeBase64 } from "./base64.js";
|
||||||
|
|
||||||
export {
|
export {
|
||||||
isHexString, isBytesLike, hexlify, concat, dataLength, dataSlice,
|
getBytes, getBytesCopy, isHexString, isBytesLike, hexlify, concat, dataLength, dataSlice,
|
||||||
stripZerosLeft, zeroPadValue, zeroPadBytes
|
stripZerosLeft, zeroPadValue, zeroPadBytes
|
||||||
} from "./data.js";
|
} from "./data.js";
|
||||||
|
|
||||||
export { isCallException, isError } from "./errors.js"
|
export {
|
||||||
|
isCallException, isError,
|
||||||
|
makeError, throwError, throwArgumentError,
|
||||||
|
assertArgument, assertArgumentCount, assertPrivate, assertNormalize
|
||||||
|
} from "./errors.js"
|
||||||
|
|
||||||
export { EventPayload } from "./events.js";
|
export { EventPayload } from "./events.js";
|
||||||
|
|
||||||
@ -31,11 +35,9 @@ export { FetchRequest, FetchResponse } from "./fetch.js";
|
|||||||
|
|
||||||
export { FixedFormat, FixedNumber, formatFixed, parseFixed } from "./fixednumber.js"
|
export { FixedFormat, FixedNumber, formatFixed, parseFixed } from "./fixednumber.js"
|
||||||
|
|
||||||
export { assertArgument, Logger, logger } from "./logger.js";
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
fromTwos, toTwos, mask,
|
fromTwos, toTwos, mask,
|
||||||
toBigInt, toNumber, toHex, toArray, toQuantity
|
getBigInt, getNumber, toBigInt, toNumber, toHex, toArray, toQuantity
|
||||||
} from "./maths.js";
|
} from "./maths.js";
|
||||||
|
|
||||||
export { resolveProperties, defineReadOnly, defineProperties} from "./properties.js";
|
export { resolveProperties, defineReadOnly, defineProperties} from "./properties.js";
|
||||||
|
@ -1,36 +1,13 @@
|
|||||||
|
/*
|
||||||
import { version } from "../_version.js";
|
import { version } from "../_version.js";
|
||||||
|
|
||||||
import type { BigNumberish, BytesLike } from "./index.js";
|
import { throwArgumentError } from "./errors.js";
|
||||||
|
|
||||||
import type { CodedEthersError, ErrorCode } from "./errors.js";
|
|
||||||
|
|
||||||
|
|
||||||
export type ErrorInfo<T> = Omit<T, "code" | "name" | "message">;
|
|
||||||
|
|
||||||
export type LogLevel = "debug" | "info" | "warning" | "error" | "off";
|
export type LogLevel = "debug" | "info" | "warning" | "error" | "off";
|
||||||
|
|
||||||
const LogLevels: Array<LogLevel> = [ "debug", "info", "warning", "error", "off" ];
|
const LogLevels: Array<LogLevel> = [ "debug", "info", "warning", "error", "off" ];
|
||||||
|
|
||||||
const _normalizeForms = ["NFD", "NFC", "NFKD", "NFKC"].reduce((accum, form) => {
|
|
||||||
try {
|
|
||||||
// General test for normalize
|
|
||||||
/* c8 ignore start */
|
|
||||||
if ("test".normalize(form) !== "test") { throw new Error("bad"); };
|
|
||||||
/* c8 ignore stop */
|
|
||||||
|
|
||||||
if (form === "NFD") {
|
|
||||||
const check = String.fromCharCode(0xe9).normalize("NFD");
|
|
||||||
const expected = String.fromCharCode(0x65, 0x0301)
|
|
||||||
/* c8 ignore start */
|
|
||||||
if (check !== expected) { throw new Error("broken") }
|
|
||||||
/* c8 ignore stop */
|
|
||||||
}
|
|
||||||
|
|
||||||
accum.push(form);
|
|
||||||
} catch(error) { }
|
|
||||||
|
|
||||||
return accum;
|
|
||||||
}, <Array<string>>[]);
|
|
||||||
|
|
||||||
function defineReadOnly<T, P extends keyof T>(object: T, name: P, value: T[P]): void {
|
function defineReadOnly<T, P extends keyof T>(object: T, name: P, value: T[P]): void {
|
||||||
Object.defineProperty(object, name, {
|
Object.defineProperty(object, name, {
|
||||||
@ -38,15 +15,6 @@ function defineReadOnly<T, P extends keyof T>(object: T, name: P, value: T[P]):
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// IEEE 754 support 53-bits of mantissa
|
|
||||||
const maxValue = 0x1fffffffffffff;
|
|
||||||
|
|
||||||
// The type of error to use for various error codes
|
|
||||||
const ErrorConstructors: Record<string, { new (...args: Array<any>): Error }> = { };
|
|
||||||
ErrorConstructors.INVALID_ARGUMENT = TypeError;
|
|
||||||
ErrorConstructors.NUMERIC_FAULT = RangeError;
|
|
||||||
ErrorConstructors.BUFFER_OVERRUN = RangeError;
|
|
||||||
|
|
||||||
export type AssertFunc<T> = () => (undefined | T);
|
export type AssertFunc<T> = () => (undefined | T);
|
||||||
|
|
||||||
export class Logger {
|
export class Logger {
|
||||||
@ -66,168 +34,15 @@ export class Logger {
|
|||||||
set logLevel(value: LogLevel) {
|
set logLevel(value: LogLevel) {
|
||||||
const logLevel = LogLevels.indexOf(value);
|
const logLevel = LogLevels.indexOf(value);
|
||||||
if (logLevel == null) {
|
if (logLevel == null) {
|
||||||
this.throwArgumentError("invalid logLevel", "logLevel", value);
|
throwArgumentError("invalid logLevel", "logLevel", value);
|
||||||
}
|
}
|
||||||
this.#logLevel = logLevel;
|
this.#logLevel = logLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
makeError<K extends ErrorCode, T extends CodedEthersError<K>>(message: string, code: K, info?: ErrorInfo<T>): T {
|
|
||||||
{
|
|
||||||
const details: Array<string> = [];
|
|
||||||
if (info) {
|
|
||||||
for (const key in info) {
|
|
||||||
const value = <any>(info[<keyof ErrorInfo<T>>key]);
|
|
||||||
try {
|
|
||||||
details.push(key + "=" + JSON.stringify(value));
|
|
||||||
} catch (error) {
|
|
||||||
details.push(key + "=[could not serialize object]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
details.push(`code=${ code }`);
|
|
||||||
details.push(`version=${ this.version }`);
|
|
||||||
|
|
||||||
if (details.length) {
|
|
||||||
message += " (" + details.join(", ") + ")";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const create = ErrorConstructors[code] || Error;
|
|
||||||
const error = <T>(new create(message));
|
|
||||||
defineReadOnly(error, "code", code);
|
|
||||||
if (info) {
|
|
||||||
for (const key in info) {
|
|
||||||
defineReadOnly(error, <keyof T>key, <any>(info[<keyof ErrorInfo<T>>key]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return <T>error;
|
|
||||||
}
|
|
||||||
|
|
||||||
throwError<K extends ErrorCode, T extends CodedEthersError<K>>(message: string, code: K, info?: ErrorInfo<T>): never {
|
|
||||||
throw this.makeError(message, code, info);
|
|
||||||
}
|
|
||||||
|
|
||||||
throwArgumentError(message: string, name: string, value: any): never {
|
|
||||||
return this.throwError(message, "INVALID_ARGUMENT", {
|
|
||||||
argument: name,
|
|
||||||
value: value
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
assertNormalize(form: string): void {
|
|
||||||
if (_normalizeForms.indexOf(form) === -1) {
|
|
||||||
this.throwError("platform missing String.prototype.normalize", "UNSUPPORTED_OPERATION", {
|
|
||||||
operation: "String.prototype.normalize", info: { form }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assertPrivate(givenGuard: any, guard: any, className = ""): void {
|
|
||||||
if (givenGuard !== guard) {
|
|
||||||
let method = className, operation = "new";
|
|
||||||
if (className) {
|
|
||||||
method += ".";
|
|
||||||
operation += " " + className;
|
|
||||||
}
|
|
||||||
this.throwError(`private constructor; use ${ method }from* methods`, "UNSUPPORTED_OPERATION", {
|
|
||||||
operation
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assertArgumentCount(count: number, expectedCount: number, message: string = ""): void {
|
|
||||||
if (message) { message = ": " + message; }
|
|
||||||
|
|
||||||
if (count < expectedCount) {
|
|
||||||
this.throwError("missing arguemnt" + message, "MISSING_ARGUMENT", {
|
|
||||||
count: count,
|
|
||||||
expectedCount: expectedCount
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count > expectedCount) {
|
|
||||||
this.throwError("too many arguemnts" + message, "UNEXPECTED_ARGUMENT", {
|
|
||||||
count: count,
|
|
||||||
expectedCount: expectedCount
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#getBytes(value: BytesLike, name?: string, copy?: boolean): Uint8Array {
|
|
||||||
if (value instanceof Uint8Array) {
|
|
||||||
if (copy) { return new Uint8Array(value); }
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof(value) === "string" && value.match(/^0x([0-9a-f][0-9a-f])*$/i)) {
|
|
||||||
const result = new Uint8Array((value.length - 2) / 2);
|
|
||||||
let offset = 2;
|
|
||||||
for (let i = 0; i < result.length; i++) {
|
|
||||||
result[i] = parseInt(value.substring(offset, offset + 2), 16);
|
|
||||||
offset += 2;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.throwArgumentError("invalid BytesLike value", name || "value", value);
|
|
||||||
}
|
|
||||||
|
|
||||||
getBytes(value: BytesLike, name?: string): Uint8Array {
|
|
||||||
return this.#getBytes(value, name, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
getBytesCopy(value: BytesLike, name?: string): Uint8Array {
|
|
||||||
return this.#getBytes(value, name, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
getNumber(value: BigNumberish, name?: string): number {
|
|
||||||
switch (typeof(value)) {
|
|
||||||
case "bigint":
|
|
||||||
if (value < -maxValue || value > maxValue) {
|
|
||||||
this.throwArgumentError("overflow", name || "value", value);
|
|
||||||
}
|
|
||||||
return Number(value);
|
|
||||||
case "number":
|
|
||||||
if (!Number.isInteger(value)) {
|
|
||||||
this.throwArgumentError("underflow", name || "value", value);
|
|
||||||
} else if (value < -maxValue || value > maxValue) {
|
|
||||||
this.throwArgumentError("overflow", name || "value", value);
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
case "string":
|
|
||||||
try {
|
|
||||||
return this.getNumber(BigInt(value), name);
|
|
||||||
} catch(e: any) {
|
|
||||||
this.throwArgumentError(`invalid numeric string: ${ e.message }`, name || "value", value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this.throwArgumentError("invalid numeric value", name || "value", value);
|
|
||||||
}
|
|
||||||
|
|
||||||
getBigInt(value: BigNumberish, name?: string): bigint {
|
|
||||||
switch (typeof(value)) {
|
|
||||||
case "bigint": return value;
|
|
||||||
case "number":
|
|
||||||
if (!Number.isInteger(value)) {
|
|
||||||
this.throwArgumentError("underflow", name || "value", value);
|
|
||||||
} else if (value < -maxValue || value > maxValue) {
|
|
||||||
this.throwArgumentError("overflow", name || "value", value);
|
|
||||||
}
|
|
||||||
return BigInt(value);
|
|
||||||
case "string":
|
|
||||||
try {
|
|
||||||
return BigInt(value);
|
|
||||||
} catch(e: any) {
|
|
||||||
this.throwArgumentError(`invalid BigNumberish string: ${ e.message }`, name || "value", value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this.throwArgumentError("invalid BigNumberish value", name || "value", value);
|
|
||||||
}
|
|
||||||
|
|
||||||
#log(_logLevel: LogLevel, args: Array<any>): void {
|
#log(_logLevel: LogLevel, args: Array<any>): void {
|
||||||
const logLevel = LogLevels.indexOf(_logLevel);
|
const logLevel = LogLevels.indexOf(_logLevel);
|
||||||
if (logLevel === -1) {
|
if (logLevel === -1) {
|
||||||
this.throwArgumentError("invalid log level name", "logLevel", _logLevel);
|
throwArgumentError("invalid log level name", "logLevel", _logLevel);
|
||||||
}
|
}
|
||||||
if (this.#logLevel > logLevel) { return; }
|
if (this.#logLevel > logLevel) { return; }
|
||||||
console.log.apply(console, args);
|
console.log.apply(console, args);
|
||||||
@ -248,7 +63,5 @@ export class Logger {
|
|||||||
|
|
||||||
export const logger = new Logger(version);
|
export const logger = new Logger(version);
|
||||||
|
|
||||||
export function assertArgument(check: unknown, message: string, name: string, value: unknown): asserts check {
|
|
||||||
if (!check) { logger.throwArgumentError(message, name, value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { hexlify, isBytesLike } from "./data.js";
|
import { hexlify, isBytesLike } from "./data.js";
|
||||||
import { logger } from "./logger.js";
|
import { throwArgumentError } from "./errors.js";
|
||||||
|
|
||||||
import type { BytesLike } from "./data.js";
|
import type { BytesLike } from "./data.js";
|
||||||
|
|
||||||
@ -11,12 +11,15 @@ export type BigNumberish = string | Numeric;
|
|||||||
const BN_0 = BigInt(0);
|
const BN_0 = BigInt(0);
|
||||||
const BN_1 = BigInt(1);
|
const BN_1 = BigInt(1);
|
||||||
|
|
||||||
|
// IEEE 754 support 53-bits of mantissa
|
||||||
|
const maxValue = 0x1fffffffffffff;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert %%value%% from a twos-compliment value of %%width%% bits.
|
* Convert %%value%% from a twos-compliment value of %%width%% bits.
|
||||||
*/
|
*/
|
||||||
export function fromTwos(_value: BigNumberish, _width: Numeric): bigint {
|
export function fromTwos(_value: BigNumberish, _width: Numeric): bigint {
|
||||||
const value = logger.getBigInt(_value, "value");
|
const value = getBigInt(_value, "value");
|
||||||
const width = BigInt(logger.getNumber(_width, "width"));
|
const width = BigInt(getNumber(_width, "width"));
|
||||||
|
|
||||||
// Top bit set; treat as a negative value
|
// Top bit set; treat as a negative value
|
||||||
if (value >> (width - BN_1)) {
|
if (value >> (width - BN_1)) {
|
||||||
@ -31,8 +34,8 @@ export function fromTwos(_value: BigNumberish, _width: Numeric): bigint {
|
|||||||
* Convert %%value%% to a twos-compliment value of %%width%% bits.
|
* Convert %%value%% to a twos-compliment value of %%width%% bits.
|
||||||
*/
|
*/
|
||||||
export function toTwos(_value: BigNumberish, _width: Numeric): bigint {
|
export function toTwos(_value: BigNumberish, _width: Numeric): bigint {
|
||||||
const value = logger.getBigInt(_value, "value");
|
const value = getBigInt(_value, "value");
|
||||||
const width = BigInt(logger.getNumber(_width, "width"));
|
const width = BigInt(getNumber(_width, "width"));
|
||||||
|
|
||||||
if (value < BN_0) {
|
if (value < BN_0) {
|
||||||
const mask = (BN_1 << width) - BN_1;
|
const mask = (BN_1 << width) - BN_1;
|
||||||
@ -46,11 +49,30 @@ export function toTwos(_value: BigNumberish, _width: Numeric): bigint {
|
|||||||
* Mask %%value%% with a bitmask of %%bits%% ones.
|
* Mask %%value%% with a bitmask of %%bits%% ones.
|
||||||
*/
|
*/
|
||||||
export function mask(_value: BigNumberish, _bits: Numeric): bigint {
|
export function mask(_value: BigNumberish, _bits: Numeric): bigint {
|
||||||
const value = logger.getBigInt(_value, "value");
|
const value = getBigInt(_value, "value");
|
||||||
const bits = BigInt(logger.getNumber(_bits, "bits"));
|
const bits = BigInt(getNumber(_bits, "bits"));
|
||||||
return value & ((BN_1 << bits) - BN_1);
|
return value & ((BN_1 << bits) - BN_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getBigInt(value: BigNumberish, name?: string): bigint {
|
||||||
|
switch (typeof(value)) {
|
||||||
|
case "bigint": return value;
|
||||||
|
case "number":
|
||||||
|
if (!Number.isInteger(value)) {
|
||||||
|
throwArgumentError("underflow", name || "value", value);
|
||||||
|
} else if (value < -maxValue || value > maxValue) {
|
||||||
|
throwArgumentError("overflow", name || "value", value);
|
||||||
|
}
|
||||||
|
return BigInt(value);
|
||||||
|
case "string":
|
||||||
|
try {
|
||||||
|
return BigInt(value);
|
||||||
|
} catch(e: any) {
|
||||||
|
throwArgumentError(`invalid BigNumberish string: ${ e.message }`, name || "value", value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return throwArgumentError("invalid BigNumberish value", name || "value", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -68,15 +90,40 @@ export function toBigInt(value: BigNumberish | Uint8Array): bigint {
|
|||||||
return BigInt(result);
|
return BigInt(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return logger.getBigInt(value);
|
return getBigInt(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getNumber(value: BigNumberish, name?: string): number {
|
||||||
|
switch (typeof(value)) {
|
||||||
|
case "bigint":
|
||||||
|
if (value < -maxValue || value > maxValue) {
|
||||||
|
throwArgumentError("overflow", name || "value", value);
|
||||||
|
}
|
||||||
|
return Number(value);
|
||||||
|
case "number":
|
||||||
|
if (!Number.isInteger(value)) {
|
||||||
|
throwArgumentError("underflow", name || "value", value);
|
||||||
|
} else if (value < -maxValue || value > maxValue) {
|
||||||
|
throwArgumentError("overflow", name || "value", value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
case "string":
|
||||||
|
try {
|
||||||
|
return getNumber(BigInt(value), name);
|
||||||
|
} catch(e: any) {
|
||||||
|
throwArgumentError(`invalid numeric string: ${ e.message }`, name || "value", value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return throwArgumentError("invalid numeric value", name || "value", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Converts %%value%% to a number. If %%value%% is a Uint8Array, it
|
* Converts %%value%% to a number. If %%value%% is a Uint8Array, it
|
||||||
* is treated as Big Endian data. Throws if the value is not safe.
|
* is treated as Big Endian data. Throws if the value is not safe.
|
||||||
*/
|
*/
|
||||||
export function toNumber(value: BigNumberish | Uint8Array): number {
|
export function toNumber(value: BigNumberish | Uint8Array): number {
|
||||||
return logger.getNumber(toBigInt(value));
|
return getNumber(toBigInt(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -85,7 +132,7 @@ export function toNumber(value: BigNumberish | Uint8Array): number {
|
|||||||
*/
|
*/
|
||||||
// Converts value to hex, optionally padding on the left to width bytes
|
// Converts value to hex, optionally padding on the left to width bytes
|
||||||
export function toHex(_value: BigNumberish, _width?: Numeric): string {
|
export function toHex(_value: BigNumberish, _width?: Numeric): string {
|
||||||
const value = logger.getBigInt(_value, "value");
|
const value = getBigInt(_value, "value");
|
||||||
if (value < 0) { throw new Error("cannot convert negative value to hex"); }
|
if (value < 0) { throw new Error("cannot convert negative value to hex"); }
|
||||||
|
|
||||||
let result = value.toString(16);
|
let result = value.toString(16);
|
||||||
@ -94,7 +141,7 @@ export function toHex(_value: BigNumberish, _width?: Numeric): string {
|
|||||||
// Ensure the value is of even length
|
// Ensure the value is of even length
|
||||||
if (result.length % 2) { result = "0" + result; }
|
if (result.length % 2) { result = "0" + result; }
|
||||||
} else {
|
} else {
|
||||||
const width = logger.getNumber(_width, "width");
|
const width = getNumber(_width, "width");
|
||||||
if (width * 2 < result.length) { throw new Error(`value ${ value } exceeds width ${ width }`); }
|
if (width * 2 < result.length) { throw new Error(`value ${ value } exceeds width ${ width }`); }
|
||||||
|
|
||||||
// Pad the value to the required width
|
// Pad the value to the required width
|
||||||
@ -109,7 +156,7 @@ export function toHex(_value: BigNumberish, _width?: Numeric): string {
|
|||||||
* Converts %%value%% to a Big Endian Uint8Array.
|
* Converts %%value%% to a Big Endian Uint8Array.
|
||||||
*/
|
*/
|
||||||
export function toArray(_value: BigNumberish): Uint8Array {
|
export function toArray(_value: BigNumberish): Uint8Array {
|
||||||
const value = logger.getBigInt(_value, "value");
|
const value = getBigInt(_value, "value");
|
||||||
if (value < 0) { throw new Error("cannot convert negative value to hex"); }
|
if (value < 0) { throw new Error("cannot convert negative value to hex"); }
|
||||||
|
|
||||||
if (value === BN_0) { return new Uint8Array([ ]); }
|
if (value === BN_0) { return new Uint8Array([ ]); }
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
//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 { logger } from "./logger.js";
|
import { throwArgumentError, throwError } from "./errors.js";
|
||||||
|
import { getBytes } from "./data.js";
|
||||||
|
|
||||||
import type { BytesLike, RlpStructuredData } from "./index.js";
|
import type { BytesLike, RlpStructuredData } from "./index.js";
|
||||||
|
|
||||||
@ -35,7 +36,7 @@ function _decodeChildren(data: Uint8Array, offset: number, childOffset: number,
|
|||||||
|
|
||||||
childOffset += decoded.consumed;
|
childOffset += decoded.consumed;
|
||||||
if (childOffset > offset + 1 + length) {
|
if (childOffset > offset + 1 + length) {
|
||||||
logger.throwError("child data too short", "BUFFER_OVERRUN", {
|
throwError("child data too short", "BUFFER_OVERRUN", {
|
||||||
buffer: data, length, offset
|
buffer: data, length, offset
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -47,14 +48,14 @@ function _decodeChildren(data: Uint8Array, offset: number, childOffset: number,
|
|||||||
// returns { consumed: number, result: Object }
|
// returns { consumed: number, result: Object }
|
||||||
function _decode(data: Uint8Array, offset: number): { consumed: number, result: any } {
|
function _decode(data: Uint8Array, offset: number): { consumed: number, result: any } {
|
||||||
if (data.length === 0) {
|
if (data.length === 0) {
|
||||||
logger.throwError("data too short", "BUFFER_OVERRUN", {
|
throwError("data too short", "BUFFER_OVERRUN", {
|
||||||
buffer: data, length: 0, offset: 1
|
buffer: data, length: 0, offset: 1
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const checkOffset = (offset: number) => {
|
const checkOffset = (offset: number) => {
|
||||||
if (offset > data.length) {
|
if (offset > data.length) {
|
||||||
logger.throwError("data short segment too short", "BUFFER_OVERRUN", {
|
throwError("data short segment too short", "BUFFER_OVERRUN", {
|
||||||
buffer: data, length: data.length, offset
|
buffer: data, length: data.length, offset
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -98,10 +99,10 @@ function _decode(data: Uint8Array, offset: number): { consumed: number, result:
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function decodeRlp(_data: BytesLike): RlpStructuredData {
|
export function decodeRlp(_data: BytesLike): RlpStructuredData {
|
||||||
const data = logger.getBytes(_data, "data");
|
const data = getBytes(_data, "data");
|
||||||
const decoded = _decode(data, 0);
|
const decoded = _decode(data, 0);
|
||||||
if (decoded.consumed !== data.length) {
|
if (decoded.consumed !== data.length) {
|
||||||
logger.throwArgumentError("unexpected junk after rlp payload", "data", _data);
|
throwArgumentError("unexpected junk after rlp payload", "data", _data);
|
||||||
}
|
}
|
||||||
return decoded.result;
|
return decoded.result;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//See: https://github.com/ethereum/wiki/wiki/RLP
|
//See: https://github.com/ethereum/wiki/wiki/RLP
|
||||||
|
|
||||||
import { logger } from "./logger.js";
|
import { getBytes } from "./data.js";
|
||||||
|
|
||||||
import type { RlpStructuredData } from "./rlp.js";
|
import type { RlpStructuredData } from "./rlp.js";
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ function _encode(object: Array<any> | string): Array<number> {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const data: Array<number> = Array.prototype.slice.call(logger.getBytes(object, "object"));
|
const data: Array<number> = Array.prototype.slice.call(getBytes(object, "object"));
|
||||||
|
|
||||||
if (data.length === 1 && data[0] <= 0x7f) {
|
if (data.length === 1 && data[0] <= 0x7f) {
|
||||||
return data;
|
return data;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { formatFixed, parseFixed } from "./fixednumber.js";
|
import { formatFixed, parseFixed } from "./fixednumber.js";
|
||||||
import { logger } from "./logger.js";
|
import { throwArgumentError } 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) { logger.throwArgumentError("invalid unit", "unit", unit); }
|
if (index === -1) { throwArgumentError("invalid unit", "unit", unit); }
|
||||||
unit = 3 * index;
|
unit = 3 * index;
|
||||||
}
|
}
|
||||||
return formatFixed(value, (unit != null) ? unit: 18);
|
return formatFixed(value, (unit != null) ? unit: 18);
|
||||||
@ -36,12 +36,12 @@ export function formatUnits(value: BigNumberish, unit?: string | Numeric): strin
|
|||||||
*/
|
*/
|
||||||
export function parseUnits(value: string, unit?: string | Numeric): bigint {
|
export function parseUnits(value: string, unit?: string | Numeric): bigint {
|
||||||
if (typeof(value) !== "string") {
|
if (typeof(value) !== "string") {
|
||||||
logger.throwArgumentError("value must be a string", "value", value);
|
throwArgumentError("value must be a string", "value", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof(unit) === "string") {
|
if (typeof(unit) === "string") {
|
||||||
const index = names.indexOf(unit);
|
const index = names.indexOf(unit);
|
||||||
if (index === -1) { logger.throwArgumentError("invalid unit", "unit", unit); }
|
if (index === -1) { throwArgumentError("invalid unit", "unit", unit); }
|
||||||
unit = 3 * index;
|
unit = 3 * index;
|
||||||
}
|
}
|
||||||
return parseFixed(value, (unit != null) ? unit: 18);
|
return parseFixed(value, (unit != null) ? unit: 18);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { logger } from "./logger.js";
|
import { getBytes } from "./data.js";
|
||||||
|
import { assertNormalize, throwArgumentError } from "./errors.js";
|
||||||
|
|
||||||
import type { BytesLike } from "./index.js";
|
import type { BytesLike } from "./index.js";
|
||||||
|
|
||||||
@ -42,8 +43,11 @@ export type Utf8ErrorReason =
|
|||||||
|
|
||||||
export type Utf8ErrorFunc = (reason: Utf8ErrorReason, offset: number, bytes: ArrayLike<number>, output: Array<number>, badCodepoint?: number) => number;
|
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 logger.throwArgumentError(`invalid codepoint at offset ${ offset }; ${ reason }`, "bytes", bytes);
|
return throwArgumentError(`invalid codepoint at offset ${ offset }; ${ reason }`, "bytes", bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ignoreFunc(reason: Utf8ErrorReason, offset: number, bytes: ArrayLike<number>, output: Array<number>, badCodepoint?: number): number {
|
function ignoreFunc(reason: Utf8ErrorReason, offset: number, bytes: ArrayLike<number>, output: Array<number>, badCodepoint?: number): number {
|
||||||
@ -94,7 +98,7 @@ export const Utf8ErrorFuncs: Readonly<Record<"error" | "ignore" | "replace", Utf
|
|||||||
function getUtf8CodePoints(_bytes: BytesLike, onError?: Utf8ErrorFunc): Array<number> {
|
function getUtf8CodePoints(_bytes: BytesLike, onError?: Utf8ErrorFunc): Array<number> {
|
||||||
if (onError == null) { onError = Utf8ErrorFuncs.error; }
|
if (onError == null) { onError = Utf8ErrorFuncs.error; }
|
||||||
|
|
||||||
const bytes = logger.getBytes(_bytes, "bytes");
|
const bytes = getBytes(_bytes, "bytes");
|
||||||
|
|
||||||
const result: Array<number> = [];
|
const result: Array<number> = [];
|
||||||
let i = 0;
|
let i = 0;
|
||||||
@ -192,7 +196,7 @@ function getUtf8CodePoints(_bytes: BytesLike, onError?: Utf8ErrorFunc): Array<nu
|
|||||||
export function toUtf8Bytes(str: string, form?: UnicodeNormalizationForm): Uint8Array {
|
export function toUtf8Bytes(str: string, form?: UnicodeNormalizationForm): Uint8Array {
|
||||||
|
|
||||||
if (form != null) {
|
if (form != null) {
|
||||||
logger.assertNormalize(form);
|
assertNormalize(form);
|
||||||
str = str.normalize(form);
|
str = str.normalize(form);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,7 +236,7 @@ export function toUtf8Bytes(str: string, form?: UnicodeNormalizationForm): Uint8
|
|||||||
return new Uint8Array(result);
|
return new Uint8Array(result);
|
||||||
};
|
};
|
||||||
|
|
||||||
function escapeChar(value: number) {
|
function escapeChar(value: number): string {
|
||||||
const hex = ("0000" + value.toString(16));
|
const hex = ("0000" + value.toString(16));
|
||||||
return "\\u" + hex.substring(hex.length - 4);
|
return "\\u" + hex.substring(hex.length - 4);
|
||||||
}
|
}
|
||||||
@ -283,3 +287,4 @@ export function toUtf8String(bytes: BytesLike, onError?: Utf8ErrorFunc): string
|
|||||||
export function toUtf8CodePoints(str: string, form?: UnicodeNormalizationForm): Array<number> {
|
export function toUtf8CodePoints(str: string, form?: UnicodeNormalizationForm): Array<number> {
|
||||||
return getUtf8CodePoints(toUtf8Bytes(str, form));
|
return getUtf8CodePoints(toUtf8Bytes(str, form));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,9 @@ import { getAddress, resolveAddress } from "../address/index.js";
|
|||||||
import { hashMessage, TypedDataEncoder } from "../hash/index.js";
|
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 { defineProperties, logger, resolveProperties } from "../utils/index.js";
|
import {
|
||||||
|
defineProperties, resolveProperties, throwArgumentError, throwError
|
||||||
|
} from "../utils/index.js";
|
||||||
|
|
||||||
import type { SigningKey } from "../crypto/index.js";
|
import type { SigningKey } from "../crypto/index.js";
|
||||||
import type { TypedDataDomain, TypedDataField } from "../hash/index.js";
|
import type { TypedDataDomain, TypedDataField } from "../hash/index.js";
|
||||||
@ -42,7 +44,7 @@ export class BaseWallet extends AbstractSigner {
|
|||||||
|
|
||||||
if (tx.from != null) {
|
if (tx.from != null) {
|
||||||
if (getAddress(tx.from) !== this.address) {
|
if (getAddress(tx.from) !== this.address) {
|
||||||
logger.throwArgumentError("transaction from address mismatch", "tx.from", _tx.from);
|
throwArgumentError("transaction from address mismatch", "tx.from", _tx.from);
|
||||||
}
|
}
|
||||||
delete tx.from;
|
delete tx.from;
|
||||||
}
|
}
|
||||||
@ -63,7 +65,7 @@ export class BaseWallet extends AbstractSigner {
|
|||||||
// Populate any ENS names
|
// Populate any ENS names
|
||||||
const populated = await TypedDataEncoder.resolveNames(domain, types, value, async (name: string) => {
|
const populated = await TypedDataEncoder.resolveNames(domain, types, value, async (name: string) => {
|
||||||
if (this.provider == null) {
|
if (this.provider == null) {
|
||||||
return logger.throwError("cannot resolve ENS names without a provider", "UNSUPPORTED_OPERATION", {
|
return throwError("cannot resolve ENS names without a provider", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "resolveName",
|
operation: "resolveName",
|
||||||
info: { name }
|
info: { name }
|
||||||
});
|
});
|
||||||
@ -71,7 +73,7 @@ export class BaseWallet extends AbstractSigner {
|
|||||||
|
|
||||||
const address = await this.provider.resolveName(name);
|
const address = await this.provider.resolveName(name);
|
||||||
if (address == null) {
|
if (address == null) {
|
||||||
return logger.throwError("unconfigured ENS name", "UNCONFIGURED_NAME", {
|
return throwError("unconfigured ENS name", "UNCONFIGURED_NAME", {
|
||||||
value: name
|
value: name
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,10 @@ import { computeHmac, randomBytes, ripemd160, SigningKey, sha256 } from "../cryp
|
|||||||
import { VoidSigner } from "../providers/index.js";
|
import { VoidSigner } from "../providers/index.js";
|
||||||
import { computeAddress } from "../transaction/index.js";
|
import { computeAddress } from "../transaction/index.js";
|
||||||
import {
|
import {
|
||||||
concat, dataSlice, decodeBase58, defineProperties, encodeBase58, hexlify, logger, toBigInt, toHex
|
concat, dataSlice, decodeBase58, defineProperties, encodeBase58,
|
||||||
|
getBytes, hexlify,
|
||||||
|
getNumber, toBigInt, toHex,
|
||||||
|
assertPrivate, throwArgumentError, throwError
|
||||||
} from "../utils/index.js";
|
} from "../utils/index.js";
|
||||||
import { langEn } from "../wordlists/lang-en.js";
|
import { langEn } from "../wordlists/lang-en.js";
|
||||||
|
|
||||||
@ -36,7 +39,7 @@ function zpad(value: number, length: number): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function encodeBase58Check(_value: BytesLike): string {
|
function encodeBase58Check(_value: BytesLike): string {
|
||||||
const value = logger.getBytes(_value);
|
const value = getBytes(_value);
|
||||||
const check = dataSlice(sha256(sha256(value)), 0, 4);
|
const check = dataSlice(sha256(sha256(value)), 0, 4);
|
||||||
const bytes = concat([ value, check ]);
|
const bytes = concat([ value, check ]);
|
||||||
return encodeBase58(bytes);
|
return encodeBase58(bytes);
|
||||||
@ -49,22 +52,22 @@ function ser_I(index: number, chainCode: string, publicKey: string, privateKey:
|
|||||||
|
|
||||||
if (index & HardenedBit) {
|
if (index & HardenedBit) {
|
||||||
if (privateKey == null) {
|
if (privateKey == null) {
|
||||||
return logger.throwError("cannot derive child of neutered node", "UNSUPPORTED_OPERATION", {
|
return throwError("cannot derive child of neutered node", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "deriveChild"
|
operation: "deriveChild"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Data = 0x00 || ser_256(k_par)
|
// Data = 0x00 || ser_256(k_par)
|
||||||
data.set(logger.getBytes(privateKey), 1);
|
data.set(getBytes(privateKey), 1);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Data = ser_p(point(k_par))
|
// Data = ser_p(point(k_par))
|
||||||
data.set(logger.getBytes(publicKey));
|
data.set(getBytes(publicKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Data += ser_32(i)
|
// Data += ser_32(i)
|
||||||
for (let i = 24; i >= 0; i -= 8) { data[33 + (i >> 3)] = ((index >> (24 - i)) & 0xff); }
|
for (let i = 24; i >= 0; i -= 8) { data[33 + (i >> 3)] = ((index >> (24 - i)) & 0xff); }
|
||||||
const I = logger.getBytes(computeHmac("sha512", chainCode, data));
|
const I = getBytes(computeHmac("sha512", chainCode, data));
|
||||||
|
|
||||||
return { IL: I.slice(0, 32), IR: I.slice(32) };
|
return { IL: I.slice(0, 32), IR: I.slice(32) };
|
||||||
}
|
}
|
||||||
@ -122,7 +125,7 @@ export class HDNodeWallet extends BaseWallet {
|
|||||||
|
|
||||||
constructor(guard: any, signingKey: SigningKey, parentFingerprint: string, chainCode: string, path: null | string, index: number, depth: number, mnemonic: null | Mnemonic, provider: null | Provider) {
|
constructor(guard: any, signingKey: SigningKey, parentFingerprint: string, chainCode: string, path: null | string, index: number, depth: number, mnemonic: null | Mnemonic, provider: null | Provider) {
|
||||||
super(signingKey, provider);
|
super(signingKey, provider);
|
||||||
logger.assertPrivate(guard, _guard, "HDNodeWallet");
|
assertPrivate(guard, _guard, "HDNodeWallet");
|
||||||
|
|
||||||
defineProperties<HDNodeWallet>(this, { publicKey: signingKey.compressedPublicKey });
|
defineProperties<HDNodeWallet>(this, { publicKey: signingKey.compressedPublicKey });
|
||||||
|
|
||||||
@ -165,7 +168,7 @@ export class HDNodeWallet extends BaseWallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
deriveChild(_index: Numeric): HDNodeWallet {
|
deriveChild(_index: Numeric): HDNodeWallet {
|
||||||
const index = logger.getNumber(_index, "index");
|
const index = getNumber(_index, "index");
|
||||||
if (index > 0xffffffff) { throw new Error("invalid index - " + String(index)); }
|
if (index > 0xffffffff) { throw new Error("invalid index - " + String(index)); }
|
||||||
|
|
||||||
// Base path
|
// Base path
|
||||||
@ -188,12 +191,12 @@ export class HDNodeWallet extends BaseWallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static #fromSeed(_seed: BytesLike, mnemonic: null | Mnemonic): HDNodeWallet {
|
static #fromSeed(_seed: BytesLike, mnemonic: null | Mnemonic): HDNodeWallet {
|
||||||
const seed = logger.getBytes(_seed, "seed");
|
const seed = getBytes(_seed, "seed");
|
||||||
if (seed.length < 16 || seed.length > 64) {
|
if (seed.length < 16 || seed.length > 64) {
|
||||||
throw new Error("invalid seed");
|
throw new Error("invalid seed");
|
||||||
}
|
}
|
||||||
|
|
||||||
const I = logger.getBytes(computeHmac("sha512", MasterSecret, seed));
|
const I = getBytes(computeHmac("sha512", MasterSecret, seed));
|
||||||
const signingKey = new SigningKey(hexlify(I.slice(0, 32)));
|
const signingKey = new SigningKey(hexlify(I.slice(0, 32)));
|
||||||
|
|
||||||
return new HDNodeWallet(_guard, signingKey, "0x00000000", hexlify(I.slice(32)),
|
return new HDNodeWallet(_guard, signingKey, "0x00000000", hexlify(I.slice(32)),
|
||||||
@ -204,7 +207,7 @@ export class HDNodeWallet extends BaseWallet {
|
|||||||
return HDNodeWallet.#fromSeed(seed, null);
|
return HDNodeWallet.#fromSeed(seed, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromPhrase(phrase: string, password = "", path: null | string = defaultPath, wordlist: Wordlist = langEn): HDNodeWallet {
|
static fromPhrase(phrase: string, password: string = "", path: null | string = defaultPath, wordlist: Wordlist = langEn): HDNodeWallet {
|
||||||
if (!path) { path = defaultPath; }
|
if (!path) { path = defaultPath; }
|
||||||
const mnemonic = Mnemonic.fromPhrase(phrase, password, wordlist)
|
const mnemonic = Mnemonic.fromPhrase(phrase, password, wordlist)
|
||||||
return HDNodeWallet.#fromSeed(mnemonic.computeSeed(), mnemonic).derivePath(path);
|
return HDNodeWallet.#fromSeed(mnemonic.computeSeed(), mnemonic).derivePath(path);
|
||||||
@ -216,10 +219,10 @@ export class HDNodeWallet extends BaseWallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static fromExtendedKey(extendedKey: string): HDNodeWallet | HDNodeVoidWallet {
|
static fromExtendedKey(extendedKey: string): HDNodeWallet | HDNodeVoidWallet {
|
||||||
const bytes = logger.getBytes(decodeBase58(extendedKey)); // @TODO: redact
|
const bytes = getBytes(decodeBase58(extendedKey)); // @TODO: redact
|
||||||
|
|
||||||
if (bytes.length !== 82 || encodeBase58Check(bytes.slice(0, 78)) !== extendedKey) {
|
if (bytes.length !== 82 || encodeBase58Check(bytes.slice(0, 78)) !== extendedKey) {
|
||||||
logger.throwArgumentError("invalid extended key", "extendedKey", "[ REDACTED ]");
|
throwArgumentError("invalid extended key", "extendedKey", "[ REDACTED ]");
|
||||||
}
|
}
|
||||||
|
|
||||||
const depth = bytes[4];
|
const depth = bytes[4];
|
||||||
@ -244,10 +247,10 @@ export class HDNodeWallet extends BaseWallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return logger.throwArgumentError("invalid extended key prefix", "extendedKey", "[ REDACTED ]");
|
return throwArgumentError("invalid extended key prefix", "extendedKey", "[ REDACTED ]");
|
||||||
}
|
}
|
||||||
|
|
||||||
static createRandom(password = "", path: null | string = defaultPath, wordlist: Wordlist = langEn): HDNodeWallet {
|
static createRandom(password: string = "", path: null | string = defaultPath, wordlist: Wordlist = langEn): HDNodeWallet {
|
||||||
if (!path) { path = defaultPath; }
|
if (!path) { path = defaultPath; }
|
||||||
const mnemonic = Mnemonic.fromEntropy(randomBytes(16), password, wordlist)
|
const mnemonic = Mnemonic.fromEntropy(randomBytes(16), password, wordlist)
|
||||||
return HDNodeWallet.#fromSeed(mnemonic.computeSeed(), mnemonic).derivePath(path);
|
return HDNodeWallet.#fromSeed(mnemonic.computeSeed(), mnemonic).derivePath(path);
|
||||||
@ -268,7 +271,7 @@ export class HDNodeVoidWallet extends VoidSigner {
|
|||||||
|
|
||||||
constructor(guard: any, address: string, publicKey: string, parentFingerprint: string, chainCode: string, path: null | string, index: number, depth: number, provider: null | Provider) {
|
constructor(guard: any, address: string, publicKey: string, parentFingerprint: string, chainCode: string, path: null | string, index: number, depth: number, provider: null | Provider) {
|
||||||
super(address, provider);
|
super(address, provider);
|
||||||
logger.assertPrivate(guard, _guard, "HDNodeVoidWallet");
|
assertPrivate(guard, _guard, "HDNodeVoidWallet");
|
||||||
|
|
||||||
defineProperties<HDNodeVoidWallet>(this, { publicKey });
|
defineProperties<HDNodeVoidWallet>(this, { publicKey });
|
||||||
|
|
||||||
@ -305,7 +308,7 @@ export class HDNodeVoidWallet extends VoidSigner {
|
|||||||
hasPath(): this is { path: string } { return (this.path != null); }
|
hasPath(): this is { path: string } { return (this.path != null); }
|
||||||
|
|
||||||
deriveChild(_index: Numeric): HDNodeVoidWallet {
|
deriveChild(_index: Numeric): HDNodeVoidWallet {
|
||||||
const index = logger.getNumber(_index, "index");
|
const index = getNumber(_index, "index");
|
||||||
if (index > 0xffffffff) { throw new Error("invalid index - " + String(index)); }
|
if (index > 0xffffffff) { throw new Error("invalid index - " + String(index)); }
|
||||||
|
|
||||||
// Base path
|
// Base path
|
||||||
@ -333,19 +336,19 @@ export class HDNodeVoidWallet extends VoidSigner {
|
|||||||
export class HDNodeWalletManager {
|
export class HDNodeWalletManager {
|
||||||
#root: HDNodeWallet;
|
#root: HDNodeWallet;
|
||||||
|
|
||||||
constructor(phrase: string, password = "", path = "m/44'/60'/0'/0", locale: Wordlist = langEn) {
|
constructor(phrase: string, password: string = "", path: string = "m/44'/60'/0'/0", locale: Wordlist = langEn) {
|
||||||
this.#root = HDNodeWallet.fromPhrase(phrase, password, path, locale);
|
this.#root = HDNodeWallet.fromPhrase(phrase, password, path, locale);
|
||||||
}
|
}
|
||||||
|
|
||||||
getSigner(index = 0): HDNodeWallet {
|
getSigner(index?: number): HDNodeWallet {
|
||||||
return this.#root.deriveChild(index);
|
return this.#root.deriveChild((index == null) ? 0: index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getAccountPath(_index: Numeric): string {
|
export function getAccountPath(_index: Numeric): string {
|
||||||
const index = logger.getNumber(_index, "index");
|
const index = getNumber(_index, "index");
|
||||||
if (index < 0 || index >= HardenedBit) {
|
if (index < 0 || index >= HardenedBit) {
|
||||||
logger.throwArgumentError("invalid account index", "index", index);
|
throwArgumentError("invalid account index", "index", index);
|
||||||
}
|
}
|
||||||
return `m/44'/60'/${ index }'/0/0`;
|
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/id.js";
|
import { id } from "../hash/id.js";
|
||||||
import { logger } from "../utils/index.js";
|
import { getBytes, throwArgumentError } from "../utils/index.js";
|
||||||
|
|
||||||
import { getPassword, looseArrayify, spelunk } from "./utils.js";
|
import { getPassword, looseArrayify, spelunk } from "./utils.js";
|
||||||
|
|
||||||
@ -32,17 +32,17 @@ 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) {
|
if (!encseed || (encseed.length % 16) !== 0) {
|
||||||
logger.throwArgumentError("invalid encseed", "json", json);
|
throwArgumentError("invalid encseed", "json", json);
|
||||||
}
|
}
|
||||||
|
|
||||||
const key = logger.getBytes(pbkdf2(password, password, 2000, 32, "sha256")).slice(0, 16);
|
const key = getBytes(pbkdf2(password, password, 2000, 32, "sha256")).slice(0, 16);
|
||||||
|
|
||||||
const iv = encseed.slice(0, 16);
|
const iv = encseed.slice(0, 16);
|
||||||
const encryptedSeed = encseed.slice(16);
|
const encryptedSeed = encseed.slice(16);
|
||||||
|
|
||||||
// Decrypt the seed
|
// Decrypt the seed
|
||||||
const aesCbc = new CBC(key, iv);
|
const aesCbc = new CBC(key, iv);
|
||||||
const seed = pkcs7Strip(logger.getBytes(aesCbc.decrypt(encryptedSeed)));
|
const seed = pkcs7Strip(getBytes(aesCbc.decrypt(encryptedSeed)));
|
||||||
|
|
||||||
// This wallet format is weird... Convert the binary encoded hex to a string.
|
// This wallet format is weird... Convert the binary encoded hex to a string.
|
||||||
let seedHex = "";
|
let seedHex = "";
|
||||||
|
@ -3,7 +3,9 @@ import { CTR } from "aes-js";
|
|||||||
import { getAddress } from "../address/index.js";
|
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 { concat, hexlify, logger } from "../utils/index.js";
|
import {
|
||||||
|
concat, getBytes, hexlify, throwArgumentError, throwError
|
||||||
|
} from "../utils/index.js";
|
||||||
|
|
||||||
import { getPassword, spelunk, uuidV4, zpad } from "./utils.js";
|
import { getPassword, spelunk, uuidV4, zpad } from "./utils.js";
|
||||||
|
|
||||||
@ -65,18 +67,18 @@ function decrypt(data: any, key: Uint8Array, ciphertext: Uint8Array): string {
|
|||||||
return hexlify(aesCtr.decrypt(ciphertext));
|
return hexlify(aesCtr.decrypt(ciphertext));
|
||||||
}
|
}
|
||||||
|
|
||||||
return logger.throwError("unsupported cipher", "UNSUPPORTED_OPERATION", {
|
return throwError("unsupported cipher", "UNSUPPORTED_OPERATION", {
|
||||||
operation: "decrypt"
|
operation: "decrypt"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAccount(data: any, _key: string): KeystoreAccount {
|
function getAccount(data: any, _key: string): KeystoreAccount {
|
||||||
const key = logger.getBytes(_key);
|
const key = getBytes(_key);
|
||||||
const ciphertext = spelunk<Uint8Array>(data, "crypto.ciphertext:data!");
|
const 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()) {
|
if (computedMAC !== spelunk(data, "crypto.mac:string!").toLowerCase()) {
|
||||||
return logger.throwArgumentError("incorrect password", "password", "[ REDACTED ]");
|
return throwArgumentError("incorrect password", "password", "[ REDACTED ]");
|
||||||
}
|
}
|
||||||
|
|
||||||
const privateKey = decrypt(data, key.slice(0, 16), ciphertext);
|
const privateKey = decrypt(data, key.slice(0, 16), ciphertext);
|
||||||
@ -87,7 +89,7 @@ function getAccount(data: any, _key: string): KeystoreAccount {
|
|||||||
if (check.substring(0, 2) !== "0x") { check = "0x" + check; }
|
if (check.substring(0, 2) !== "0x") { check = "0x" + check; }
|
||||||
|
|
||||||
if (getAddress(check) !== address) {
|
if (getAddress(check) !== address) {
|
||||||
logger.throwArgumentError("keystore address/privateKey mismatch", "address", data.address);
|
throwArgumentError("keystore address/privateKey mismatch", "address", data.address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +108,7 @@ function getAccount(data: any, _key: string): KeystoreAccount {
|
|||||||
account.mnemonic = {
|
account.mnemonic = {
|
||||||
path: (spelunk<null | string>(data, "x-ethers.path:string") || defaultPath),
|
path: (spelunk<null | string>(data, "x-ethers.path:string") || defaultPath),
|
||||||
locale: (spelunk<null | string>(data, "x-ethers.locale:string") || "en"),
|
locale: (spelunk<null | string>(data, "x-ethers.locale:string") || "en"),
|
||||||
entropy: hexlify(logger.getBytes(mnemonicAesCtr.decrypt(mnemonicCiphertext)))
|
entropy: hexlify(getBytes(mnemonicAesCtr.decrypt(mnemonicCiphertext)))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,7 +134,7 @@ function getKdfParams<T>(data: any): KdfParams {
|
|||||||
const kdf = spelunk(data, "crypto.kdf:string");
|
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 logger.throwArgumentError("invalid key-derivation function parameters", name, value);
|
return throwArgumentError("invalid key-derivation function parameters", name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kdf.toLowerCase() === "scrypt") {
|
if (kdf.toLowerCase() === "scrypt") {
|
||||||
@ -171,7 +173,7 @@ function getKdfParams<T>(data: any): KdfParams {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return logger.throwArgumentError("unsupported key-derivation function", "kdf", kdf);
|
return throwArgumentError("unsupported key-derivation function", "kdf", kdf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -252,7 +254,7 @@ export async function encryptKeystoreJson(account: KeystoreAccount, password: st
|
|||||||
}
|
}
|
||||||
if (!options) { options = {}; }
|
if (!options) { options = {}; }
|
||||||
|
|
||||||
const privateKey = logger.getBytes(account.privateKey, "privateKey");
|
const privateKey = getBytes(account.privateKey, "privateKey");
|
||||||
const passwordBytes = getPassword(password);
|
const passwordBytes = getPassword(password);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -269,18 +271,18 @@ export async function encryptKeystoreJson(account: KeystoreAccount, password: st
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
// Check/generate the salt
|
// Check/generate the salt
|
||||||
const salt = (options.salt != null) ? logger.getBytes(options.salt, "options.slat"): randomBytes(32);
|
const salt = (options.salt != null) ? getBytes(options.salt, "options.slat"): randomBytes(32);
|
||||||
|
|
||||||
// Override initialization vector
|
// Override initialization vector
|
||||||
const iv = (options.iv != null) ? logger.getBytes(options.iv, "options.iv"): randomBytes(16);
|
const iv = (options.iv != null) ? getBytes(options.iv, "options.iv"): randomBytes(16);
|
||||||
if (iv.length !== 16) {
|
if (iv.length !== 16) {
|
||||||
logger.throwArgumentError("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) ? logger.getBytes(options.uuid, "options.uuid"): randomBytes(16);
|
const uuidRandom = (options.uuid != null) ? getBytes(options.uuid, "options.uuid"): randomBytes(16);
|
||||||
if (uuidRandom.length !== 16) {
|
if (uuidRandom.length !== 16) {
|
||||||
logger.throwArgumentError("invalid options.uuid", "options.uuid", options.iv);
|
throwArgumentError("invalid options.uuid", "options.uuid", options.iv);
|
||||||
}
|
}
|
||||||
if (uuidRandom.length !== 16) { throw new Error("invalid uuid"); }
|
if (uuidRandom.length !== 16) { throw new Error("invalid uuid"); }
|
||||||
|
|
||||||
@ -296,7 +298,7 @@ export async function encryptKeystoreJson(account: KeystoreAccount, password: st
|
|||||||
// - 32 bytes As normal for the Web3 secret storage (derivedKey, macPrefix)
|
// - 32 bytes As normal for the Web3 secret storage (derivedKey, macPrefix)
|
||||||
// - 32 bytes AES key to encrypt mnemonic with (required here to be Ethers Wallet)
|
// - 32 bytes AES key to encrypt mnemonic with (required here to be Ethers Wallet)
|
||||||
const _key = await scrypt(passwordBytes, salt, N, r, p, 64, progressCallback);
|
const _key = await scrypt(passwordBytes, salt, N, r, p, 64, progressCallback);
|
||||||
const key = logger.getBytes(_key);
|
const key = getBytes(_key);
|
||||||
|
|
||||||
// This will be used to encrypt the wallet (as per Web3 secret storage)
|
// This will be used to encrypt the wallet (as per Web3 secret storage)
|
||||||
const derivedKey = key.slice(0, 16);
|
const derivedKey = key.slice(0, 16);
|
||||||
@ -304,7 +306,7 @@ export async function encryptKeystoreJson(account: KeystoreAccount, password: st
|
|||||||
|
|
||||||
// Encrypt the private key
|
// Encrypt the private key
|
||||||
const aesCtr = new CTR(derivedKey, iv);
|
const aesCtr = new CTR(derivedKey, iv);
|
||||||
const ciphertext = logger.getBytes(aesCtr.encrypt(privateKey));
|
const ciphertext = getBytes(aesCtr.encrypt(privateKey));
|
||||||
|
|
||||||
// Compute the message authentication code, used to check the password
|
// Compute the message authentication code, used to check the password
|
||||||
const mac = keccak256(concat([ macPrefix, ciphertext ]))
|
const mac = keccak256(concat([ macPrefix, ciphertext ]))
|
||||||
@ -341,10 +343,10 @@ export async function encryptKeystoreJson(account: KeystoreAccount, password: st
|
|||||||
|
|
||||||
const mnemonicKey = key.slice(32, 64);
|
const mnemonicKey = key.slice(32, 64);
|
||||||
|
|
||||||
const entropy = logger.getBytes(account.mnemonic.entropy, "account.mnemonic.entropy");
|
const entropy = getBytes(account.mnemonic.entropy, "account.mnemonic.entropy");
|
||||||
const mnemonicIv = randomBytes(16);
|
const mnemonicIv = randomBytes(16);
|
||||||
const mnemonicAesCtr = new CTR(mnemonicKey, mnemonicIv);
|
const mnemonicAesCtr = new CTR(mnemonicKey, mnemonicIv);
|
||||||
const mnemonicCiphertext = logger.getBytes(mnemonicAesCtr.encrypt(entropy));
|
const mnemonicCiphertext = getBytes(mnemonicAesCtr.encrypt(entropy));
|
||||||
|
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const timestamp = (now.getUTCFullYear() + "-" +
|
const timestamp = (now.getUTCFullYear() + "-" +
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import { pbkdf2, sha256 } from "../crypto/index.js";
|
import { pbkdf2, sha256 } from "../crypto/index.js";
|
||||||
import { defineProperties, hexlify, logger, toUtf8Bytes } from "../utils/index.js";
|
import {
|
||||||
|
defineProperties, getBytes, hexlify, assertNormalize, assertPrivate, throwArgumentError, toUtf8Bytes
|
||||||
|
} from "../utils/index.js";
|
||||||
import { langEn } from "../wordlists/lang-en.js";
|
import { langEn } from "../wordlists/lang-en.js";
|
||||||
|
|
||||||
import type { BytesLike } from "../utils/index.js";
|
import type { BytesLike } from "../utils/index.js";
|
||||||
@ -18,13 +20,13 @@ function getLowerMask(bits: number): number {
|
|||||||
|
|
||||||
|
|
||||||
function mnemonicToEntropy(mnemonic: string, wordlist: null | Wordlist = langEn): string {
|
function mnemonicToEntropy(mnemonic: string, wordlist: null | Wordlist = langEn): string {
|
||||||
logger.assertNormalize("NFKD");
|
assertNormalize("NFKD");
|
||||||
|
|
||||||
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) {
|
if ((words.length % 3) !== 0 || words.length < 12 || words.length > 24) {
|
||||||
logger.throwArgumentError("invalid mnemonic length", "mnemonic", "[ REDACTED ]");
|
throwArgumentError("invalid mnemonic length", "mnemonic", "[ REDACTED ]");
|
||||||
}
|
}
|
||||||
|
|
||||||
const entropy = new Uint8Array(Math.ceil(11 * words.length / 8));
|
const entropy = new Uint8Array(Math.ceil(11 * words.length / 8));
|
||||||
@ -33,7 +35,7 @@ function mnemonicToEntropy(mnemonic: string, wordlist: null | Wordlist = langEn)
|
|||||||
for (let i = 0; i < words.length; i++) {
|
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) {
|
if (index === -1) {
|
||||||
logger.throwArgumentError(`invalid mnemonic word at index ${ i }`, "mnemonic", "[ REDACTED ]");
|
throwArgumentError(`invalid mnemonic word at index ${ i }`, "mnemonic", "[ REDACTED ]");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let bit = 0; bit < 11; bit++) {
|
for (let bit = 0; bit < 11; bit++) {
|
||||||
@ -50,10 +52,10 @@ function mnemonicToEntropy(mnemonic: string, wordlist: null | Wordlist = langEn)
|
|||||||
const checksumBits = words.length / 3;
|
const checksumBits = words.length / 3;
|
||||||
const checksumMask = getUpperMask(checksumBits);
|
const checksumMask = getUpperMask(checksumBits);
|
||||||
|
|
||||||
const checksum = logger.getBytes(sha256(entropy.slice(0, entropyBits / 8)))[0] & checksumMask;
|
const checksum = getBytes(sha256(entropy.slice(0, entropyBits / 8)))[0] & checksumMask;
|
||||||
|
|
||||||
if (checksum !== (entropy[entropy.length - 1] & checksumMask)) {
|
if (checksum !== (entropy[entropy.length - 1] & checksumMask)) {
|
||||||
logger.throwArgumentError("invalid mnemonic checksum", "mnemonic", "[ REDACTED ]");
|
throwArgumentError("invalid mnemonic checksum", "mnemonic", "[ REDACTED ]");
|
||||||
}
|
}
|
||||||
|
|
||||||
return hexlify(entropy.slice(0, entropyBits / 8));
|
return hexlify(entropy.slice(0, entropyBits / 8));
|
||||||
@ -61,7 +63,7 @@ function mnemonicToEntropy(mnemonic: string, wordlist: null | Wordlist = langEn)
|
|||||||
|
|
||||||
function entropyToMnemonic(entropy: Uint8Array, wordlist: null | Wordlist = langEn): string {
|
function entropyToMnemonic(entropy: Uint8Array, wordlist: null | Wordlist = langEn): string {
|
||||||
if ((entropy.length % 4) || entropy.length < 16 || entropy.length > 32) {
|
if ((entropy.length % 4) || entropy.length < 16 || entropy.length > 32) {
|
||||||
logger.throwArgumentError("invalid entropy size", "entropy", "[ REDACTED ]");
|
throwArgumentError("invalid entropy size", "entropy", "[ REDACTED ]");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wordlist == null) { wordlist = langEn; }
|
if (wordlist == null) { wordlist = langEn; }
|
||||||
@ -113,7 +115,7 @@ export class Mnemonic {
|
|||||||
constructor(guard: any, entropy: string, phrase: string, password?: null | string, wordlist?: null | Wordlist) {
|
constructor(guard: any, entropy: string, phrase: string, password?: null | string, wordlist?: null | Wordlist) {
|
||||||
if (password == null) { password = ""; }
|
if (password == null) { password = ""; }
|
||||||
if (wordlist == null) { wordlist = langEn; }
|
if (wordlist == null) { wordlist = langEn; }
|
||||||
logger.assertPrivate(guard, _guard, "Mnemonic");
|
assertPrivate(guard, _guard, "Mnemonic");
|
||||||
defineProperties<Mnemonic>(this, { phrase, password, wordlist, entropy });
|
defineProperties<Mnemonic>(this, { phrase, password, wordlist, entropy });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,21 +124,21 @@ export class Mnemonic {
|
|||||||
return pbkdf2(toUtf8Bytes(this.phrase, "NFKD"), salt, 2048, 64, "sha512");
|
return pbkdf2(toUtf8Bytes(this.phrase, "NFKD"), salt, 2048, 64, "sha512");
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromPhrase(phrase: string, password?: null | string, wordlist?: null | Wordlist) {
|
static fromPhrase(phrase: string, password?: null | string, wordlist?: null | Wordlist): Mnemonic {
|
||||||
// Normalize the case and space; throws if invalid
|
// Normalize the case and space; throws if invalid
|
||||||
const entropy = mnemonicToEntropy(phrase, wordlist);
|
const entropy = mnemonicToEntropy(phrase, wordlist);
|
||||||
phrase = entropyToMnemonic(logger.getBytes(entropy), wordlist);
|
phrase = entropyToMnemonic(getBytes(entropy), wordlist);
|
||||||
return new Mnemonic(_guard, entropy, phrase, password, wordlist);
|
return new Mnemonic(_guard, entropy, phrase, password, wordlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromEntropy(_entropy: BytesLike, password?: null | string, wordlist?: null | Wordlist): Mnemonic {
|
static fromEntropy(_entropy: BytesLike, password?: null | string, wordlist?: null | Wordlist): Mnemonic {
|
||||||
const entropy = logger.getBytes(_entropy, "entropy");
|
const entropy = getBytes(_entropy, "entropy");
|
||||||
const phrase = entropyToMnemonic(entropy, wordlist);
|
const phrase = entropyToMnemonic(entropy, wordlist);
|
||||||
return new Mnemonic(_guard, hexlify(entropy), phrase, password, wordlist);
|
return new Mnemonic(_guard, hexlify(entropy), phrase, password, wordlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
static entropyToPhrase(_entropy: BytesLike, wordlist?: null | Wordlist): string {
|
static entropyToPhrase(_entropy: BytesLike, wordlist?: null | Wordlist): string {
|
||||||
const entropy = logger.getBytes(_entropy, "entropy");
|
const entropy = getBytes(_entropy, "entropy");
|
||||||
return entropyToMnemonic(entropy, wordlist);
|
return entropyToMnemonic(entropy, wordlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import { hexlify, logger, toUtf8Bytes } from "../utils/index.js";
|
import {
|
||||||
|
getBytes, getBytesCopy, hexlify, throwArgumentError, toUtf8Bytes
|
||||||
|
} from "../utils/index.js";
|
||||||
|
|
||||||
import type { BytesLike } from "../utils/index.js";
|
import type { BytesLike } from "../utils/index.js";
|
||||||
|
|
||||||
@ -7,7 +9,7 @@ export function looseArrayify(hexString: string): Uint8Array {
|
|||||||
if (typeof(hexString) === 'string' && hexString.substring(0, 2) !== '0x') {
|
if (typeof(hexString) === 'string' && hexString.substring(0, 2) !== '0x') {
|
||||||
hexString = '0x' + hexString;
|
hexString = '0x' + hexString;
|
||||||
}
|
}
|
||||||
return logger.getBytesCopy(hexString);
|
return getBytesCopy(hexString);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function zpad(value: String | number, length: number): String {
|
export function zpad(value: String | number, length: number): String {
|
||||||
@ -20,14 +22,14 @@ export function getPassword(password: string | Uint8Array): Uint8Array {
|
|||||||
if (typeof(password) === 'string') {
|
if (typeof(password) === 'string') {
|
||||||
return toUtf8Bytes(password, "NFKC");
|
return toUtf8Bytes(password, "NFKC");
|
||||||
}
|
}
|
||||||
return logger.getBytesCopy(password);
|
return getBytesCopy(password);
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
if (match == null) {
|
||||||
return logger.throwArgumentError("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];
|
||||||
@ -59,7 +61,7 @@ export function spelunk<T = string>(object: any, _path: string): T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (reqd && cur == null) {
|
if (reqd && cur == null) {
|
||||||
logger.throwArgumentError("missing required value", "path", path);
|
throwArgumentError("missing required value", "path", path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type && cur != null) {
|
if (type && cur != null) {
|
||||||
@ -84,7 +86,7 @@ export function spelunk<T = string>(object: any, _path: string): T {
|
|||||||
if (type === "array" && Array.isArray(cur)) { return <T><unknown>cur; }
|
if (type === "array" && Array.isArray(cur)) { return <T><unknown>cur; }
|
||||||
if (type === typeof(cur)) { return cur; }
|
if (type === typeof(cur)) { return cur; }
|
||||||
|
|
||||||
logger.throwArgumentError(`wrong type found for ${ type } `, "path", path);
|
throwArgumentError(`wrong type found for ${ type } `, "path", path);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cur;
|
return cur;
|
||||||
@ -122,7 +124,7 @@ export function followRequired(data: any, path: string): string {
|
|||||||
*/
|
*/
|
||||||
// See: https://www.ietf.org/rfc/rfc4122.txt (Section 4.4)
|
// See: https://www.ietf.org/rfc/rfc4122.txt (Section 4.4)
|
||||||
export function uuidV4(randomBytes: BytesLike): string {
|
export function uuidV4(randomBytes: BytesLike): string {
|
||||||
const bytes = logger.getBytes(randomBytes, "randomBytes");
|
const bytes = getBytes(randomBytes, "randomBytes");
|
||||||
|
|
||||||
// Section: 4.1.3:
|
// Section: 4.1.3:
|
||||||
// - time_hi_and_version[12:16] = 0b0100
|
// - time_hi_and_version[12:16] = 0b0100
|
||||||
|
@ -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, logger } from "../utils/index.js";
|
import { isHexString, throwArgumentError } 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";
|
||||||
@ -90,7 +90,7 @@ export class Wallet extends BaseWallet {
|
|||||||
if (signingKey == null) { signingKey = trySigningKey(key); }
|
if (signingKey == null) { signingKey = trySigningKey(key); }
|
||||||
|
|
||||||
if (signingKey == null) {
|
if (signingKey == null) {
|
||||||
logger.throwArgumentError("invalid key", "key", "[ REDACTED ]");
|
throwArgumentError("invalid key", "key", "[ REDACTED ]");
|
||||||
}
|
}
|
||||||
|
|
||||||
super(signingKey as SigningKey, provider);
|
super(signingKey as SigningKey, provider);
|
||||||
@ -123,12 +123,12 @@ export class Wallet extends BaseWallet {
|
|||||||
if (progress) { progress(1); await stall(0); }
|
if (progress) { progress(1); await stall(0); }
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return logger.throwArgumentError("invalid JSON wallet", "json", "[ REDACTED ]");
|
return throwArgumentError("invalid JSON wallet", "json", "[ REDACTED ]");
|
||||||
}
|
}
|
||||||
|
|
||||||
const wallet = new Wallet(account.privateKey);
|
const wallet = new Wallet(account.privateKey);
|
||||||
if (wallet.address !== account.address) {
|
if (wallet.address !== account.address) {
|
||||||
logger.throwArgumentError("address/privateKey mismatch", "json", "[ REDACTED ]");
|
throwArgumentError("address/privateKey mismatch", "json", "[ REDACTED ]");
|
||||||
}
|
}
|
||||||
// @TODO: mnemonic
|
// @TODO: mnemonic
|
||||||
return wallet;
|
return wallet;
|
||||||
@ -141,12 +141,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 logger.throwArgumentError("invalid JSON wallet", "json", "[ REDACTED ]");
|
return throwArgumentError("invalid JSON wallet", "json", "[ REDACTED ]");
|
||||||
}
|
}
|
||||||
|
|
||||||
const wallet = new Wallet(account.privateKey);
|
const wallet = new Wallet(account.privateKey);
|
||||||
if (wallet.address !== account.address) {
|
if (wallet.address !== account.address) {
|
||||||
logger.throwArgumentError("address/privateKey mismatch", "json", "[ REDACTED ]");
|
throwArgumentError("address/privateKey mismatch", "json", "[ REDACTED ]");
|
||||||
}
|
}
|
||||||
// @TODO: mnemonic
|
// @TODO: mnemonic
|
||||||
return wallet;
|
return wallet;
|
||||||
@ -160,7 +160,8 @@ export class Wallet extends BaseWallet {
|
|||||||
return new Wallet(mnemonic, provider);
|
return new Wallet(mnemonic, provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromPhrase(phrase: string, provider?: null | Provider, password = "", wordlist?: Wordlist): Wallet {
|
static fromPhrase(phrase: string, provider?: null | Provider, password?: string, wordlist?: Wordlist): Wallet {
|
||||||
|
if (password == null) { password = ""; }
|
||||||
return new Wallet(Mnemonic.fromPhrase(phrase, password, wordlist), provider);
|
return new Wallet(Mnemonic.fromPhrase(phrase, password, wordlist), provider);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { assertArgument } from "../utils/logger.js";
|
import { assertArgument } from "../utils/index.js";
|
||||||
|
|
||||||
|
|
||||||
const subsChrs = " !#$%&'()*+,-./<=>?@[]^_`{|}~";
|
const subsChrs = " !#$%&'()*+,-./<=>?@[]^_`{|}~";
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { assertArgument } from "../utils/logger.js";
|
import { assertArgument } from "../utils/index.js";
|
||||||
|
|
||||||
import { decodeBits } from "./bit-reader.js";
|
import { decodeBits } from "./bit-reader.js";
|
||||||
import { decodeOwl } from "./decode-owl.js";
|
import { decodeOwl } from "./decode-owl.js";
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import { id } from "../hash/id.js";
|
import { id } from "../hash/id.js";
|
||||||
import { hexlify, logger, toUtf8Bytes, toUtf8String } from "../utils/index.js";
|
import {
|
||||||
|
hexlify, throwArgumentError, toUtf8Bytes, toUtf8String
|
||||||
|
} from "../utils/index.js";
|
||||||
|
|
||||||
import { Wordlist } from "./wordlist.js";
|
import { Wordlist } from "./wordlist.js";
|
||||||
|
|
||||||
@ -135,7 +137,7 @@ class LangJa extends Wordlist {
|
|||||||
getWord(index: number): string {
|
getWord(index: number): string {
|
||||||
const words = loadWords();
|
const words = loadWords();
|
||||||
if (index < 0 || index >= words.length) {
|
if (index < 0 || index >= words.length) {
|
||||||
logger.throwArgumentError(`invalid word index: ${ index }`, "index", index);
|
throwArgumentError(`invalid word index: ${ index }`, "index", index);
|
||||||
}
|
}
|
||||||
return words[index];
|
return words[index];
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { id } from "../hash/id.js";
|
import { id } from "../hash/id.js";
|
||||||
import { logger, toUtf8String } from "../utils/index.js";
|
import { throwArgumentError, toUtf8String } from "../utils/index.js";
|
||||||
|
|
||||||
import { Wordlist } from "./wordlist.js";
|
import { Wordlist } from "./wordlist.js";
|
||||||
|
|
||||||
@ -70,7 +70,7 @@ class LangKo extends Wordlist {
|
|||||||
getWord(index: number): string {
|
getWord(index: number): string {
|
||||||
const words = loadWords();
|
const words = loadWords();
|
||||||
if (index < 0 || index >= words.length) {
|
if (index < 0 || index >= words.length) {
|
||||||
logger.throwArgumentError(`invalid word index: ${ index }`, "index", index);
|
throwArgumentError(`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 { toUtf8String, logger } from "../utils/index.js";
|
import { throwArgumentError, toUtf8String } from "../utils/index.js";
|
||||||
|
|
||||||
import { Wordlist } from "./wordlist.js";
|
import { Wordlist } from "./wordlist.js";
|
||||||
|
|
||||||
@ -64,7 +64,7 @@ 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) {
|
if (index < 0 || index >= words.length) {
|
||||||
logger.throwArgumentError(`invalid word index: ${ index }`, "index", index);
|
throwArgumentError(`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/id.js";
|
import { id } from "../hash/id.js";
|
||||||
import { logger } from "../utils/logger.js";
|
import { throwArgumentError } from "../utils/index.js";
|
||||||
|
|
||||||
import { decodeOwl } from "./decode-owl.js";
|
import { decodeOwl } from "./decode-owl.js";
|
||||||
import { Wordlist } from "./wordlist.js";
|
import { Wordlist } from "./wordlist.js";
|
||||||
@ -46,7 +46,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) {
|
if (index < 0 || index >= words.length) {
|
||||||
logger.throwArgumentError(`invalid word index: ${ index }`, "index", index);
|
throwArgumentError(`invalid word index: ${ index }`, "index", index);
|
||||||
}
|
}
|
||||||
return words[index];
|
return words[index];
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user