diff options
Merge branch 'dev' into i843-MoveSaltIntoEncryptor
Diffstat (limited to 'app/scripts')
-rw-r--r-- | app/scripts/inpage.js | 2 | ||||
-rw-r--r-- | app/scripts/keyring-controller.js | 93 | ||||
-rw-r--r-- | app/scripts/keyrings/hd.js | 67 | ||||
-rw-r--r-- | app/scripts/keyrings/simple.js | 21 | ||||
-rw-r--r-- | app/scripts/lib/encryptor.js | 10 | ||||
-rw-r--r-- | app/scripts/lib/idStore-migrator.js | 2 | ||||
-rw-r--r-- | app/scripts/lib/idStore.js | 8 | ||||
-rw-r--r-- | app/scripts/lib/inpage-provider.js | 10 | ||||
-rw-r--r-- | app/scripts/metamask-controller.js | 18 |
9 files changed, 157 insertions, 74 deletions
diff --git a/app/scripts/inpage.js b/app/scripts/inpage.js index 9d6fc96de..68c6165c8 100644 --- a/app/scripts/inpage.js +++ b/app/scripts/inpage.js @@ -50,7 +50,7 @@ endOfStream(pingStream, triggerReload) // set web3 defaultAcount inpageProvider.publicConfigStore.subscribe(function (state) { - web3.eth.defaultAccount = state.selectedAddress + web3.eth.defaultAccount = state.selectedAccount }) // diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index e3705c113..00c04ea9b 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -1,4 +1,5 @@ const async = require('async') +const bind = require('ap').partial const ethUtil = require('ethereumjs-util') const ethBinToOps = require('eth-bin-to-ops') const EthQuery = require('eth-query') @@ -9,7 +10,6 @@ const EventEmitter = require('events').EventEmitter const normalize = require('./lib/sig-util').normalize const encryptor = require('./lib/encryptor') const messageManager = require('./lib/message-manager') -const autoFaucet = require('./lib/auto-faucet') const IdStoreMigrator = require('./lib/idStore-migrator') const BN = ethUtil.BN @@ -61,13 +61,12 @@ module.exports = class KeyringController extends EventEmitter { transactions: this.configManager.getTxList(), unconfMsgs: messageManager.unconfirmedMsgs(), messages: messageManager.getMsgList(), - selectedAddress: address, selectedAccount: address, shapeShiftTxList: this.configManager.getShapeShiftTxList(), currentFiat: this.configManager.getCurrentFiat(), conversionRate: this.configManager.getConversionRate(), conversionDate: this.configManager.getConversionDate(), - keyringTypes: this.keyringTypes.map((krt) => krt.type()), + keyringTypes: this.keyringTypes.map(krt => krt.type), identities: this.identities, } } @@ -76,8 +75,8 @@ module.exports = class KeyringController extends EventEmitter { this.ethStore = ethStore } - createNewVaultAndKeychain (password, entropy, cb) { - this.createNewVault(password, entropy, (err) => { + createNewVaultAndKeychain (password, cb) { + this.createNewVault(password, (err) => { if (err) return cb(err) this.createFirstKeyTree(password, cb) }) @@ -94,7 +93,7 @@ module.exports = class KeyringController extends EventEmitter { this.clearKeyrings() - this.createNewVault(password, '', (err) => { + this.createNewVault(password, (err) => { if (err) return cb(err) this.addNewKeyring('HD Key Tree', { mnemonic: seed, @@ -121,7 +120,7 @@ module.exports = class KeyringController extends EventEmitter { .then((derivedKey) => { key = derivedKey this.key = key - return this.idStoreMigrator.oldSeedForPassword(password) + return this.idStoreMigrator.migratedVaultForPassword(password) }) .then((serialized) => { if (serialized && shouldMigrate) { @@ -135,7 +134,7 @@ module.exports = class KeyringController extends EventEmitter { }) } - createNewVault (password, entropy, cb) { + createNewVault (password, cb) { const configManager = this.configManager const salt = this.getSalt() configManager.setSalt(salt) @@ -161,7 +160,7 @@ module.exports = class KeyringController extends EventEmitter { this.configManager.setSelectedAccount(firstAccount) this.placeSeedWords() - autoFaucet(hexAccount) + this.emit('newAccount', hexAccount) this.setupAccounts(accounts) this.persistAllKeyrings() .then(() => { @@ -173,10 +172,15 @@ module.exports = class KeyringController extends EventEmitter { }) } - placeSeedWords () { + placeSeedWords (cb) { const firstKeyring = this.keyrings[0] const seedWords = firstKeyring.serialize().mnemonic this.configManager.setSeedWords(seedWords) + + if (cb) { + cb() + } + this.emit('update') } submitPassword (password, cb) { @@ -317,7 +321,7 @@ module.exports = class KeyringController extends EventEmitter { getKeyringClassForType (type) { const Keyring = this.keyringTypes.reduce((res, kr) => { - if (kr.type() === type) { + if (kr.type === type) { return kr } else { return res @@ -334,7 +338,7 @@ module.exports = class KeyringController extends EventEmitter { }, []) } - setSelectedAddress (address, cb) { + setSelectedAccount (address, cb) { var addr = normalize(address) this.configManager.setSelectedAccount(addr) cb(null, addr) @@ -369,7 +373,7 @@ module.exports = class KeyringController extends EventEmitter { // calculate metadata for tx async.parallel([ analyzeForDelegateCall, - estimateGas, + analyzeGasUsage, ], didComplete) // perform static analyis on the target contract code @@ -392,14 +396,69 @@ module.exports = class KeyringController extends EventEmitter { } } - function estimateGas (cb) { - query.estimateGas(txParams, function (err, result) { + function analyzeGasUsage (cb) { + query.getBlockByNumber('latest', true, function (err, block) { if (err) return cb(err) - txData.estimatedGas = self.addGasBuffer(result) - cb() + async.waterfall([ + bind(estimateGas, txData, block.gasLimit), + bind(checkForGasError, txData), + bind(setTxGas, txData, block.gasLimit), + ], cb) }) } + function estimateGas(txData, blockGasLimitHex, cb) { + const txParams = txData.txParams + // check if gasLimit is already specified + txData.gasLimitSpecified = Boolean(txParams.gas) + // if not, fallback to block gasLimit + if (!txData.gasLimitSpecified) { + txParams.gas = blockGasLimitHex + } + // run tx, see if it will OOG + query.estimateGas(txParams, cb) + } + + function checkForGasError(txData, estimatedGasHex) { + txData.estimatedGas = estimatedGasHex + // all gas used - must be an error + if (estimatedGasHex === txData.txParams.gas) { + txData.simulationFails = true + } + cb() + } + + function setTxGas(txData, blockGasLimitHex) { + const txParams = txData.txParams + // if OOG, nothing more to do + if (txData.simulationFails) { + cb() + return + } + // if gasLimit was specified and doesnt OOG, + // use original specified amount + if (txData.gasLimitSpecified) { + txData.estimatedGas = txParams.gas + cb() + return + } + // if gasLimit not originally specified, + // try adding an additional gas buffer to our estimation for safety + const estimatedGasBn = new BN(ethUtil.stripHexPrefix(txData.estimatedGas), 16) + const blockGasLimitBn = new BN(ethUtil.stripHexPrefix(blockGasLimitHex), 16) + const estimationWithBuffer = self.addGasBuffer(estimatedGasBn) + // added gas buffer is too high + if (estimationWithBuffer.gt(blockGasLimitBn)) { + txParams.gas = txData.estimatedGas + // added gas buffer is safe + } else { + const gasWithBufferHex = ethUtil.intToHex(estimationWithBuffer) + txParams.gas = gasWithBufferHex + } + cb() + return + } + function didComplete (err) { if (err) return cb(err) configManager.addTx(txData) diff --git a/app/scripts/keyrings/hd.js b/app/scripts/keyrings/hd.js index b98f29187..a28ef6736 100644 --- a/app/scripts/keyrings/hd.js +++ b/app/scripts/keyrings/hd.js @@ -2,17 +2,17 @@ const EventEmitter = require('events').EventEmitter const hdkey = require('ethereumjs-wallet/hdkey') const bip39 = require('bip39') const ethUtil = require('ethereumjs-util') -const sigUtil = require('../lib/sig-util') -const type = 'HD Key Tree' +// *Internal Deps +const sigUtil = require('../lib/sig-util') +// Options: const hdPathString = `m/44'/60'/0'/0` +const type = 'HD Key Tree' -module.exports = class HdKeyring extends EventEmitter { +class HdKeyring extends EventEmitter { - static type () { - return type - } + /* PUBLIC METHODS */ constructor (opts = {}) { super() @@ -20,6 +20,13 @@ module.exports = class HdKeyring extends EventEmitter { this.deserialize(opts) } + serialize () { + return { + mnemonic: this.mnemonic, + numberOfAccounts: this.wallets.length, + } + } + deserialize (opts = {}) { this.opts = opts || {} this.wallets = [] @@ -27,7 +34,7 @@ module.exports = class HdKeyring extends EventEmitter { this.root = null if ('mnemonic' in opts) { - this.initFromMnemonic(opts.mnemonic) + this._initFromMnemonic(opts.mnemonic) } if ('numberOfAccounts' in opts) { @@ -35,28 +42,9 @@ module.exports = class HdKeyring extends EventEmitter { } } - initFromMnemonic (mnemonic) { - this.mnemonic = mnemonic - const seed = bip39.mnemonicToSeed(mnemonic) - this.hdWallet = hdkey.fromMasterSeed(seed) - this.root = this.hdWallet.derivePath(hdPathString) - } - - serialize () { - return { - mnemonic: this.mnemonic, - numberOfAccounts: this.wallets.length, - } - } - - exportAccount (address) { - const wallet = this.getWalletForAccount(address) - return wallet.getPrivateKey().toString('hex') - } - addAccounts (numberOfAccounts = 1) { if (!this.root) { - this.initFromMnemonic(bip39.generateMnemonic()) + this._initFromMnemonic(bip39.generateMnemonic()) } const oldLen = this.wallets.length @@ -76,7 +64,7 @@ module.exports = class HdKeyring extends EventEmitter { // tx is an instance of the ethereumjs-transaction class. signTransaction (address, tx) { - const wallet = this.getWalletForAccount(address) + const wallet = this._getWalletForAccount(address) var privKey = wallet.getPrivateKey() tx.sign(privKey) return tx @@ -84,7 +72,7 @@ module.exports = class HdKeyring extends EventEmitter { // For eth_sign, we need to sign transactions: signMessage (withAccount, data) { - const wallet = this.getWalletForAccount(withAccount) + const wallet = this._getWalletForAccount(withAccount) const message = ethUtil.removeHexPrefix(data) var privKey = wallet.getPrivateKey() var msgSig = ethUtil.ecsign(new Buffer(message, 'hex'), privKey) @@ -92,10 +80,29 @@ module.exports = class HdKeyring extends EventEmitter { return rawMsgSig } - getWalletForAccount (account) { + exportAccount (address) { + const wallet = this._getWalletForAccount(address) + return wallet.getPrivateKey().toString('hex') + } + + + /* PRIVATE METHODS */ + + _initFromMnemonic (mnemonic) { + this.mnemonic = mnemonic + const seed = bip39.mnemonicToSeed(mnemonic) + this.hdWallet = hdkey.fromMasterSeed(seed) + this.root = this.hdWallet.derivePath(hdPathString) + } + + + _getWalletForAccount (account) { return this.wallets.find((w) => { const address = w.getAddress().toString('hex') return ((address === account) || (sigUtil.normalize(address) === account)) }) } } + +HdKeyring.type = type +module.exports = HdKeyring diff --git a/app/scripts/keyrings/simple.js b/app/scripts/keyrings/simple.js index ee743bc03..4fdccc4f7 100644 --- a/app/scripts/keyrings/simple.js +++ b/app/scripts/keyrings/simple.js @@ -4,7 +4,9 @@ const ethUtil = require('ethereumjs-util') const type = 'Simple Key Pair' const sigUtil = require('../lib/sig-util') -module.exports = class SimpleKeyring extends EventEmitter { +class SimpleKeyring extends EventEmitter { + + /* PUBLIC METHODS */ static type () { return type @@ -44,7 +46,7 @@ module.exports = class SimpleKeyring extends EventEmitter { // tx is an instance of the ethereumjs-transaction class. signTransaction (address, tx) { - const wallet = this.getWalletForAccount(address) + const wallet = this._getWalletForAccount(address) var privKey = wallet.getPrivateKey() tx.sign(privKey) return tx @@ -52,7 +54,7 @@ module.exports = class SimpleKeyring extends EventEmitter { // For eth_sign, we need to sign transactions: signMessage (withAccount, data) { - const wallet = this.getWalletForAccount(withAccount) + const wallet = this._getWalletForAccount(withAccount) const message = ethUtil.removeHexPrefix(data) var privKey = wallet.getPrivateKey() var msgSig = ethUtil.ecsign(new Buffer(message, 'hex'), privKey) @@ -60,8 +62,19 @@ module.exports = class SimpleKeyring extends EventEmitter { return rawMsgSig } - getWalletForAccount (account) { + exportAccount (address) { + const wallet = this._getWalletForAccount(address) + return wallet.getPrivateKey().toString('hex') + } + + + /* PRIVATE METHODS */ + + _getWalletForAccount (account) { return this.wallets.find(w => w.getAddress().toString('hex') === account) } } + +SimpleKeyring.type = type +module.exports = SimpleKeyring diff --git a/app/scripts/lib/encryptor.js b/app/scripts/lib/encryptor.js index 2af2a1d2b..df72b62c0 100644 --- a/app/scripts/lib/encryptor.js +++ b/app/scripts/lib/encryptor.js @@ -1,5 +1,3 @@ -var ethUtil = require('ethereumjs-util') - module.exports = { // Simple encryption methods: @@ -101,10 +99,10 @@ function keyFromPassword (password) { } function serializeBufferFromStorage (str) { - str = ethUtil.stripHexPrefix(str) - var buf = new Uint8Array(str.length / 2) - for (var i = 0; i < str.length; i += 2) { - var seg = str.substr(i, 2) + var stripStr = (str.slice(0, 2) === '0x') ? str.slice(2) : str + var buf = new Uint8Array(stripStr.length / 2) + for (var i = 0; i < stripStr.length; i += 2) { + var seg = stripStr.substr(i, 2) buf[i / 2] = parseInt(seg, 16) } return buf diff --git a/app/scripts/lib/idStore-migrator.js b/app/scripts/lib/idStore-migrator.js index 18134b677..40b08efee 100644 --- a/app/scripts/lib/idStore-migrator.js +++ b/app/scripts/lib/idStore-migrator.js @@ -11,7 +11,7 @@ module.exports = class IdentityStoreMigrator { } } - oldSeedForPassword (password) { + migratedVaultForPassword (password) { const hasOldVault = this.hasOldVault() const configManager = this.configManager diff --git a/app/scripts/lib/idStore.js b/app/scripts/lib/idStore.js index b73652af5..e5861c0ca 100644 --- a/app/scripts/lib/idStore.js +++ b/app/scripts/lib/idStore.js @@ -44,7 +44,7 @@ function IdentityStore (opts = {}) { // public // -IdentityStore.prototype.createNewVault = function (password, entropy, cb) { +IdentityStore.prototype.createNewVault = function (password, cb) { delete this._keyStore var serializedKeystore = this.configManager.getWallet() @@ -53,7 +53,7 @@ IdentityStore.prototype.createNewVault = function (password, entropy, cb) { } this.purgeCache() - this._createVault(password, null, entropy, (err) => { + this._createVault(password, null, (err) => { if (err) return cb(err) this._autoFaucet() @@ -77,7 +77,7 @@ IdentityStore.prototype.recoverSeed = function (cb) { IdentityStore.prototype.recoverFromSeed = function (password, seed, cb) { this.purgeCache() - this._createVault(password, seed, null, (err) => { + this._createVault(password, seed, (err) => { if (err) return cb(err) this._loadIdentities() @@ -497,7 +497,7 @@ IdentityStore.prototype.tryPassword = function (password, cb) { }) } -IdentityStore.prototype._createVault = function (password, seedPhrase, entropy, cb) { +IdentityStore.prototype._createVault = function (password, seedPhrase, cb) { const opts = { password, hdPathString: this.hdPathString, diff --git a/app/scripts/lib/inpage-provider.js b/app/scripts/lib/inpage-provider.js index 034812b6a..7179ae978 100644 --- a/app/scripts/lib/inpage-provider.js +++ b/app/scripts/lib/inpage-provider.js @@ -66,20 +66,20 @@ function MetamaskInpageProvider (connectionStream) { MetamaskInpageProvider.prototype.send = function (payload) { const self = this - let selectedAddress + let selectedAccount let result = null switch (payload.method) { case 'eth_accounts': // read from localStorage - selectedAddress = self.publicConfigStore.get('selectedAddress') - result = selectedAddress ? [selectedAddress] : [] + selectedAccount = self.publicConfigStore.get('selectedAddress') + result = selectedAccount ? [selectedAccount] : [] break case 'eth_coinbase': // read from localStorage - selectedAddress = self.publicConfigStore.get('selectedAddress') - result = selectedAddress || '0x0000000000000000000000000000000000000000' + selectedAccount = self.publicConfigStore.get('selectedAddress') + result = selectedAccount || '0x0000000000000000000000000000000000000000' break // throw not-supported Error diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 951918460..701046e76 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -7,6 +7,8 @@ const HostStore = require('./lib/remote-store.js').HostStore const Web3 = require('web3') const ConfigManager = require('./lib/config-manager') const extension = require('./lib/extension') +const autoFaucet = require('./lib/auto-faucet') + module.exports = class MetamaskController { @@ -67,7 +69,7 @@ module.exports = class MetamaskController { addNewKeyring: keyringController.addNewKeyring.bind(keyringController), addNewAccount: keyringController.addNewAccount.bind(keyringController), submitPassword: keyringController.submitPassword.bind(keyringController), - setSelectedAddress: keyringController.setSelectedAddress.bind(keyringController), + setSelectedAccount: keyringController.setSelectedAccount.bind(keyringController), approveTransaction: keyringController.approveTransaction.bind(keyringController), cancelTransaction: keyringController.cancelTransaction.bind(keyringController), signMessage: keyringController.signMessage.bind(keyringController), @@ -125,8 +127,8 @@ module.exports = class MetamaskController { rpcUrl: this.configManager.getCurrentRpcAddress(), // account mgmt getAccounts: (cb) => { - var selectedAddress = this.configManager.getSelectedAccount() - var result = selectedAddress ? [selectedAddress] : [] + var selectedAccount = this.configManager.getSelectedAccount() + var result = selectedAccount ? [selectedAccount] : [] cb(null, result) }, // tx signing @@ -174,17 +176,21 @@ module.exports = class MetamaskController { this.sendUpdate() }) + this.keyringController.on('newAccount', (account) => { + autoFaucet(account) + }) + // keyringController substate function keyringControllerToPublic (state) { return { - selectedAddress: state.selectedAddress, + selectedAccount: state.selectedAccount, } } // config substate function configToPublic (state) { return { provider: state.provider, - selectedAddress: state.selectedAccount, + selectedAccount: state.selectedAccount, } } // dump obj into store @@ -341,7 +347,7 @@ module.exports = class MetamaskController { var network = this.state.network var url = `https://buy.coinbase.com/?code=9ec56d01-7e81-5017-930c-513daa27bb6a&amount=${amount}&address=${address}&crypto_currency=ETH` - if (network === '2') { + if (network === '3') { url = 'https://faucet.metamask.io/' } |