Refactor Wallet and HDNodeWallet structure.
This commit is contained in:
parent
bbc488a472
commit
1e56d5044e
@ -6,11 +6,18 @@ import {
|
||||
defineProperties, resolveProperties, assert, assertArgument
|
||||
} from "../utils/index.js";
|
||||
|
||||
import {
|
||||
encryptKeystoreJson, encryptKeystoreJsonSync,
|
||||
} from "./json-keystore.js";
|
||||
|
||||
import type { SigningKey } from "../crypto/index.js";
|
||||
import type { TypedDataDomain, TypedDataField } from "../hash/index.js";
|
||||
import type { Provider, TransactionRequest } from "../providers/index.js";
|
||||
import type { TransactionLike } from "../transaction/index.js";
|
||||
|
||||
import type { ProgressCallback } from "../crypto/index.js";
|
||||
|
||||
|
||||
export class BaseWallet extends AbstractSigner {
|
||||
readonly address!: string;
|
||||
|
||||
@ -34,6 +41,16 @@ export class BaseWallet extends AbstractSigner {
|
||||
return new BaseWallet(this.#signingKey, provider);
|
||||
}
|
||||
|
||||
async encrypt(password: Uint8Array | string, progressCallback?: ProgressCallback): Promise<string> {
|
||||
const account = { address: this.address, privateKey: this.privateKey };
|
||||
return await encryptKeystoreJson(account, password, { progressCallback });
|
||||
}
|
||||
|
||||
encryptSync(password: Uint8Array | string): string {
|
||||
const account = { address: this.address, privateKey: this.privateKey };
|
||||
return encryptKeystoreJsonSync(account, password);
|
||||
}
|
||||
|
||||
async signTransaction(tx: TransactionRequest): Promise<string> {
|
||||
|
||||
// Replace any Addressable or ENS name with an address
|
||||
@ -72,6 +89,9 @@ export class BaseWallet extends AbstractSigner {
|
||||
|
||||
// Populate any ENS names
|
||||
const populated = await TypedDataEncoder.resolveNames(domain, types, value, async (name: string) => {
|
||||
// @TODO: this should use resolveName; addresses don't
|
||||
// need a provider
|
||||
|
||||
assert(this.provider != null, "cannot resolve ENS names without a provider", "UNSUPPORTED_OPERATION", {
|
||||
operation: "resolveName",
|
||||
info: { name }
|
||||
|
@ -194,21 +194,6 @@ export class HDNodeWallet extends BaseWallet {
|
||||
"m", 0, 0, mnemonic, null);
|
||||
}
|
||||
|
||||
static fromSeed(seed: BytesLike): HDNodeWallet {
|
||||
return HDNodeWallet.#fromSeed(seed, null);
|
||||
}
|
||||
|
||||
static fromPhrase(phrase: string, password: string = "", path: null | string = defaultPath, wordlist: Wordlist = langEn): HDNodeWallet {
|
||||
if (!path) { path = defaultPath; }
|
||||
const mnemonic = Mnemonic.fromPhrase(phrase, password, wordlist)
|
||||
return HDNodeWallet.#fromSeed(mnemonic.computeSeed(), mnemonic).derivePath(path);
|
||||
}
|
||||
|
||||
static fromMnemonic(mnemonic: Mnemonic, path: null | string = defaultPath): HDNodeWallet {
|
||||
if (!path) { path = defaultPath; }
|
||||
return HDNodeWallet.#fromSeed(mnemonic.computeSeed(), mnemonic).derivePath(path);
|
||||
}
|
||||
|
||||
static fromExtendedKey(extendedKey: string): HDNodeWallet | HDNodeVoidWallet {
|
||||
const bytes = getBytes(decodeBase58(extendedKey)); // @TODO: redact
|
||||
|
||||
@ -240,11 +225,30 @@ export class HDNodeWallet extends BaseWallet {
|
||||
assertArgument(false, "invalid extended key prefix", "extendedKey", "[ REDACTED ]");
|
||||
}
|
||||
|
||||
static createRandom(password: string = "", path: null | string = defaultPath, wordlist: Wordlist = langEn): HDNodeWallet {
|
||||
if (!path) { path = defaultPath; }
|
||||
static createRandom(password?: string, path?: string, wordlist?: Wordlist): HDNodeWallet {
|
||||
if (password == null) { password = ""; }
|
||||
if (path == null) { path = defaultPath; }
|
||||
if (wordlist == null) { wordlist = langEn; }
|
||||
const mnemonic = Mnemonic.fromEntropy(randomBytes(16), password, wordlist)
|
||||
return HDNodeWallet.#fromSeed(mnemonic.computeSeed(), mnemonic).derivePath(path);
|
||||
}
|
||||
|
||||
static fromMnemonic(mnemonic: Mnemonic, path?: string): HDNodeWallet {
|
||||
if (!path) { path = defaultPath; }
|
||||
return HDNodeWallet.#fromSeed(mnemonic.computeSeed(), mnemonic).derivePath(path);
|
||||
}
|
||||
|
||||
static fromPhrase(phrase: string, password?: string, path?: string, wordlist?: Wordlist): HDNodeWallet {
|
||||
if (password == null) { password = ""; }
|
||||
if (path == null) { path = defaultPath; }
|
||||
if (wordlist == null) { wordlist = langEn; }
|
||||
const mnemonic = Mnemonic.fromPhrase(phrase, password, wordlist)
|
||||
return HDNodeWallet.#fromSeed(mnemonic.computeSeed(), mnemonic).derivePath(path);
|
||||
}
|
||||
|
||||
static fromSeed(seed: BytesLike): HDNodeWallet {
|
||||
return HDNodeWallet.#fromSeed(seed, null);
|
||||
}
|
||||
}
|
||||
|
||||
export class HDNodeVoidWallet extends VoidSigner {
|
||||
|
@ -23,6 +23,5 @@ export { Wallet } from "./wallet.js";
|
||||
|
||||
export type { CrowdsaleAccount } from "./json-crowdsale.js";
|
||||
export type {
|
||||
KeystoreAccountParams, KeystoreAccount,
|
||||
EncryptOptions
|
||||
KeystoreAccount, EncryptOptions
|
||||
} from "./json-keystore.js"
|
||||
|
@ -14,30 +14,22 @@ import type { BytesLike } from "../utils/index.js";
|
||||
|
||||
import { version } from "../_version.js";
|
||||
|
||||
|
||||
const defaultPath = "m/44'/60'/0'/0/0";
|
||||
|
||||
|
||||
export type KeystoreAccountParams = {
|
||||
privateKey: string;
|
||||
address?: string;
|
||||
mnemonic?: {
|
||||
entropy: string;
|
||||
path: string;
|
||||
locale: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type KeystoreAccount = {
|
||||
address: string;
|
||||
privateKey: string;
|
||||
mnemonic?: {
|
||||
path?: string;
|
||||
locale?: string;
|
||||
entropy: string;
|
||||
path: string;
|
||||
locale: string;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export type EncryptOptions = {
|
||||
progressCallback?: ProgressCallback;
|
||||
iv?: BytesLike;
|
||||
entropy?: BytesLike;
|
||||
client?: string;
|
||||
@ -112,14 +104,16 @@ function getAccount(data: any, _key: string): KeystoreAccount {
|
||||
return account;
|
||||
}
|
||||
|
||||
type KdfParams = {
|
||||
type ScryptParams = {
|
||||
name: "scrypt";
|
||||
salt: Uint8Array;
|
||||
N: number;
|
||||
r: number;
|
||||
p: number;
|
||||
dkLen: number;
|
||||
} | {
|
||||
};
|
||||
|
||||
type KdfParams = ScryptParams | {
|
||||
name: "pbkdf2";
|
||||
salt: Uint8Array;
|
||||
count: number;
|
||||
@ -127,7 +121,7 @@ type KdfParams = {
|
||||
algorithm: "sha256" | "sha512";
|
||||
};
|
||||
|
||||
function getKdfParams<T>(data: any): KdfParams {
|
||||
function getDecryptKdfParams<T>(data: any): KdfParams {
|
||||
const kdf = spelunk(data, "crypto.kdf:string");
|
||||
if (kdf && typeof(kdf) === "string") {
|
||||
const throwError = function(name: string, value: any): never {
|
||||
@ -179,18 +173,18 @@ export function decryptKeystoreJsonSync(json: string, _password: string | Uint8A
|
||||
|
||||
const password = getPassword(_password);
|
||||
|
||||
const params = getKdfParams(data);
|
||||
const params = getDecryptKdfParams(data);
|
||||
if (params.name === "pbkdf2") {
|
||||
const { salt, count, dkLen, algorithm } = params;
|
||||
const key = pbkdf2(password, salt, count, dkLen, algorithm);
|
||||
return getAccount(data, key);
|
||||
} else if (params.name === "scrypt") {
|
||||
const { salt, N, r, p, dkLen } = params;
|
||||
const key = scryptSync(password, salt, N, r, p, dkLen);
|
||||
return getAccount(data, key);
|
||||
}
|
||||
|
||||
throw new Error("unreachable");
|
||||
assert(params.name === "scrypt", "cannot be reached", "UNKNOWN_ERROR", { params })
|
||||
|
||||
const { salt, N, r, p, dkLen } = params;
|
||||
const key = scryptSync(password, salt, N, r, p, dkLen);
|
||||
return getAccount(data, key);
|
||||
}
|
||||
|
||||
function stall(duration: number): Promise<void> {
|
||||
@ -202,7 +196,7 @@ export async function decryptKeystoreJson(json: string, _password: string | Uint
|
||||
|
||||
const password = getPassword(_password);
|
||||
|
||||
const params = getKdfParams(data);
|
||||
const params = getDecryptKdfParams(data);
|
||||
if (params.name === "pbkdf2") {
|
||||
if (progress) {
|
||||
progress(0);
|
||||
@ -215,69 +209,18 @@ export async function decryptKeystoreJson(json: string, _password: string | Uint
|
||||
await stall(0);
|
||||
}
|
||||
return getAccount(data, key);
|
||||
} else if (params.name === "scrypt") {
|
||||
const { salt, N, r, p, dkLen } = params;
|
||||
const key = await scrypt(password, salt, N, r, p, dkLen, progress);
|
||||
return getAccount(data, key);
|
||||
}
|
||||
|
||||
throw new Error("unreachable");
|
||||
assert(params.name === "scrypt", "cannot be reached", "UNKNOWN_ERROR", { params })
|
||||
|
||||
const { salt, N, r, p, dkLen } = params;
|
||||
const key = await scrypt(password, salt, N, r, p, dkLen, progress);
|
||||
return getAccount(data, key);
|
||||
}
|
||||
|
||||
|
||||
export async function encryptKeystoreJson(account: KeystoreAccount, password: string | Uint8Array, options?: EncryptOptions, progressCallback?: ProgressCallback): Promise<string> {
|
||||
|
||||
// Check the address matches the private key
|
||||
//if (getAddress(account.address) !== computeAddress(account.privateKey)) {
|
||||
// throw new Error("address/privateKey mismatch");
|
||||
//}
|
||||
|
||||
// Check the mnemonic (if any) matches the private key
|
||||
/*
|
||||
if (hasMnemonic(account)) {
|
||||
const mnemonic = account.mnemonic;
|
||||
const node = HDNode.fromMnemonic(mnemonic.phrase, null, mnemonic.locale).derivePath(mnemonic.path || defaultPath);
|
||||
|
||||
if (node.privateKey != account.privateKey) {
|
||||
throw new Error("mnemonic mismatch");
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// The options are optional, so adjust the call as needed
|
||||
if (typeof(options) === "function" && !progressCallback) {
|
||||
progressCallback = options;
|
||||
options = {};
|
||||
}
|
||||
if (!options) { options = {}; }
|
||||
|
||||
const privateKey = getBytes(account.privateKey, "privateKey");
|
||||
const passwordBytes = getPassword(password);
|
||||
|
||||
/*
|
||||
let mnemonic: null | Mnemonic = null;
|
||||
let entropy: Uint8Array = null
|
||||
let path: string = null;
|
||||
let locale: string = null;
|
||||
if (hasMnemonic(account)) {
|
||||
const srcMnemonic = account.mnemonic;
|
||||
entropy = arrayify(mnemonicToEntropy(srcMnemonic.phrase, srcMnemonic.locale || "en"));
|
||||
path = srcMnemonic.path || defaultPath;
|
||||
locale = srcMnemonic.locale || "en";
|
||||
mnemonic = Mnemonic.from(
|
||||
}
|
||||
*/
|
||||
function getEncryptKdfParams(options: EncryptOptions): ScryptParams {
|
||||
// Check/generate the salt
|
||||
const salt = (options.salt != null) ? getBytes(options.salt, "options.slat"): randomBytes(32);
|
||||
|
||||
// Override initialization vector
|
||||
const iv = (options.iv != null) ? getBytes(options.iv, "options.iv"): randomBytes(16);
|
||||
assertArgument(iv.length === 16, "invalid options.iv", "options.iv", options.iv);
|
||||
|
||||
// Override the uuid
|
||||
const uuidRandom = (options.uuid != null) ? getBytes(options.uuid, "options.uuid"): randomBytes(16);
|
||||
assertArgument(uuidRandom.length === 16, "invalid options.uuid", "options.uuid", options.iv);
|
||||
if (uuidRandom.length !== 16) { throw new Error("invalid uuid"); }
|
||||
const salt = (options.salt != null) ? getBytes(options.salt, "options.salt"): randomBytes(32);
|
||||
|
||||
// Override the scrypt password-based key derivation function parameters
|
||||
let N = (1 << 17), r = 8, p = 1;
|
||||
@ -286,14 +229,28 @@ export async function encryptKeystoreJson(account: KeystoreAccount, password: st
|
||||
if (options.scrypt.r) { r = options.scrypt.r; }
|
||||
if (options.scrypt.p) { p = options.scrypt.p; }
|
||||
}
|
||||
assertArgument(typeof(N) === "number" && Number.isSafeInteger(N) && (BigInt(N) & BigInt(N - 1)) === BigInt(0), "invalid scrypt N parameter", "options.N", N);
|
||||
assertArgument(typeof(r) === "number" && Number.isSafeInteger(r), "invalid scrypt r parameter", "options.r", r);
|
||||
assertArgument(typeof(p) === "number" && Number.isSafeInteger(p), "invalid scrypt p parameter", "options.p", p);
|
||||
|
||||
// We take 64 bytes:
|
||||
// - 32 bytes As normal for the Web3 secret storage (derivedKey, macPrefix)
|
||||
// - 32 bytes AES key to encrypt mnemonic with (required here to be Ethers Wallet)
|
||||
const _key = await scrypt(passwordBytes, salt, N, r, p, 64, progressCallback);
|
||||
const key = getBytes(_key);
|
||||
return { name: "scrypt", dkLen: 32, salt, N, r, p };
|
||||
}
|
||||
|
||||
export function _encryptKeystore(key: Uint8Array, kdf: ScryptParams, account: KeystoreAccount, options: EncryptOptions): any {
|
||||
|
||||
const privateKey = getBytes(account.privateKey, "privateKey");
|
||||
|
||||
// Override initialization vector
|
||||
const iv = (options.iv != null) ? getBytes(options.iv, "options.iv"): randomBytes(16);
|
||||
assertArgument(iv.length === 16, "invalid options.iv", "options.iv", options.iv);
|
||||
|
||||
// Override the uuid
|
||||
const uuidRandom = (options.uuid != null) ? getBytes(options.uuid, "options.uuid"): randomBytes(16);
|
||||
assertArgument(uuidRandom.length === 16, "invalid options.uuid", "options.uuid", options.iv);
|
||||
|
||||
// This will be used to encrypt the wallet (as per Web3 secret storage)
|
||||
// - 32 bytes As normal for the Web3 secret storage (derivedKey, macPrefix)
|
||||
// - 32 bytes AES key to encrypt mnemonic with (required here to be Ethers Wallet)
|
||||
const derivedKey = key.slice(0, 16);
|
||||
const macPrefix = key.slice(16, 32);
|
||||
|
||||
@ -317,11 +274,11 @@ export async function encryptKeystoreJson(account: KeystoreAccount, password: st
|
||||
ciphertext: hexlify(ciphertext).substring(2),
|
||||
kdf: "scrypt",
|
||||
kdfparams: {
|
||||
salt: hexlify(salt).substring(2),
|
||||
n: N,
|
||||
salt: hexlify(kdf.salt).substring(2),
|
||||
n: kdf.N,
|
||||
dklen: 32,
|
||||
p: p,
|
||||
r: r
|
||||
p: kdf.p,
|
||||
r: kdf.r
|
||||
},
|
||||
mac: mac.substring(2)
|
||||
}
|
||||
@ -360,3 +317,22 @@ export async function encryptKeystoreJson(account: KeystoreAccount, password: st
|
||||
|
||||
return JSON.stringify(data);
|
||||
}
|
||||
|
||||
export function encryptKeystoreJsonSync(account: KeystoreAccount, password: string | Uint8Array, options?: EncryptOptions): string {
|
||||
if (options == null) { options = { }; }
|
||||
|
||||
const passwordBytes = getPassword(password);
|
||||
const kdf = getEncryptKdfParams(options);
|
||||
const key = scryptSync(passwordBytes, kdf.salt, kdf.N, kdf.r, kdf.p, 64);
|
||||
return _encryptKeystore(getBytes(key), kdf, account, options);
|
||||
}
|
||||
|
||||
export async function encryptKeystoreJson(account: KeystoreAccount, password: string | Uint8Array, options?: EncryptOptions): Promise<string> {
|
||||
if (options == null) { options = { }; }
|
||||
|
||||
const passwordBytes = getPassword(password);
|
||||
const kdf = getEncryptKdfParams(options);
|
||||
const key = await scrypt(passwordBytes, kdf.salt, kdf.N, kdf.r, kdf.p, 64, options.progressCallback);
|
||||
return _encryptKeystore(getBytes(key), kdf, account, options);
|
||||
}
|
||||
|
||||
|
@ -1,116 +1,58 @@
|
||||
import { randomBytes, SigningKey } from "../crypto/index.js";
|
||||
import { computeAddress } from "../transaction/index.js";
|
||||
import { isHexString, assertArgument } from "../utils/index.js";
|
||||
import { SigningKey } from "../crypto/index.js";
|
||||
import { assertArgument } from "../utils/index.js";
|
||||
|
||||
import { BaseWallet } from "./base-wallet.js";
|
||||
import { HDNodeWallet } from "./hdwallet.js";
|
||||
import { decryptCrowdsaleJson, isCrowdsaleJson } from "./json-crowdsale.js";
|
||||
import {
|
||||
decryptKeystoreJson, decryptKeystoreJsonSync, isKeystoreJson
|
||||
decryptKeystoreJson, decryptKeystoreJsonSync,
|
||||
isKeystoreJson
|
||||
} from "./json-keystore.js";
|
||||
import { Mnemonic } from "./mnemonic.js";
|
||||
|
||||
import type { ProgressCallback } from "../crypto/index.js";
|
||||
import type { Provider } from "../providers/index.js";
|
||||
import type { Wordlist } from "../wordlists/index.js";
|
||||
|
||||
import type { CrowdsaleAccount } from "./json-crowdsale.js";
|
||||
import type { KeystoreAccount } from "./json-keystore.js";
|
||||
|
||||
|
||||
function tryWallet(value: any): null | Wallet {
|
||||
try {
|
||||
if (!value || !value.signingKey) { return null; }
|
||||
const key = trySigningKey(value.signingKey);
|
||||
if (key == null || computeAddress(key.publicKey) !== value.address) { return null; }
|
||||
if (value.mnemonic) {
|
||||
const wallet = HDNodeWallet.fromMnemonic(value.mnemonic);
|
||||
if (wallet.privateKey !== key.privateKey) { return null; }
|
||||
}
|
||||
return value;
|
||||
} catch (e) { console.log(e); }
|
||||
return null;
|
||||
}
|
||||
|
||||
// Try using value as mnemonic to derive the defaultPath HDodeWallet
|
||||
function tryMnemonic(value: any): null | HDNodeWallet {
|
||||
try {
|
||||
if (value == null || typeof(value.phrase) !== "string" ||
|
||||
typeof(value.password) !== "string" ||
|
||||
value.wordlist == null) { return null; }
|
||||
return HDNodeWallet.fromPhrase(value.phrase, value.password, null, value.wordlist);
|
||||
} catch (error) { console.log(error); }
|
||||
return null;
|
||||
}
|
||||
|
||||
function trySigningKey(value: any): null | SigningKey {
|
||||
try {
|
||||
if (!value || !isHexString(value.privateKey, 32)) { return null; }
|
||||
|
||||
const key = value.privateKey;
|
||||
if (SigningKey.computePublicKey(key) !== value.publicKey) { return null; }
|
||||
return new SigningKey(key);
|
||||
} catch (e) { console.log(e); }
|
||||
return null;
|
||||
}
|
||||
|
||||
function stall(duration: number): Promise<void> {
|
||||
return new Promise((resolve) => { setTimeout(() => { resolve(); }, duration); });
|
||||
}
|
||||
|
||||
export class Wallet extends BaseWallet {
|
||||
readonly #mnemonic: null | Mnemonic;
|
||||
|
||||
constructor(key: string | Mnemonic | SigningKey | BaseWallet, provider?: null | Provider) {
|
||||
let signingKey: null | SigningKey = null;
|
||||
let mnemonic: null | Mnemonic = null;
|
||||
|
||||
// A normal private key
|
||||
if (typeof(key) === "string") { signingKey = new SigningKey(key); }
|
||||
|
||||
// Try Wallet
|
||||
if (signingKey == null) {
|
||||
const wallet = tryWallet(key);
|
||||
if (wallet) {
|
||||
signingKey = wallet.signingKey;
|
||||
mnemonic = wallet.mnemonic || null;
|
||||
}
|
||||
}
|
||||
|
||||
// Try Mnemonic, with the defaultPath wallet
|
||||
if (signingKey == null) {
|
||||
const wallet = tryMnemonic(key);
|
||||
if (wallet) {
|
||||
signingKey = wallet.signingKey;
|
||||
mnemonic = wallet.mnemonic || null;
|
||||
}
|
||||
}
|
||||
|
||||
// A signing key
|
||||
if (signingKey == null) { signingKey = trySigningKey(key); }
|
||||
|
||||
assertArgument(signingKey != null, "invalid key", "key", "[ REDACTED ]");
|
||||
|
||||
super(signingKey as SigningKey, provider);
|
||||
this.#mnemonic = mnemonic;
|
||||
constructor(key: string | SigningKey, provider?: null | Provider) {
|
||||
let signingKey = (typeof(key) === "string") ? new SigningKey(key): key;
|
||||
super(signingKey, provider);
|
||||
}
|
||||
|
||||
// Store this in a getter to reduce visibility in console.log
|
||||
get mnemonic(): null | Mnemonic { return this.#mnemonic; }
|
||||
|
||||
connect(provider: null | Provider): Wallet {
|
||||
return new Wallet(this, provider);
|
||||
return new Wallet(this.signingKey, provider);
|
||||
}
|
||||
|
||||
async encrypt(password: Uint8Array | string, options?: any, progressCallback?: ProgressCallback): Promise<string> {
|
||||
throw new Error("TODO");
|
||||
static #fromAccount(account: null | CrowdsaleAccount | KeystoreAccount): HDNodeWallet | Wallet {
|
||||
assertArgument(account, "invalid JSON wallet", "json", "[ REDACTED ]");
|
||||
|
||||
if ("mnemonic" in account && account.mnemonic && account.mnemonic.locale === "en") {
|
||||
const mnemonic = Mnemonic.fromEntropy(account.mnemonic.entropy);
|
||||
const wallet = HDNodeWallet.fromMnemonic(mnemonic, account.mnemonic.path);
|
||||
if (wallet.address === account.address && wallet.privateKey === account.privateKey) {
|
||||
return wallet;
|
||||
}
|
||||
console.log("WARNING: JSON mismatch address/privateKey != mnemonic; fallback onto private key");
|
||||
}
|
||||
|
||||
const wallet = new Wallet(account.privateKey);
|
||||
|
||||
assertArgument(wallet.address === account.address,
|
||||
"address/privateKey mismatch", "json", "[ REDACTED ]");
|
||||
|
||||
return wallet;
|
||||
}
|
||||
|
||||
encryptSync(password: Uint8Array | string, options?: any): Promise<string> {
|
||||
throw new Error("TODO");
|
||||
}
|
||||
|
||||
static async fromEncryptedJson(json: string, password: Uint8Array | string, progress?: ProgressCallback): Promise<Wallet> {
|
||||
static async fromEncryptedJson(json: string, password: Uint8Array | string, progress?: ProgressCallback): Promise<HDNodeWallet | Wallet> {
|
||||
let account: null | CrowdsaleAccount | KeystoreAccount = null;
|
||||
if (isKeystoreJson(json)) {
|
||||
account = await decryptKeystoreJson(json, password, progress);
|
||||
@ -120,15 +62,9 @@ export class Wallet extends BaseWallet {
|
||||
account = decryptCrowdsaleJson(json, password);
|
||||
if (progress) { progress(1); await stall(0); }
|
||||
|
||||
} else {
|
||||
assertArgument(false, "invalid JSON wallet", "json", "[ REDACTED ]");
|
||||
}
|
||||
|
||||
const wallet = new Wallet(account.privateKey);
|
||||
assertArgument(wallet.address === account.address,
|
||||
"address/privateKey mismatch", "json", "[ REDACTED ]");
|
||||
// @TODO: mnemonic
|
||||
return wallet;
|
||||
return Wallet.#fromAccount(account);
|
||||
}
|
||||
|
||||
static fromEncryptedJsonSync(json: string, password: Uint8Array | string): Wallet {
|
||||
@ -141,23 +77,18 @@ export class Wallet extends BaseWallet {
|
||||
assertArgument(false, "invalid JSON wallet", "json", "[ REDACTED ]");
|
||||
}
|
||||
|
||||
const wallet = new Wallet(account.privateKey);
|
||||
assertArgument(wallet.address === account.address,
|
||||
"address/privateKey mismatch", "json", "[ REDACTED ]");
|
||||
// @TODO: mnemonic
|
||||
return Wallet.#fromAccount(account);
|
||||
}
|
||||
|
||||
static createRandom(provider?: null | Provider): HDNodeWallet {
|
||||
const wallet = HDNodeWallet.createRandom();
|
||||
if (provider) { return wallet.connect(provider); }
|
||||
return wallet;
|
||||
}
|
||||
|
||||
static createRandom(provider?: null | Provider, password?: null | string, wordlist?: null | Wordlist): Wallet {
|
||||
return new Wallet(Mnemonic.fromEntropy(randomBytes(16), password, wordlist), provider);
|
||||
}
|
||||
|
||||
static fromMnemonic(mnemonic: Mnemonic, provider?: null | Provider): Wallet {
|
||||
return new Wallet(mnemonic, provider);
|
||||
}
|
||||
|
||||
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);
|
||||
static fromPhrase(phrase: string, provider?: Provider): HDNodeWallet {
|
||||
const wallet = HDNodeWallet.fromPhrase(phrase);
|
||||
if (provider) { return wallet.connect(provider); }
|
||||
return wallet;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user