From a824957de7e692d9932a591bb5730ba798bcd8ed Mon Sep 17 00:00:00 2001 From: Jacob Evans Date: Wed, 11 Apr 2018 13:46:01 +1000 Subject: Follow file naming pattern for mnemonic and private key subprovider --- packages/subproviders/src/index.ts | 4 +- .../src/subproviders/mnemonic_wallet.ts | 134 +++++++++++++++++++++ .../subproviders/mnemonic_wallet_subprovider.ts | 134 --------------------- .../src/subproviders/private_key_wallet.ts | 80 ++++++++++++ .../subproviders/private_key_wallet_subprovider.ts | 80 ------------ 5 files changed, 216 insertions(+), 216 deletions(-) create mode 100644 packages/subproviders/src/subproviders/mnemonic_wallet.ts delete mode 100644 packages/subproviders/src/subproviders/mnemonic_wallet_subprovider.ts create mode 100644 packages/subproviders/src/subproviders/private_key_wallet.ts delete mode 100644 packages/subproviders/src/subproviders/private_key_wallet_subprovider.ts (limited to 'packages') diff --git a/packages/subproviders/src/index.ts b/packages/subproviders/src/index.ts index 9c30c6ba1..01aec956a 100644 --- a/packages/subproviders/src/index.ts +++ b/packages/subproviders/src/index.ts @@ -12,8 +12,8 @@ export { LedgerSubprovider } from './subproviders/ledger'; export { GanacheSubprovider } from './subproviders/ganache'; export { Subprovider } from './subproviders/subprovider'; export { NonceTrackerSubprovider } from './subproviders/nonce_tracker'; -export { PrivateKeyWalletSubprovider } from './subproviders/private_key_wallet_subprovider'; -export { MnemonicWalletSubprovider } from './subproviders/mnemonic_wallet_subprovider'; +export { PrivateKeyWalletSubprovider } from './subproviders/private_key_wallet'; +export { MnemonicWalletSubprovider } from './subproviders/mnemonic_wallet'; export { Callback, ErrorCallback, diff --git a/packages/subproviders/src/subproviders/mnemonic_wallet.ts b/packages/subproviders/src/subproviders/mnemonic_wallet.ts new file mode 100644 index 000000000..40f584250 --- /dev/null +++ b/packages/subproviders/src/subproviders/mnemonic_wallet.ts @@ -0,0 +1,134 @@ +import { assert } from '@0xproject/assert'; +import * as bip39 from 'bip39'; +import ethUtil = require('ethereumjs-util'); +import HDNode = require('hdkey'); +import * as _ from 'lodash'; + +import { DerivedHDKey, PartialTxParams, WalletSubproviderErrors } from '../types'; +import { walletUtils } from '../utils/wallet_utils'; + +import { BaseWalletSubprovider } from './base_wallet_subprovider'; +import { PrivateKeyWalletSubprovider } from './private_key_wallet'; + +const DEFAULT_DERIVATION_PATH = `44'/60'/0'/0`; + +/** + * This class implements the [web3-provider-engine](https://github.com/MetaMask/provider-engine) subprovider interface. + * This subprovider intercepts all account related RPC requests (e.g message/transaction signing, etc...) and handles + * all requests with accounts derived from the supplied mnemonic. + */ +export class MnemonicWalletSubprovider extends BaseWalletSubprovider { + private _addressSearchLimit: number; + private _derivationPath: string; + private _derivedKey: DerivedHDKey; + /** + * Instantiates a MnemonicWalletSubprovider. Defaults to derivationPath set to `44'/60'/0'/0`. + * This is the default in TestRPC/Ganache, this can be overridden if desired. + * @param mnemonic The mnemonic seed + * @param derivationPath The derivation path, defaults to `44'/60'/0'/0` + * @param addressSearchLimit The limit on address search attempts before raising `WalletSubproviderErrors.AddressNotFound` + * @return MnemonicWalletSubprovider instance + */ + constructor( + mnemonic: string, + derivationPath: string = DEFAULT_DERIVATION_PATH, + addressSearchLimit: number = walletUtils.DEFAULT_ADDRESS_SEARCH_LIMIT, + ) { + assert.isString('mnemonic', mnemonic); + assert.isString('derivationPath', derivationPath); + assert.isNumber('addressSearchLimit', addressSearchLimit); + super(); + const seed = bip39.mnemonicToSeed(mnemonic); + const hdKey = HDNode.fromMasterSeed(seed); + this._derivationPath = derivationPath; + this._derivedKey = { + address: walletUtils.addressOfHDKey(hdKey), + derivationPath: this._derivationPath, + derivationIndex: 0, + hdKey, + isChildKey: false, + }; + this._addressSearchLimit = addressSearchLimit; + } + /** + * Retrieve the set derivation path + * @returns derivation path + */ + public getPath(): string { + return this._derivationPath; + } + /** + * Set a desired derivation path when computing the available user addresses + * @param derivationPath The desired derivation path (e.g `44'/60'/0'`) + */ + public setPath(derivationPath: string) { + this._derivationPath = derivationPath; + this._derivedKey = { + ...this._derivedKey, + derivationPath: this._derivationPath, + }; + } + /** + * Retrieve the accounts associated with the mnemonic. + * This method is implicitly called when issuing a `eth_accounts` JSON RPC request + * via your providerEngine instance. + * @param numberOfAccounts Number of accounts to retrieve (default: 10) + * @return An array of accounts + */ + public async getAccountsAsync( + numberOfAccounts: number = walletUtils.DEFAULT_NUM_ADDRESSES_TO_FETCH, + ): Promise { + const derivedKeys = walletUtils.calculateDerivedHDKeys(this._derivedKey, numberOfAccounts); + const accounts = _.map(derivedKeys, 'address'); + return accounts; + } + + /** + * Signs a transaction with the from account (if specificed in txParams) or the first account. + * If you've added this Subprovider to your app's provider, you can simply send + * an `eth_sendTransaction` JSON RPC request, and * this method will be called auto-magically. + * If you are not using this via a ProviderEngine instance, you can call it directly. + * @param txParams Parameters of the transaction to sign + * @return Signed transaction hex string + */ + public async signTransactionAsync(txParams: PartialTxParams): Promise { + const privateKeyWallet = this._privateKeyWalletFromAddress(txParams.from); + const signedTx = privateKeyWallet.signTransactionAsync(txParams); + return signedTx; + } + /** + * Sign a personal Ethereum signed message. The signing address used will be + * address provided or the first address derived from the set path. + * If you've added the MnemonicWalletSubprovider to your app's provider, you can simply send an `eth_sign` + * or `personal_sign` JSON RPC request, and this method will be called auto-magically. + * If you are not using this via a ProviderEngine instance, you can call it directly. + * @param data Message to sign + * @param address Address to sign with + * @return Signature hex string (order: rsv) + */ + public async signPersonalMessageAsync(data: string, address: string): Promise { + const privateKeyWallet = this._privateKeyWalletFromAddress(address); + const sig = await privateKeyWallet.signPersonalMessageAsync(data, address); + return sig; + } + private _privateKeyWalletFromAddress(address: string): PrivateKeyWalletSubprovider { + const derivedKey = this._findDerivedKeyByPublicAddress(address); + const privateKeyHex = derivedKey.hdKey.privateKey.toString('hex'); + const privateKeyWallet = new PrivateKeyWalletSubprovider(privateKeyHex); + return privateKeyWallet; + } + private _findDerivedKeyByPublicAddress(address: string): DerivedHDKey { + if (_.isUndefined(address)) { + throw new Error(WalletSubproviderErrors.FromAddressMissingOrInvalid); + } + const matchedDerivedKey = walletUtils.findDerivedKeyByAddress( + address, + this._derivedKey, + this._addressSearchLimit, + ); + if (_.isUndefined(matchedDerivedKey)) { + throw new Error(`${WalletSubproviderErrors.AddressNotFound}: ${address}`); + } + return matchedDerivedKey; + } +} diff --git a/packages/subproviders/src/subproviders/mnemonic_wallet_subprovider.ts b/packages/subproviders/src/subproviders/mnemonic_wallet_subprovider.ts deleted file mode 100644 index 730453bc6..000000000 --- a/packages/subproviders/src/subproviders/mnemonic_wallet_subprovider.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { assert } from '@0xproject/assert'; -import * as bip39 from 'bip39'; -import ethUtil = require('ethereumjs-util'); -import HDNode = require('hdkey'); -import * as _ from 'lodash'; - -import { DerivedHDKey, PartialTxParams, WalletSubproviderErrors } from '../types'; -import { walletUtils } from '../utils/wallet_utils'; - -import { BaseWalletSubprovider } from './base_wallet_subprovider'; -import { PrivateKeyWalletSubprovider } from './private_key_wallet_subprovider'; - -const DEFAULT_DERIVATION_PATH = `44'/60'/0'/0`; - -/** - * This class implements the [web3-provider-engine](https://github.com/MetaMask/provider-engine) subprovider interface. - * This subprovider intercepts all account related RPC requests (e.g message/transaction signing, etc...) and handles - * all requests with accounts derived from the supplied mnemonic. - */ -export class MnemonicWalletSubprovider extends BaseWalletSubprovider { - private _addressSearchLimit: number; - private _derivationPath: string; - private _derivedKey: DerivedHDKey; - /** - * Instantiates a MnemonicWalletSubprovider. Defaults to derivationPath set to `44'/60'/0'/0`. - * This is the default in TestRPC/Ganache, this can be overridden if desired. - * @param mnemonic The mnemonic seed - * @param derivationPath The derivation path, defaults to `44'/60'/0'/0` - * @param addressSearchLimit The limit on address search attempts before raising `WalletSubproviderErrors.AddressNotFound` - * @return MnemonicWalletSubprovider instance - */ - constructor( - mnemonic: string, - derivationPath: string = DEFAULT_DERIVATION_PATH, - addressSearchLimit: number = walletUtils.DEFAULT_ADDRESS_SEARCH_LIMIT, - ) { - assert.isString('mnemonic', mnemonic); - assert.isString('derivationPath', derivationPath); - assert.isNumber('addressSearchLimit', addressSearchLimit); - super(); - const seed = bip39.mnemonicToSeed(mnemonic); - const hdKey = HDNode.fromMasterSeed(seed); - this._derivationPath = derivationPath; - this._derivedKey = { - address: walletUtils.addressOfHDKey(hdKey), - derivationPath: this._derivationPath, - derivationIndex: 0, - hdKey, - isChildKey: false, - }; - this._addressSearchLimit = addressSearchLimit; - } - /** - * Retrieve the set derivation path - * @returns derivation path - */ - public getPath(): string { - return this._derivationPath; - } - /** - * Set a desired derivation path when computing the available user addresses - * @param derivationPath The desired derivation path (e.g `44'/60'/0'`) - */ - public setPath(derivationPath: string) { - this._derivationPath = derivationPath; - this._derivedKey = { - ...this._derivedKey, - derivationPath: this._derivationPath, - }; - } - /** - * Retrieve the accounts associated with the mnemonic. - * This method is implicitly called when issuing a `eth_accounts` JSON RPC request - * via your providerEngine instance. - * @param numberOfAccounts Number of accounts to retrieve (default: 10) - * @return An array of accounts - */ - public async getAccountsAsync( - numberOfAccounts: number = walletUtils.DEFAULT_NUM_ADDRESSES_TO_FETCH, - ): Promise { - const derivedKeys = walletUtils.calculateDerivedHDKeys(this._derivedKey, numberOfAccounts); - const accounts = _.map(derivedKeys, 'address'); - return accounts; - } - - /** - * Signs a transaction with the from account (if specificed in txParams) or the first account. - * If you've added this Subprovider to your app's provider, you can simply send - * an `eth_sendTransaction` JSON RPC request, and * this method will be called auto-magically. - * If you are not using this via a ProviderEngine instance, you can call it directly. - * @param txParams Parameters of the transaction to sign - * @return Signed transaction hex string - */ - public async signTransactionAsync(txParams: PartialTxParams): Promise { - const privateKeyWallet = this._privateKeyWalletFromAddress(txParams.from); - const signedTx = privateKeyWallet.signTransactionAsync(txParams); - return signedTx; - } - /** - * Sign a personal Ethereum signed message. The signing address used will be - * address provided or the first address derived from the set path. - * If you've added the MnemonicWalletSubprovider to your app's provider, you can simply send an `eth_sign` - * or `personal_sign` JSON RPC request, and this method will be called auto-magically. - * If you are not using this via a ProviderEngine instance, you can call it directly. - * @param data Message to sign - * @param address Address to sign with - * @return Signature hex string (order: rsv) - */ - public async signPersonalMessageAsync(data: string, address: string): Promise { - const privateKeyWallet = this._privateKeyWalletFromAddress(address); - const sig = await privateKeyWallet.signPersonalMessageAsync(data, address); - return sig; - } - private _privateKeyWalletFromAddress(address: string): PrivateKeyWalletSubprovider { - const derivedKey = this._findDerivedKeyByPublicAddress(address); - const privateKeyHex = derivedKey.hdKey.privateKey.toString('hex'); - const privateKeyWallet = new PrivateKeyWalletSubprovider(privateKeyHex); - return privateKeyWallet; - } - private _findDerivedKeyByPublicAddress(address: string): DerivedHDKey { - if (_.isUndefined(address)) { - throw new Error(WalletSubproviderErrors.FromAddressMissingOrInvalid); - } - const matchedDerivedKey = walletUtils.findDerivedKeyByAddress( - address, - this._derivedKey, - this._addressSearchLimit, - ); - if (_.isUndefined(matchedDerivedKey)) { - throw new Error(`${WalletSubproviderErrors.AddressNotFound}: ${address}`); - } - return matchedDerivedKey; - } -} diff --git a/packages/subproviders/src/subproviders/private_key_wallet.ts b/packages/subproviders/src/subproviders/private_key_wallet.ts new file mode 100644 index 000000000..f8afab722 --- /dev/null +++ b/packages/subproviders/src/subproviders/private_key_wallet.ts @@ -0,0 +1,80 @@ +import { assert } from '@0xproject/assert'; +import EthereumTx = require('ethereumjs-tx'); +import * as ethUtil from 'ethereumjs-util'; +import * as _ from 'lodash'; + +import { PartialTxParams, WalletSubproviderErrors } from '../types'; + +import { BaseWalletSubprovider } from './base_wallet_subprovider'; + +/** + * This class implements the [web3-provider-engine](https://github.com/MetaMask/provider-engine) subprovider interface. + * This subprovider intercepts all account related RPC requests (e.g message/transaction signing, etc...) and handles + * all requests with the supplied Ethereum private key. + */ +export class PrivateKeyWalletSubprovider extends BaseWalletSubprovider { + private _address: string; + private _privateKeyBuffer: Buffer; + /** + * Instantiates a PrivateKeyWalletSubprovider. + * @param privateKey The private key of the ethereum address + * @return PrivateKeyWalletSubprovider instance + */ + constructor(privateKey: string) { + assert.isString('privateKey', privateKey); + super(); + this._privateKeyBuffer = new Buffer(privateKey, 'hex'); + this._address = `0x${ethUtil.privateToAddress(this._privateKeyBuffer).toString('hex')}`; + } + /** + * Retrieve the account associated with the supplied private key. + * This method is implicitly called when issuing a `eth_accounts` JSON RPC request + * via your providerEngine instance. + * @return An array of accounts + */ + public async getAccountsAsync(): Promise { + return [this._address]; + } + /** + * Sign a transaction with the private key. If you've added this Subprovider to your + * app's provider, you can simply send an `eth_sendTransaction` JSON RPC request, and + * this method will be called auto-magically. If you are not using this via a ProviderEngine + * instance, you can call it directly. + * @param txParams Parameters of the transaction to sign + * @return Signed transaction hex string + */ + public async signTransactionAsync(txParams: PartialTxParams): Promise { + PrivateKeyWalletSubprovider._validateTxParams(txParams); + if (!_.isUndefined(txParams.from) && txParams.from !== this._address) { + throw new Error(`${WalletSubproviderErrors.AddressNotFound}: ${txParams.from}`); + } + const tx = new EthereumTx(txParams); + tx.sign(this._privateKeyBuffer); + const rawTx = `0x${tx.serialize().toString('hex')}`; + return rawTx; + } + /** + * Sign a personal Ethereum signed message. The signing address will be + * calculated from the private key, if an address is provided it must match the address calculated from the private key. + * If you've added this Subprovider to your app's provider, you can simply send an `eth_sign` + * or `personal_sign` JSON RPC request, and this method will be called auto-magically. + * If you are not using this via a ProviderEngine instance, you can call it directly. + * @param data Message to sign + * @param address Address to sign with + * @return Signature hex string (order: rsv) + */ + public async signPersonalMessageAsync(data: string, address: string): Promise { + if (_.isUndefined(data)) { + throw new Error(WalletSubproviderErrors.DataMissingForSignPersonalMessage); + } + if (_.isUndefined(address) || address !== this._address) { + throw new Error(`${WalletSubproviderErrors.FromAddressMissingOrInvalid}: ${address}`); + } + assert.isHexString('data', data); + const dataBuff = ethUtil.toBuffer(data); + const msgHashBuff = ethUtil.hashPersonalMessage(dataBuff); + const sig = ethUtil.ecsign(msgHashBuff, this._privateKeyBuffer); + const rpcSig = ethUtil.toRpcSig(sig.v, sig.r, sig.s); + return rpcSig; + } +} diff --git a/packages/subproviders/src/subproviders/private_key_wallet_subprovider.ts b/packages/subproviders/src/subproviders/private_key_wallet_subprovider.ts deleted file mode 100644 index f8afab722..000000000 --- a/packages/subproviders/src/subproviders/private_key_wallet_subprovider.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { assert } from '@0xproject/assert'; -import EthereumTx = require('ethereumjs-tx'); -import * as ethUtil from 'ethereumjs-util'; -import * as _ from 'lodash'; - -import { PartialTxParams, WalletSubproviderErrors } from '../types'; - -import { BaseWalletSubprovider } from './base_wallet_subprovider'; - -/** - * This class implements the [web3-provider-engine](https://github.com/MetaMask/provider-engine) subprovider interface. - * This subprovider intercepts all account related RPC requests (e.g message/transaction signing, etc...) and handles - * all requests with the supplied Ethereum private key. - */ -export class PrivateKeyWalletSubprovider extends BaseWalletSubprovider { - private _address: string; - private _privateKeyBuffer: Buffer; - /** - * Instantiates a PrivateKeyWalletSubprovider. - * @param privateKey The private key of the ethereum address - * @return PrivateKeyWalletSubprovider instance - */ - constructor(privateKey: string) { - assert.isString('privateKey', privateKey); - super(); - this._privateKeyBuffer = new Buffer(privateKey, 'hex'); - this._address = `0x${ethUtil.privateToAddress(this._privateKeyBuffer).toString('hex')}`; - } - /** - * Retrieve the account associated with the supplied private key. - * This method is implicitly called when issuing a `eth_accounts` JSON RPC request - * via your providerEngine instance. - * @return An array of accounts - */ - public async getAccountsAsync(): Promise { - return [this._address]; - } - /** - * Sign a transaction with the private key. If you've added this Subprovider to your - * app's provider, you can simply send an `eth_sendTransaction` JSON RPC request, and - * this method will be called auto-magically. If you are not using this via a ProviderEngine - * instance, you can call it directly. - * @param txParams Parameters of the transaction to sign - * @return Signed transaction hex string - */ - public async signTransactionAsync(txParams: PartialTxParams): Promise { - PrivateKeyWalletSubprovider._validateTxParams(txParams); - if (!_.isUndefined(txParams.from) && txParams.from !== this._address) { - throw new Error(`${WalletSubproviderErrors.AddressNotFound}: ${txParams.from}`); - } - const tx = new EthereumTx(txParams); - tx.sign(this._privateKeyBuffer); - const rawTx = `0x${tx.serialize().toString('hex')}`; - return rawTx; - } - /** - * Sign a personal Ethereum signed message. The signing address will be - * calculated from the private key, if an address is provided it must match the address calculated from the private key. - * If you've added this Subprovider to your app's provider, you can simply send an `eth_sign` - * or `personal_sign` JSON RPC request, and this method will be called auto-magically. - * If you are not using this via a ProviderEngine instance, you can call it directly. - * @param data Message to sign - * @param address Address to sign with - * @return Signature hex string (order: rsv) - */ - public async signPersonalMessageAsync(data: string, address: string): Promise { - if (_.isUndefined(data)) { - throw new Error(WalletSubproviderErrors.DataMissingForSignPersonalMessage); - } - if (_.isUndefined(address) || address !== this._address) { - throw new Error(`${WalletSubproviderErrors.FromAddressMissingOrInvalid}: ${address}`); - } - assert.isHexString('data', data); - const dataBuff = ethUtil.toBuffer(data); - const msgHashBuff = ethUtil.hashPersonalMessage(dataBuff); - const sig = ethUtil.ecsign(msgHashBuff, this._privateKeyBuffer); - const rpcSig = ethUtil.toRpcSig(sig.v, sig.r, sig.s); - return rpcSig; - } -} -- cgit v1.2.3