UNPKG

minterjs-wallet

Version:
227 lines (196 loc) 5.42 kB
// @TODO remove some wordlists import * as bip39 from 'bip39'; import { HDKey as hdKey } from 'ethereum-cryptography/hdkey'; import { isValidPrivate, privateToPublic, publicToAddress } from 'ethereumjs-util/dist/account'; import { publicToString } from 'minterjs-util'; function assert(val, msg) { if (!val) { throw new Error(msg || 'Assertion failed'); } } /** * BIP39 Master seed from mnemonic phrase * @param mnemonic - 12 words * @return {Buffer} */ export function seedFromMnemonic(mnemonic) { return bip39.mnemonicToSeedSync(mnemonic); } /** * BIP39 Master seed from mnemonic phrase (async) * @param mnemonic - 12 words * @return {Promise<Buffer>} */ export function seedFromMnemonicAsync(mnemonic) { return bip39.mnemonicToSeed(mnemonic); } /** * @typedef {{purpose?: number, coin?: number, account?: number, change?: number, index?: number}} HDKeyPathObject */ /** * @typedef {string|HDKeyPathObject} HDKeyPath */ /** * BIP44 HD key from master seed * https://en.bitcoin.it/wiki/BIP_0044 * @param {Buffer} seed - 64 bytes * @param {HDKeyPath} [path] - Ethereum path by default "m/44'/60'/0'/0/0" * @return {HDKey} */ export function hdKeyFromSeed(seed, path = {}) { if (typeof path !== 'string') { const { purpose = 44, coin = 60, account = 0, change = 0, index = 0, } = path; path = `m/${purpose}'/${coin}'/${account}'/${change}/${index}`; } return hdKey.fromMasterSeed(seed).derive(path); } /** * @param {Buffer} [priv] * @param {string} [mnemonic] * @param {boolean} [doAsync] * @constructor */ const Wallet = function WalletConstructor(priv, mnemonic, doAsync, hdPath) { if (priv && mnemonic) { throw new Error('Cannot supply both a private and a mnemonic phrase to the constructor'); } if (priv && !isValidPrivate(priv)) { throw new Error('Private key does not satisfy the curve requirements (ie. it is invalid)'); } if (mnemonic && !bip39.validateMnemonic(mnemonic)) { throw new Error('Invalid mnemonic phrase'); } if (mnemonic && doAsync) { return seedFromMnemonicAsync(mnemonic) .then((seed) => { this._privKey = hdKeyFromSeed(seed, hdPath)._privateKey; this._mnemonic = mnemonic; return this; }); } if (mnemonic) { const seed = seedFromMnemonic(mnemonic); priv = hdKeyFromSeed(seed, hdPath)._privateKey; } this._privKey = priv; this._mnemonic = mnemonic; }; Object.defineProperty(Wallet.prototype, 'mnemonic', { get() { assert(this._mnemonic, 'This is a private key only wallet'); return this._mnemonic; }, }); Object.defineProperty(Wallet.prototype, 'privKey', { get() { return this._privKey; }, }); // uncompressed public key Object.defineProperty(Wallet.prototype, 'pubKey', { get() { if (!this._pubKey) { this._pubKey = privateToPublic(this.privKey); } return this._pubKey; }, }); /** * @return {string} */ Wallet.prototype.getMnemonic = function getMnemonic() { return this.mnemonic; }; /** * @return {Buffer} */ Wallet.prototype.getPrivateKey = function getPrivateKey() { return this.privKey; }; /** * @return {string} */ Wallet.prototype.getPrivateKeyString = function getPrivateKeyString() { return `0x${this.getPrivateKey().toString('hex')}`; }; /** * @return {Buffer} */ Wallet.prototype.getPublicKey = function getPublicKey() { return this.pubKey; }; /** * @return {string} */ Wallet.prototype.getPublicKeyString = function getPublicKeyString() { return publicToString(this.getPublicKey()); }; /** * @return {Buffer} */ Wallet.prototype.getAddress = function getAddress() { return publicToAddress(this.pubKey); }; /** * @return {string} */ Wallet.prototype.getAddressString = function getAddressString() { return `Mx${this.getAddress().toString('hex')}`; }; /** * Generate Wallet from random mnemonic * @param {HDKeyPath} [path] * @return {Wallet} */ export function generateWallet(path) { const mnemonic = bip39.generateMnemonic(); return walletFromMnemonic(mnemonic, path); } /** * MinterWallet from mnemonic phrase * @param {string} mnemonic - 12 words * @param {HDKeyPath} [path] * @return {Wallet} */ export function walletFromMnemonic(mnemonic, path) { return new Wallet(undefined, mnemonic, false, path); } /** * MinterWallet from mnemonic phrase * @param {string} mnemonic - 12 words * @param {HDKeyPath} [path] * @return {Promise<Wallet>} */ export function walletFromMnemonicAsync(mnemonic, path) { return new Wallet(undefined, mnemonic, true, path); } /** * MinterWallet from private key * @param {Buffer} priv - 64 bytes * @return {Wallet} */ export function walletFromPrivateKey(priv) { return new Wallet(priv); } /** * Generate 12 words mnemonic phrase * @return {string} */ export function generateMnemonic() { return bip39.generateMnemonic(); } /** * Check that mnemonic phrase has 12 words and represents valid entropy * @param {string} mnemonic * @return {boolean} */ export function isValidMnemonic(mnemonic) { return typeof mnemonic === 'string' && mnemonic.trim().split(/\s+/g).length >= 12 && bip39.validateMnemonic(mnemonic); } export default Wallet;