ethers.js/src.ts/wallet/wallet.ts

133 lines
5.1 KiB
TypeScript
Raw Normal View History

import { SigningKey } from "../crypto/index.js";
import { assertArgument } from "../utils/index.js";
2022-09-05 23:14:43 +03:00
import { BaseWallet } from "./base-wallet.js";
import { HDNodeWallet } from "./hdwallet.js";
import { decryptCrowdsaleJson, isCrowdsaleJson } from "./json-crowdsale.js";
import {
decryptKeystoreJson, decryptKeystoreJsonSync,
2022-11-28 05:49:24 +03:00
encryptKeystoreJson, encryptKeystoreJsonSync,
isKeystoreJson
2022-09-05 23:14:43 +03:00
} 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 { CrowdsaleAccount } from "./json-crowdsale.js";
import type { KeystoreAccount } from "./json-keystore.js";
function stall(duration: number): Promise<void> {
return new Promise((resolve) => { setTimeout(() => { resolve(); }, duration); });
}
2022-11-28 05:49:24 +03:00
/**
* A **Wallet** manages a single private key which is used to sign
* transactions, messages and other common payloads.
*
* This class is generally the main entry point for developers
* that wish to use a private key directly, as it can create
* instances from a large variety of common sources, including
* raw private key, [[link-bip-39]] mnemonics and encrypte JSON
* wallets.
*/
2022-09-05 23:14:43 +03:00
export class Wallet extends BaseWallet {
constructor(key: string | SigningKey, provider?: null | Provider) {
let signingKey = (typeof(key) === "string") ? new SigningKey(key): key;
super(signingKey, provider);
}
2022-09-05 23:14:43 +03:00
connect(provider: null | Provider): Wallet {
return new Wallet(this.signingKey, provider);
}
2022-09-05 23:14:43 +03:00
2022-11-28 05:49:24 +03:00
/**
* Resolves to a [JSON Keystore Wallet](json-wallets) encrypted with
* %%password%%.
*
* If %%progressCallback%% is specified, it will receive periodic
* updates as the encryption process progreses.
*/
async encrypt(password: Uint8Array | string, progressCallback?: ProgressCallback): Promise<string> {
const account = { address: this.address, privateKey: this.privateKey };
return await encryptKeystoreJson(account, password, { progressCallback });
}
/**
* Returns a [JSON Keystore Wallet](json-wallets) encryped with
* %%password%%.
*
* It is preferred to use the [async version](encrypt) instead,
* which allows a [[ProgressCallback]] to keep the user informed.
*
* This method will block the event loop (freezing all UI) until
* it is complete, which may be a non-trivial duration.
*/
encryptSync(password: Uint8Array | string): string {
const account = { address: this.address, privateKey: this.privateKey };
return encryptKeystoreJsonSync(account, password);
}
static #fromAccount(account: null | CrowdsaleAccount | KeystoreAccount): HDNodeWallet | Wallet {
assertArgument(account, "invalid JSON wallet", "json", "[ REDACTED ]");
2022-09-05 23:14:43 +03:00
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;
2022-09-05 23:14:43 +03:00
}
console.log("WARNING: JSON mismatch address/privateKey != mnemonic; fallback onto private key");
2022-09-05 23:14:43 +03:00
}
const wallet = new Wallet(account.privateKey);
2022-09-05 23:14:43 +03:00
assertArgument(wallet.address === account.address,
"address/privateKey mismatch", "json", "[ REDACTED ]");
2022-09-05 23:14:43 +03:00
return wallet;
2022-09-05 23:14:43 +03:00
}
static async fromEncryptedJson(json: string, password: Uint8Array | string, progress?: ProgressCallback): Promise<HDNodeWallet | Wallet> {
2022-09-05 23:14:43 +03:00
let account: null | CrowdsaleAccount | KeystoreAccount = null;
if (isKeystoreJson(json)) {
account = await decryptKeystoreJson(json, password, progress);
} else if (isCrowdsaleJson(json)) {
if (progress) { progress(0); await stall(0); }
account = decryptCrowdsaleJson(json, password);
if (progress) { progress(1); await stall(0); }
}
return Wallet.#fromAccount(account);
2022-09-05 23:14:43 +03:00
}
2022-11-28 05:49:24 +03:00
static fromEncryptedJsonSync(json: string, password: Uint8Array | string): HDNodeWallet | Wallet {
2022-09-05 23:14:43 +03:00
let account: null | CrowdsaleAccount | KeystoreAccount = null;
if (isKeystoreJson(json)) {
account = decryptKeystoreJsonSync(json, password);
} else if (isCrowdsaleJson(json)) {
account = decryptCrowdsaleJson(json, password);
} else {
assertArgument(false, "invalid JSON wallet", "json", "[ REDACTED ]");
2022-09-05 23:14:43 +03:00
}
return Wallet.#fromAccount(account);
2022-09-05 23:14:43 +03:00
}
static createRandom(provider?: null | Provider): HDNodeWallet {
const wallet = HDNodeWallet.createRandom();
if (provider) { return wallet.connect(provider); }
return wallet;
2022-09-05 23:14:43 +03:00
}
static fromPhrase(phrase: string, provider?: Provider): HDNodeWallet {
const wallet = HDNodeWallet.fromPhrase(phrase);
if (provider) { return wallet.connect(provider); }
return wallet;
2022-09-05 23:14:43 +03:00
}
}