aboutsummaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/scripts/inpage.js2
-rw-r--r--app/scripts/keyring-controller.js93
-rw-r--r--app/scripts/keyrings/hd.js67
-rw-r--r--app/scripts/keyrings/simple.js21
-rw-r--r--app/scripts/lib/encryptor.js10
-rw-r--r--app/scripts/lib/idStore-migrator.js2
-rw-r--r--app/scripts/lib/idStore.js8
-rw-r--r--app/scripts/lib/inpage-provider.js10
-rw-r--r--app/scripts/metamask-controller.js18
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/'
}