Moved away from isNamedInstance which breaks after Browserify name mangling.

This commit is contained in:
Richard Moore 2019-06-10 22:25:46 -04:00
parent e6f6383346
commit 257d67c962
No known key found for this signature in database
GPG Key ID: 525F70A6FCABC295
13 changed files with 172 additions and 217 deletions

View File

@ -2,7 +2,7 @@
import { BigNumber } from "@ethersproject/bignumber";
import * as errors from "@ethersproject/errors";
import { defineReadOnly, isNamedInstance } from "@ethersproject/properties";
import { defineReadOnly } from "@ethersproject/properties";
export interface JsonFragmentType {
@ -238,6 +238,8 @@ export class ParamType {
readonly arrayLength: number;
readonly arrayChildren: ParamType;
readonly _isParamType: boolean;
constructor(constructorGuard: any, params: any) {
if (constructorGuard !== _constructorGuard) { throw new Error("use fromString"); }
populate(this, params);
@ -259,6 +261,10 @@ export class ParamType {
baseType: ((this.components != null) ? "tuple": this.type)
});
}
this._isParamType = true;
Object.freeze(this);
}
// Format the parameter fragment
@ -298,7 +304,7 @@ export class ParamType {
}
static fromObject(value: JsonFragmentType | ParamType): ParamType {
if (isNamedInstance<ParamType>(ParamType, value)) { return value; }
if (ParamType.isParamType(value)) { return value; }
return new ParamType(_constructorGuard, {
name: (value.name || null),
@ -320,6 +326,10 @@ export class ParamType {
return ParamTypify(parseParamType(value, !!allowIndexed));
}
static isParamType(value: any): value is ParamType {
return !!(value != null && value._isParamType);
}
};
function parseParams(value: string, allowIndex: boolean): Array<ParamType> {
@ -332,9 +342,15 @@ export abstract class Fragment {
readonly name: string;
readonly inputs: Array<ParamType>;
readonly _isFragment: boolean;
constructor(constructorGuard: any, params: any) {
if (constructorGuard !== _constructorGuard) { throw new Error("use a static from method"); }
populate(this, params);
this._isFragment = true;
Object.freeze(this);
}
// @TOOD: move logic to sub-classes; make this abstract
@ -370,14 +386,17 @@ export abstract class Fragment {
}
static from(value: Fragment | JsonFragment | string): Fragment {
if (Fragment.isFragment(value)) { return value; }
if (typeof(value) === "string") {
return Fragment.fromString(value);
}
return Fragment.fromObject(value);
}
static fromObject(value: Fragment | JsonFragment): Fragment {
if (isNamedInstance<Fragment>(Fragment, value)) { return value; }
if (Fragment.isFragment(value)) { return value; }
if (value.type === "function") {
return FunctionFragment.fromObject(value);
@ -412,6 +431,10 @@ export abstract class Fragment {
throw new Error("unknown fragment");
}
static isFragment(value: any): value is Fragment {
return !!(value && value._isFragment);
}
}
export class EventFragment extends Fragment {
@ -425,7 +448,7 @@ export class EventFragment extends Fragment {
}
static fromObject(value: JsonFragment | EventFragment): EventFragment {
if (isNamedInstance<EventFragment>(EventFragment, value)) { return value; }
if (EventFragment.isEventFragment(value)) { return value; }
if (value.type !== "event") { throw new Error("invalid event object - " + value.type); }
@ -462,6 +485,10 @@ export class EventFragment extends Fragment {
type: "event"
});
}
static isEventFragment(value: any): value is EventFragment {
return (value && value._isFragment && value.type === "event");
}
}
function parseGas(value: string, params: any): string {
@ -528,7 +555,7 @@ export class ConstructorFragment extends Fragment {
}
static fromObject(value: ConstructorFragment | JsonFragment): ConstructorFragment {
if (isNamedInstance<ConstructorFragment>(ConstructorFragment, value)) { return value; }
if (ConstructorFragment.isConstructorFragment(value)) { return value; }
if (value.type !== "constructor") { throw new Error("invalid constructor object - " + value.type); }
@ -557,6 +584,9 @@ export class ConstructorFragment extends Fragment {
return ConstructorFragment.fromObject(params);
}
static isConstructorFragment(value: any): value is ConstructorFragment {
return (value && value._isFragment && value.type === "constructor");
}
}
export class FunctionFragment extends ConstructorFragment {
@ -571,7 +601,7 @@ export class FunctionFragment extends ConstructorFragment {
}
static fromObject(value: FunctionFragment | JsonFragment): FunctionFragment {
if (isNamedInstance<FunctionFragment>(FunctionFragment, value)) { return value; }
if (FunctionFragment.isFunctionFragment(value)) { return value; }
if (value.type !== "function") { throw new Error("invalid function object - " + value.type); }
@ -619,6 +649,10 @@ export class FunctionFragment extends ConstructorFragment {
return FunctionFragment.fromObject(params);
}
static isFunctionFragment(value: any): value is FunctionFragment {
return (value && value._isFragment && value.type === "function");
}
}
//export class ErrorFragment extends Fragment {

View File

@ -6,7 +6,7 @@ import { arrayify, BytesLike, concat, hexDataSlice, hexlify, hexZeroPad, isHexSt
import { id } from "@ethersproject/hash";
import { keccak256 } from "@ethersproject/keccak256"
import * as errors from "@ethersproject/errors";
import { defineReadOnly, Description, isNamedInstance } from "@ethersproject/properties";
import { defineReadOnly, Description } from "@ethersproject/properties";
import { AbiCoder, defaultAbiCoder } from "./abi-coder";
import { ConstructorFragment, EventFragment, Fragment, FunctionFragment, JsonFragment, ParamType } from "./fragments";
@ -31,6 +31,10 @@ export class TransactionDescription extends Description {
export class Indexed extends Description {
readonly hash: string;
static isIndexed(value: any): value is Indexed {
return !!(value && value._isIndexed);
}
}
export class Result {
@ -51,6 +55,8 @@ export class Interface {
readonly _abiCoder: AbiCoder;
static _isInterface: boolean;
constructor(fragments: string | Array<Fragment | JsonFragment | string>) {
errors.checkNew(new.target, Interface);
@ -62,9 +68,6 @@ export class Interface {
}
defineReadOnly(this, "fragments", abi.map((fragment) => {
if (isNamedInstance<Fragment>(Fragment, fragment)) {
return fragment
}
return Fragment.from(fragment);
}).filter((fragment) => (fragment != null)));
@ -122,6 +125,8 @@ export class Interface {
if (!this.deploy) {
defineReadOnly(this, "deploy", ConstructorFragment.from( { type: "constructor" } ));
}
defineReadOnly(this, "_isInterface", true);
}
static getAbiCoder(): AbiCoder {
@ -325,10 +330,10 @@ export class Interface {
eventFragment.inputs.forEach((param, index) => {
if (param.indexed) {
if (resultIndexed == null) {
result[index] = new Indexed({ hash: null });
result[index] = new Indexed({ _isIndexed: true, hash: null });
} else if (dynamic[index]) {
result[index] = new Indexed({ hash: resultIndexed[indexedIndex++] });
result[index] = new Indexed({ _isIndexed: true, hash: resultIndexed[indexedIndex++] });
} else {
result[index] = resultIndexed[indexedIndex++];
@ -387,6 +392,10 @@ export class Interface {
return new Interface(value);
}
*/
static isInterface(value: any): value is Interface {
return !!(value && value._isInterface);
}
}
function getFragment(hash: string, calcFunc: (f: Fragment) => string, items: { [ sig: string ]: Fragment } ) {

View File

@ -5,7 +5,7 @@ import { BytesLike, isHexString } from "@ethersproject/bytes";
import * as errors from "@ethersproject/errors";
import { checkAbstract } from "@ethersproject/errors";
import { Network } from "@ethersproject/networks";
import { defineReadOnly } from "@ethersproject/properties";
import { Description, defineReadOnly } from "@ethersproject/properties";
import { Transaction } from "@ethersproject/transactions";
import { OnceBlockable } from "@ethersproject/web";
@ -128,11 +128,13 @@ export interface FilterByBlockHash extends EventFilter {
// call(transaction: TransactionRequest): Promise<TransactionResponse>;
//};
export class ForkEvent {
export abstract class ForkEvent extends Description {
readonly expiry: number;
constructor(expiry?: number) {
defineReadOnly(this, "expiry", expiry || 0);
readonly _isForkEvent: boolean;
static isForkEvent(value: any): value is ForkEvent {
return !!(value && value._isForkEvent);
}
}
@ -143,8 +145,13 @@ export class BlockForkEvent extends ForkEvent {
if (!isHexString(blockhash, 32)) {
errors.throwArgumentError("invalid blockhash", "blockhash", blockhash);
}
super(expiry);
defineReadOnly(this, "blockhash", blockhash);
super({
_isForkEvent: true,
_isBlockForkEvent: true,
expiry: (expiry || 0),
blockHash: blockhash
});
}
}
@ -155,8 +162,13 @@ export class TransactionForkEvent extends ForkEvent {
if (!isHexString(hash, 32)) {
errors.throwArgumentError("invalid transaction hash", "hash", hash);
}
super(expiry);
defineReadOnly(this, "hash", hash);
super({
_isForkEvent: true,
_isTransactionForkEvent: true,
expiry: (expiry || 0),
hash: hash
});
}
}
@ -171,9 +183,14 @@ export class TransactionOrderForkEvent extends ForkEvent {
if (!isHexString(afterHash, 32)) {
errors.throwArgumentError("invalid transaction hash", "afterHash", afterHash);
}
super(expiry);
defineReadOnly(this, "beforeHash", beforeHash);
defineReadOnly(this, "afterHash", afterHash);
super({
_isForkEvent: true,
_isTransactionOrderForkEvent: true,
expiry: (expiry || 0),
beforeHash: beforeHash,
afterHash: afterHash
});
}
}
@ -239,8 +256,15 @@ export abstract class Provider implements OnceBlockable {
// @TODO: This *could* be implemented here, but would pull in events...
abstract waitForTransaction(transactionHash: string, timeout?: number): Promise<TransactionReceipt>;
readonly _isProvider: boolean;
constructor() {
checkAbstract(new.target, Provider);
defineReadOnly(this, "_isProvider", true);
}
static isProvider(value: any): value is Provider {
return !!(value && value._isProvider);
}
/*

View File

@ -51,11 +51,14 @@ export abstract class Signer {
// This MAY throw if changing providers is not supported.
abstract connect(provider: Provider): Signer;
readonly _isSigner: boolean;
///////////////////
// Sub-classes MUST call super
constructor() {
errors.checkAbstract(new.target, Signer);
defineReadOnly(this, "_isSigner", true);
}
@ -179,6 +182,10 @@ export abstract class Signer {
operation: (operation || "_checkProvider") });
}
}
static isSigner(value: any): value is Signer {
return !!(value && value._isSigner);
}
}
export class VoidSigner extends Signer {

View File

@ -11,7 +11,6 @@
import * as BN from "bn.js";
import { Bytes, Hexable, hexlify, isBytes, isHexString } from "@ethersproject/bytes";
import { defineReadOnly, isNamedInstance } from "@ethersproject/properties";
import * as errors from "@ethersproject/errors";
@ -22,18 +21,20 @@ const MAX_SAFE = 0x1fffffffffffff;
export type BigNumberish = BigNumber | Bytes | string | number;
/*
export function isBigNumberLike(value: any): value is BigNumberish {
return (BigNumber.isBigNumber(value) ||
(!!((<any>value).toHexString)) ||
isBytes(value) ||
value.match(/^-?([0-9]+|0x[0-9a-f]+)$/i) ||
typeof(value) === "number");
export function isBigNumberish(value: any): value is BigNumberish {
return (value != null) && (
BigNumber.isBigNumber(value) ||
(typeof(value) === "number" && (value % 1) === 0) ||
(typeof(value) === "string" && !!value.match(/^-?[0-9]+$/)) ||
isHexString(value) ||
(typeof(value) === "bigint") ||
isBytes(value)
);
}
*/
export class BigNumber implements Hexable {
readonly _hex: string;
readonly _isBigNumber: boolean;
constructor(constructorGuard: any, hex: string) {
errors.checkNew(new.target, BigNumber);
@ -44,7 +45,10 @@ export class BigNumber implements Hexable {
});
}
defineReadOnly(this, "_hex", hex);
this._hex = hex;
this._isBigNumber = true;
Object.freeze(this);
}
fromTwos(value: number): BigNumber {
@ -189,104 +193,10 @@ export class BigNumber implements Hexable {
}
static isBigNumber(value: any): value is BigNumber {
return isNamedInstance<BigNumber>(this, value);
return !!(value && value._isBigNumber);
}
}
/*
export function bigNumberify(value: BigNumberish): BigNumber {
if (BigNumber.isBigNumber(value)) { return value; }
return new BigNumber(value);
}
*/
/*
function zeros(length) {
let result = "";
while (result.length < length) { tens += "0"; }
return result;
}
export class FixedNumber {
readonly value: BigNumber;
readonly decimalPlaces: number;
constructor(value: BigNumberish, decimalPlaces: number) {
defineReadOnly(this, "value", bigNumberify(value));
defineReadOnly(this, "decimalPlaces", decimalPlaces);
}
toString(): string {
return formatUnits(this.value, this.decimalPlaces);
}
static fromString(value: string): FixedNumber {
let comps = value.split(".");
let decimalPlaces = 0;
if (comps.length === 2) { decimalPlaces = comps[1].length; }
return new FixedNumber(parseUnits(value, decimalPlaces), decimalPlaces);
}
*/
/*
readonly negative: boolean;
readonly whole: BigNumber;
readonly fraction: BigNumber;
constructor(whole: BigNumberish, fraction: BigNumberish, negative?: boolean) {
if (whole.lt(constants.Zero)) {
errors.throwError("whole component must be positive", errors.INVALID_ARGUMENT, {
argument: whole,
value: whole
});
}
defineReadOnly(this, "whole", bigNumberify(whole));
defineReadOnly(this, "fraction", bigNumberify(fraction));
defineReadOnly(this, "negative", !!boolean);
}
*/
/*
toHexString(bitWidth?: number, decimalPlaces?: number, signed?: boolean): string {
if (bitWidth == null) { bitWidth = 128; }
if (decimalPlaces == null) { decimalPlaces = 18; }
if (signed == null) { signed = true; }
return null;
}
static fromValue(value: BigNumberish, decimalPlaces: number): FixedNumber {
let negative = false;
if (value.lt(constants.Zero)) {
negative = true;
value = value.abs();
}
let tens = bigNumberify("1" + zeros(decimalPlaces));
return new FixedNumber(value.divide(tens), value.mod(tens), negative);
}
let negative = false;
if (value.substring(0, 1) === "-") {
negative = true;
value = value.substring(1);
}
if (value !== "." && value !== "") {
let comps = value.split(".");
if (comps.length === 1) {
return new FixedNumber(comps[0], 0, negative);
} else if (comps.length === 2) {
if (comps[0] === "") { comps[0] = "0"; }
if (comps[1] === "") { comps[1] = "0"; }
return new FixedNumber(comps[0], comps[1], negative);
}
}
errors.throwError("invalid fixed-point value", errors.INVALID_ARGUMENT, {
argument: "value",
value: value
});
return null;
*/
//}
// Normalize the hex string
function toHex(value: string | BN.BN): string {

View File

@ -2,9 +2,8 @@
import { arrayify, BytesLike, hexZeroPad, isBytes } from "@ethersproject/bytes";
import * as errors from "@ethersproject/errors";
import { defineReadOnly, isNamedInstance } from "@ethersproject/properties";
import { BigNumber, BigNumberish } from "./bignumber";
import { BigNumber, BigNumberish, isBigNumberish } from "./bignumber";
const _constructorGuard = { };
@ -115,17 +114,18 @@ export class FixedFormat {
readonly width: number;
readonly decimals: number;
readonly name: string;
readonly _multiplier: BigNumber;
readonly _multiplier: string;
constructor(constructorGuard: any, signed: boolean, width: number, decimals: number) {
defineReadOnly(this, "signed", signed);
defineReadOnly(this, "width", width);
defineReadOnly(this, "decimals", decimals);
this.signed = signed;
this.width = width;
this.decimals = decimals;
let name = (signed ? "": "u") + "fixed" + String(width) + "x" + String(decimals);
defineReadOnly(this, "name", name);
this.name = (signed ? "": "u") + "fixed" + String(width) + "x" + String(decimals);
defineReadOnly(this, "_multiplier", getMultiplier(decimals));
this._multiplier = getMultiplier(decimals);
Object.freeze(this);
}
static from(value: any): FixedFormat {
@ -170,10 +170,6 @@ export class FixedFormat {
return new FixedFormat(_constructorGuard, signed, width, decimals);
}
static isInstance(value: any): value is FixedFormat {
return isNamedInstance(this, value);
}
}
export class FixedNumber {
@ -181,13 +177,19 @@ export class FixedNumber {
readonly _hex: string;
readonly _value: string;
readonly _isFixedNumber: boolean;
constructor(constructorGuard: any, hex: string, value: string, format?: FixedFormat) {
errors.checkNew(new.target, FixedNumber);
defineReadOnly(this, 'format', format);
defineReadOnly(this, '_hex', hex);
defineReadOnly(this, '_value', value);
}
this.format = format;
this._hex = hex;
this._value = value;
this._isFixedNumber = true;
Object.freeze(this);
}
_checkFormat(other: FixedNumber): void {
if (this.format.name !== other.format.name) {
@ -261,7 +263,7 @@ export class FixedNumber {
static fromValue(value: BigNumber, decimals?: BigNumberish, format?: FixedFormat | string): FixedNumber {
// If decimals looks more like a format, and there is no format, shift the parameters
if (format == null && decimals != null && (FixedFormat.isInstance(decimals) || typeof(decimals) === "string")) {
if (format == null && decimals != null && !isBigNumberish(decimals)) {
format = decimals;
decimals = null;
}
@ -269,15 +271,14 @@ export class FixedNumber {
if (decimals == null) { decimals = 0; }
if (format == null) { format = "fixed"; }
let fixedFormat = (FixedFormat.isInstance(format) ? format: FixedFormat.from(format));
return FixedNumber.fromString(formatFixed(value, decimals), fixedFormat);
return FixedNumber.fromString(formatFixed(value, decimals), FixedFormat.from(format));
}
static fromString(value: string, format?: FixedFormat | string): FixedNumber {
if (format == null) { format = "fixed"; }
let fixedFormat = (FixedFormat.isInstance(format) ? format: FixedFormat.from(format));
let fixedFormat = FixedFormat.from(format);
let numeric = parseFixed(value, fixedFormat.decimals);
@ -301,7 +302,7 @@ export class FixedNumber {
static fromBytes(value: BytesLike, format?: FixedFormat | string): FixedNumber {
if (format == null) { format = "fixed"; }
let fixedFormat = (FixedFormat.isInstance(format) ? format: FixedFormat.from(format));
let fixedFormat = FixedFormat.from(format);
if (arrayify(value).length > fixedFormat.width / 8) {
throw new Error("overflow");
@ -338,6 +339,6 @@ export class FixedNumber {
}
static isFixedNumber(value: any): value is FixedNumber {
return isNamedInstance<FixedNumber>(this, value);
return !!(value && value._isFixedNumber);
}
}

View File

@ -8,7 +8,7 @@ import { BigNumber, BigNumberish } from "@ethersproject/bignumber";
import { BytesLike, concat, hexlify, isBytes, isHexString } from "@ethersproject/bytes";
import { Zero } from "@ethersproject/constants";
import * as errors from "@ethersproject/errors";
import { defineReadOnly, deepCopy, isNamedInstance, resolveProperties, shallowCopy } from "@ethersproject/properties";
import { defineReadOnly, deepCopy, resolveProperties, shallowCopy } from "@ethersproject/properties";
import { UnsignedTransaction } from "@ethersproject/transactions";
@ -440,10 +440,10 @@ export class Contract {
defineReadOnly(this, "interface", new.target.getInterface(contractInterface));
if (isNamedInstance<Signer>(Signer, signerOrProvider)) {
defineReadOnly(this, "provider", signerOrProvider.provider);
if (Signer.isSigner(signerOrProvider)) {
defineReadOnly(this, "provider", signerOrProvider.provider || null);
defineReadOnly(this, "signer", signerOrProvider);
} else if (isNamedInstance<Provider>(Provider, signerOrProvider)) {
} else if (Provider.isProvider(signerOrProvider)) {
defineReadOnly(this, "provider", signerOrProvider);
defineReadOnly(this, "signer", null);
} else {
@ -518,7 +518,7 @@ export class Contract {
}
static getInterface(contractInterface: ContractInterface): Interface {
if (isNamedInstance<Interface>(Interface, contractInterface)) {
if (Interface.isInterface(contractInterface)) {
return contractInterface;
}
return new Interface(contractInterface);
@ -601,7 +601,7 @@ export class Contract {
}
static isIndexed(value: any): value is Indexed {
return isNamedInstance<Indexed>(Indexed, value);
return Indexed.isIndexed(value);
}
private _normalizeRunningEvent(runningEvent: RunningEvent): RunningEvent {
@ -845,7 +845,7 @@ export class ContractFactory {
}
// If we have a signer, make sure it is valid
if (signer && !isNamedInstance<Signer>(Signer, signer)) {
if (signer && !Signer.isSigner(signer)) {
errors.throwArgumentError("invalid signer", "signer", signer);
}

View File

@ -19,8 +19,10 @@ export class CrowdsaleAccount extends Description implements ExternallyOwnedAcco
readonly mnemonic?: string;
readonly path?: string;
isType(value: any): value is CrowdsaleAccount {
return Description.isType(value);
readonly _isCrowdsaleAccount: boolean;
isCrowdsaleAccount(value: any): value is CrowdsaleAccount {
return !!(value && value._isCrowdsaleAccount);
}
}
@ -63,6 +65,7 @@ export function decrypt(json: string, password: Bytes | string): ExternallyOwned
let privateKey = keccak256(seedHexBytes);
return new CrowdsaleAccount ({
_isCrowdsaleAccount: true,
address: ethaddr,
privateKey: privateKey
});

View File

@ -24,8 +24,10 @@ export class KeystoreAccount extends Description implements ExternallyOwnedAccou
readonly mnemonic?: string;
readonly path?: string;
isType(value: any): value is KeystoreAccount {
return Description.isType(value);
readonly _isKeystoreAccount: boolean;
isKeystoreAccount(value: any): value is KeystoreAccount {
return !!(value && value._isKeystoreAccount);
}
}
@ -95,6 +97,7 @@ export function decrypt(json: string, password: Bytes | string, progressCallback
} catch (e) { }
let account: any = {
_isKeystoreAccount: true,
address: address,
privateKey: hexlify(privateKey)
};

View File

@ -10,47 +10,6 @@ export function defineReadOnly(object: any, name: string, value: any): void {
});
}
// There are some issues with instanceof with npm link, so we use this
// to ensure types are what we expect. We use this for a little extra
// protection to make sure the correct types are being passed around.
function getType(object: any) {
let type = typeof(object);
if (type !== "function") { return null; }
let types = [ ];
let obj = object;
while (true) {
let type = obj.name;
if (!type) { break; }
types.push(type);
obj = Object.getPrototypeOf(obj);
}
return types.join(" ");
}
function hasSuffix(text: string, suffix: string) {
return text.substring(text.length - suffix.length) === suffix;
}
export function isNamedInstance<T>(type: Function | string, value: any): value is T {
let name = getType(type);
if (!name) { return false; }
// Not a string...
if (typeof(value) !== "string") {
// Not an instance...
if (typeof(value) !== "object") { return false; }
// Get the instance type
value = getType(value.constructor);
}
return (name === value || hasSuffix(value, " " + name));
}
export function resolveProperties(object: any): Promise<any> {
let result: any = {};
@ -115,10 +74,8 @@ export function deepCopy(object: any, frozen?: boolean): any {
if (typeof(object) === "object") {
// Some internal objects, which are already immutable
if (isNamedInstance("BigNumber", object)) { return object; }
if (isNamedInstance("Description", object)) { return object; }
if (isNamedInstance("Indexed", object)) { return object; }
// Immutable objects are safe to just use
if (Object.isFrozen(object)) { return object; }
let result: { [ key: string ]: any } = {};
for (let key in object) {
@ -147,8 +104,4 @@ export class Description {
}
Object.freeze(this);
}
static isType(value: any): boolean {
return isNamedInstance(this, value);
}
}

View File

@ -9,7 +9,7 @@ import { arrayify, hexDataLength, hexlify, hexValue, isHexString } from "@ethers
import * as errors from "@ethersproject/errors";
import { namehash } from "@ethersproject/hash";
import { getNetwork, Network, Networkish } from "@ethersproject/networks";
import { defineReadOnly, isNamedInstance, resolveProperties } from "@ethersproject/properties";
import { defineReadOnly, resolveProperties } from "@ethersproject/properties";
import { Transaction } from "@ethersproject/transactions";
import { toUtf8String } from "@ethersproject/strings";
import { poll } from "@ethersproject/web";
@ -77,7 +77,7 @@ function getEventTag(eventName: EventType): string {
} else if (Array.isArray(eventName)) {
return "filter:*:" + serializeTopics(eventName);
} else if (isNamedInstance<ForkEvent>(ForkEvent, eventName)) {
} else if (ForkEvent.isForkEvent(eventName)) {
errors.warn("not implemented");
throw new Error("not implemented");

View File

@ -22,7 +22,9 @@ export class SigningKey {
readonly publicKey: string;
readonly compressedPublicKey: string;
readonly address: string;
//readonly address: string;
readonly _isSigningKey: boolean;
constructor(privateKey: BytesLike) {
defineReadOnly(this, "curve", "secp256k1");
@ -33,6 +35,8 @@ export class SigningKey {
defineReadOnly(this, "publicKey", "0x" + keyPair.getPublic(false, "hex"));
defineReadOnly(this, "compressedPublicKey", "0x" + keyPair.getPublic(true, "hex"));
defineReadOnly(this, "_isSigningKey", true);
}
_addPoint(other: BytesLike): string {
@ -56,6 +60,10 @@ export class SigningKey {
let otherKeyPair = getCurve().keyFromPublic(arrayify(computePublicKey(otherKey)));
return hexZeroPad("0x" + keyPair.derive(otherKeyPair.getPublic()).toString(16), 32);
}
static isSigningKey(value: any): value is SigningKey {
return !!(value && value._isSigningKey);
}
}
export function recoverPublicKey(digest: BytesLike, signature: SignatureLike): string {

View File

@ -8,7 +8,7 @@ import * as errors from "@ethersproject/errors";
import { hashMessage } from "@ethersproject/hash";
import { defaultPath, HDNode, entropyToMnemonic } from "@ethersproject/hdnode";
import { keccak256 } from "@ethersproject/keccak256";
import { defineReadOnly, isNamedInstance, resolveProperties } from "@ethersproject/properties";
import { defineReadOnly, resolveProperties } from "@ethersproject/properties";
import { randomBytes } from "@ethersproject/random";
import { SigningKey } from "@ethersproject/signing-key";
import { decryptJsonWallet, encryptKeystore, ProgressCallback } from "@ethersproject/json-wallets";
@ -61,7 +61,10 @@ export class Wallet extends Signer implements ExternallyOwnedAccount {
} else {
if (isNamedInstance<SigningKey>(SigningKey, privateKey)) {
if (SigningKey.isSigningKey(privateKey)) {
if (privateKey.curve !== "secp256k1") {
errors.throwArgumentError("unsupported curve; must be secp256k1", "privateKey", "[REDACTED]");
}
defineReadOnly(this, "_signingKey", () => privateKey);
} else {
let signingKey = new SigningKey(privateKey);
@ -72,7 +75,7 @@ export class Wallet extends Signer implements ExternallyOwnedAccount {
defineReadOnly(this, "address", computeAddress(this.publicKey));
}
if (provider && !isNamedInstance<Provider>(Provider, provider)) {
if (provider && !Provider.isProvider(provider)) {
errors.throwError("invalid provider", errors.INVALID_ARGUMENT, {
argument: "provider",
value: provider