Merge branch 'master' into NewUI-flat

feature/default_network_editable
Chi Kei Chan 7 years ago
commit 344b467d03
  1. 1
      CHANGELOG.md
  2. 10
      app/scripts/controllers/balance.js
  3. 23
      app/scripts/controllers/computed-balances.js
  4. 23
      app/scripts/lib/account-tracker.js
  5. 59
      app/scripts/metamask-controller.js
  6. 4
      package.json
  7. 7
      ui/app/reducers.js

@ -3,6 +3,7 @@
## Current Master ## Current Master
- Fix bug where web3 API was sometimes injected after the page loaded. - Fix bug where web3 API was sometimes injected after the page loaded.
- Fix bug where first account was sometimes not selected correctly after creating or restoring a vault.
- Fix bug where imported accounts could not use new eth_signTypedData method. - Fix bug where imported accounts could not use new eth_signTypedData method.
## 3.11.0 2017-10-11 ## 3.11.0 2017-10-11

@ -5,7 +5,9 @@ const BN = require('ethereumjs-util').BN
class BalanceController { class BalanceController {
constructor (opts = {}) { constructor (opts = {}) {
this._validateParams(opts)
const { address, accountTracker, txController, blockTracker } = opts const { address, accountTracker, txController, blockTracker } = opts
this.address = address this.address = address
this.accountTracker = accountTracker this.accountTracker = accountTracker
this.txController = txController this.txController = txController
@ -65,6 +67,14 @@ class BalanceController {
return pending return pending
} }
_validateParams (opts) {
const { address, accountTracker, txController, blockTracker } = opts
if (!address || !accountTracker || !txController || !blockTracker) {
const error = 'Cannot construct a balance checker without address, accountTracker, txController, and blockTracker.'
throw new Error(error)
}
}
} }
module.exports = BalanceController module.exports = BalanceController

@ -20,23 +20,34 @@ class ComputedbalancesController {
} }
updateAllBalances () { updateAllBalances () {
for (let address in this.accountTracker.store.getState().accounts) { Object.keys(this.balances).forEach((balance) => {
const address = balance.address
this.balances[address].updateBalance() this.balances[address].updateBalance()
} })
} }
_initBalanceUpdating () { _initBalanceUpdating () {
const store = this.accountTracker.store.getState() const store = this.accountTracker.store.getState()
this.addAnyAccountsFromStore(store) this.syncAllAccountsFromStore(store)
this.accountTracker.store.subscribe(this.addAnyAccountsFromStore.bind(this)) this.accountTracker.store.subscribe(this.syncAllAccountsFromStore.bind(this))
} }
addAnyAccountsFromStore(store) { syncAllAccountsFromStore(store) {
const balances = store.accounts const upstream = Object.keys(store.accounts)
const balances = Object.keys(this.balances)
.map(address => this.balances[address])
// Follow new addresses
for (let address in balances) { for (let address in balances) {
this.trackAddressIfNotAlready(address) this.trackAddressIfNotAlready(address)
} }
// Unfollow old ones
balances.forEach(({ address }) => {
if (!upstream.includes(address)) {
delete this.balances[address]
}
})
} }
trackAddressIfNotAlready (address) { trackAddressIfNotAlready (address) {

@ -38,6 +38,29 @@ class AccountTracker extends EventEmitter {
// public // public
// //
syncWithAddresses (addresses) {
const accounts = this.store.getState().accounts
const locals = Object.keys(accounts)
const toAdd = []
addresses.forEach((upstream) => {
if (!locals.includes(upstream)) {
toAdd.push(upstream)
}
})
const toRemove = []
locals.forEach((local) => {
if (!addresses.includes(local)) {
toRemove.push(local)
}
})
toAdd.forEach(upstream => this.addAccount(upstream))
toRemove.forEach(local => this.removeAccount(local))
this._updateAccounts()
}
addAccount (address) { addAccount (address) {
const accounts = this.store.getState().accounts const accounts = this.store.getState().accounts
accounts[address] = {} accounts[address] = {}

@ -1,6 +1,5 @@
const EventEmitter = require('events') const EventEmitter = require('events')
const extend = require('xtend') const extend = require('xtend')
const promiseToCallback = require('promise-to-callback')
const pump = require('pump') const pump = require('pump')
const Dnode = require('dnode') const Dnode = require('dnode')
const ObservableStore = require('obs-store') const ObservableStore = require('obs-store')
@ -96,25 +95,20 @@ module.exports = class MetamaskController extends EventEmitter {
// key mgmt // key mgmt
this.keyringController = new KeyringController({ this.keyringController = new KeyringController({
initState: initState.KeyringController, initState: initState.KeyringController,
accountTracker: this.accountTracker,
getNetwork: this.networkController.getNetworkState.bind(this.networkController), getNetwork: this.networkController.getNetworkState.bind(this.networkController),
encryptor: opts.encryptor || undefined, encryptor: opts.encryptor || undefined,
}) })
// If only one account exists, make sure it is selected. // If only one account exists, make sure it is selected.
this.keyringController.store.subscribe((state) => { this.keyringController.memStore.subscribe((state) => {
const addresses = Object.keys(state.walletNicknames || {}) const addresses = state.keyrings.reduce((res, keyring) => {
return res.concat(keyring.accounts)
}, [])
if (addresses.length === 1) { if (addresses.length === 1) {
const address = addresses[0] const address = addresses[0]
this.preferencesController.setSelectedAddress(address) this.preferencesController.setSelectedAddress(address)
} }
}) this.accountTracker.syncWithAddresses(addresses)
this.keyringController.on('newAccount', (address) => {
this.preferencesController.setSelectedAddress(address)
this.accountTracker.addAccount(address)
})
this.keyringController.on('removedAccount', (address) => {
this.accountTracker.removeAccount(address)
}) })
// address book controller // address book controller
@ -329,13 +323,13 @@ module.exports = class MetamaskController extends EventEmitter {
createShapeShiftTx: this.createShapeShiftTx.bind(this), createShapeShiftTx: this.createShapeShiftTx.bind(this),
// primary HD keyring management // primary HD keyring management
addNewAccount: this.addNewAccount.bind(this), addNewAccount: nodeify(this.addNewAccount, this),
placeSeedWords: this.placeSeedWords.bind(this), placeSeedWords: this.placeSeedWords.bind(this),
clearSeedWordCache: this.clearSeedWordCache.bind(this), clearSeedWordCache: this.clearSeedWordCache.bind(this),
importAccountWithStrategy: this.importAccountWithStrategy.bind(this), importAccountWithStrategy: this.importAccountWithStrategy.bind(this),
// vault management // vault management
submitPassword: this.submitPassword.bind(this), submitPassword: nodeify(keyringController.submitPassword, keyringController),
// network management // network management
setProviderType: nodeify(networkController.setProviderType, networkController), setProviderType: nodeify(networkController.setProviderType, networkController),
@ -352,8 +346,8 @@ module.exports = class MetamaskController extends EventEmitter {
// KeyringController // KeyringController
setLocked: nodeify(keyringController.setLocked, keyringController), setLocked: nodeify(keyringController.setLocked, keyringController),
createNewVaultAndKeychain: nodeify(keyringController.createNewVaultAndKeychain, keyringController), createNewVaultAndKeychain: nodeify(this.createNewVaultAndKeychain, this),
createNewVaultAndRestore: nodeify(keyringController.createNewVaultAndRestore, keyringController), createNewVaultAndRestore: nodeify(this.createNewVaultAndRestore, this),
addNewKeyring: nodeify(keyringController.addNewKeyring, keyringController), addNewKeyring: nodeify(keyringController.addNewKeyring, keyringController),
saveAccountLabel: nodeify(keyringController.saveAccountLabel, keyringController), saveAccountLabel: nodeify(keyringController.saveAccountLabel, keyringController),
exportAccount: nodeify(keyringController.exportAccount, keyringController), exportAccount: nodeify(keyringController.exportAccount, keyringController),
@ -474,20 +468,43 @@ module.exports = class MetamaskController extends EventEmitter {
// Vault Management // Vault Management
// //
submitPassword (password, cb) { async createNewVaultAndKeychain (password, cb) {
return this.keyringController.submitPassword(password) const vault = await this.keyringController.createNewVaultAndKeychain(password)
.then((newState) => { cb(null, newState) }) this.selectFirstIdentity(vault)
.catch((reason) => { cb(reason) }) return vault
}
async createNewVaultAndRestore (password, seed, cb) {
const vault = await this.keyringController.createNewVaultAndRestore(password, seed)
this.selectFirstIdentity(vault)
return vault
}
selectFirstIdentity (vault) {
const { identities } = vault
const address = Object.keys(identities)[0]
this.preferencesController.setSelectedAddress(address)
} }
// //
// Opinionated Keyring Management // Opinionated Keyring Management
// //
addNewAccount (cb) { async addNewAccount (cb) {
const primaryKeyring = this.keyringController.getKeyringsByType('HD Key Tree')[0] const primaryKeyring = this.keyringController.getKeyringsByType('HD Key Tree')[0]
if (!primaryKeyring) return cb(new Error('MetamaskController - No HD Key Tree found')) if (!primaryKeyring) return cb(new Error('MetamaskController - No HD Key Tree found'))
promiseToCallback(this.keyringController.addNewAccount(primaryKeyring))(cb) const keyringController = this.keyringController
const oldAccounts = await keyringController.getAccounts()
const keyState = await keyringController.addNewAccount(primaryKeyring)
const newAccounts = await keyringController.getAccounts()
newAccounts.forEach((address) => {
if (!oldAccounts.includes(address)) {
this.preferencesController.setSelectedAddress(address)
}
})
return keyState
} }
// Adds the current vault's seed words to the UI's state tree. // Adds the current vault's seed words to the UI's state tree.

@ -77,8 +77,8 @@
"eth-block-tracker": "^2.2.0", "eth-block-tracker": "^2.2.0",
"eth-hd-keyring": "^1.2.1", "eth-hd-keyring": "^1.2.1",
"eth-json-rpc-filters": "^1.2.2", "eth-json-rpc-filters": "^1.2.2",
"eth-keyring-controller": "^2.1.0",
"eth-contract-metadata": "^1.1.5", "eth-contract-metadata": "^1.1.5",
"eth-keyring-controller": "^2.1.2",
"eth-phishing-detect": "^1.1.4", "eth-phishing-detect": "^1.1.4",
"eth-query": "^2.1.2", "eth-query": "^2.1.2",
"eth-sig-util": "^1.4.0", "eth-sig-util": "^1.4.0",
@ -149,7 +149,7 @@
"redux-logger": "^3.0.6", "redux-logger": "^3.0.6",
"redux-thunk": "^2.2.0", "redux-thunk": "^2.2.0",
"request-promise": "^4.2.1", "request-promise": "^4.2.1",
"sandwich-expando": "^1.0.5", "sandwich-expando": "^1.1.3",
"semaphore": "^1.0.5", "semaphore": "^1.0.5",
"shallow-copy": "0.0.1", "shallow-copy": "0.0.1",
"sw-stream": "^2.0.0", "sw-stream": "^2.0.0",

@ -43,7 +43,12 @@ function rootReducer (state, action) {
window.logState = function () { window.logState = function () {
let state = window.METAMASK_CACHED_LOG_STATE let state = window.METAMASK_CACHED_LOG_STATE
const version = global.platform.getVersion() let version
try {
version = global.platform.getVersion()
} catch (e) {
version = 'unable to load version.'
}
state.version = version state.version = version
let stateString = JSON.stringify(state, removeSeedWords, 2) let stateString = JSON.stringify(state, removeSeedWords, 2)
return stateString return stateString

Loading…
Cancel
Save