aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/scripts/keyring-controller.js120
-rw-r--r--app/scripts/migrations/005.js41
-rw-r--r--app/scripts/migrations/index.js1
-rw-r--r--package.json2
-rw-r--r--test/unit/idStore-migration-test.js3
-rw-r--r--test/unit/keyring-controller-test.js56
-rw-r--r--ui/app/account-detail.js5
-rw-r--r--ui/app/accounts/account-list-item.js5
-rw-r--r--ui/app/first-time/init-menu.js1
9 files changed, 122 insertions, 112 deletions
diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js
index 460c71e27..68fc6e882 100644
--- a/app/scripts/keyring-controller.js
+++ b/app/scripts/keyring-controller.js
@@ -6,7 +6,7 @@ const ObservableStore = require('obs-store')
const filter = require('promise-filter')
const encryptor = require('browser-passworder')
const createId = require('./lib/random-id')
-const normalize = require('./lib/sig-util').normalize
+const normalizeAddress = require('./lib/sig-util').normalize
const messageManager = require('./lib/message-manager')
function noop () {}
@@ -74,28 +74,31 @@ class KeyringController extends EventEmitter {
// in this class, but will need to be Promisified when we move our
// persistence to an async model.
getState () {
- const configManager = this.configManager
- const address = configManager.getSelectedAccount()
- const wallet = configManager.getWallet() // old style vault
- const vault = configManager.getVault() // new style vault
- const keyrings = this.keyrings
-
- return Promise.all(keyrings.map(this.displayForKeyring))
+ return Promise.all(this.keyrings.map(this.displayForKeyring))
.then((displayKeyrings) => {
+ const state = this.store.getState()
+ // old wallet
+ const wallet = this.configManager.getWallet()
return {
+ // computed
+ isInitialized: (!!wallet || !!state.vault),
+ isUnlocked: (!!this.password),
+ keyrings: displayKeyrings,
+ // hard coded
+ keyringTypes: this.keyringTypes.map(krt => krt.type),
+ // memStore
+ identities: this.identities,
+ // diskStore
+ selectedAccount: state.selectedAccount,
+ // configManager
seedWords: this.configManager.getSeedWords(),
- isInitialized: (!!wallet || !!vault),
- isUnlocked: Boolean(this.password),
isDisclaimerConfirmed: this.configManager.getConfirmedDisclaimer(),
- unconfMsgs: messageManager.unconfirmedMsgs(),
- messages: messageManager.getMsgList(),
- selectedAccount: address,
currentFiat: this.configManager.getCurrentFiat(),
conversionRate: this.configManager.getConversionRate(),
conversionDate: this.configManager.getConversionDate(),
- keyringTypes: this.keyringTypes.map(krt => krt.type),
- identities: this.identities,
- keyrings: displayKeyrings,
+ // messageManager
+ unconfMsgs: messageManager.unconfirmedMsgs(),
+ messages: messageManager.getMsgList(),
}
})
}
@@ -148,8 +151,8 @@ class KeyringController extends EventEmitter {
.then((accounts) => {
const firstAccount = accounts[0]
if (!firstAccount) throw new Error('KeyringController - First Account not found.')
- const hexAccount = normalize(firstAccount)
- this.configManager.setSelectedAccount(hexAccount)
+ const hexAccount = normalizeAddress(firstAccount)
+ this.setSelectedAccount(hexAccount)
return this.setupAccounts(accounts)
})
.then(this.persistAllKeyrings.bind(this, password))
@@ -235,9 +238,9 @@ class KeyringController extends EventEmitter {
//
// Sets the state's `selectedAccount` value
// to the specified address.
- setSelectedAccount (address) {
- var addr = normalize(address)
- this.configManager.setSelectedAccount(addr)
+ setSelectedAccount (account) {
+ var address = normalizeAddress(account)
+ this.store.updateState({ selectedAccount: address })
return this.fullUpdate()
}
@@ -249,11 +252,19 @@ class KeyringController extends EventEmitter {
//
// Persists a nickname equal to `label` for the specified account.
saveAccountLabel (account, label) {
- const address = normalize(account)
- const configManager = this.configManager
- configManager.setNicknameForWallet(address, label)
- this.identities[address].name = label
- return Promise.resolve(label)
+ try {
+ const hexAddress = normalizeAddress(account)
+ // update state on diskStore
+ const state = this.store.getState()
+ const walletNicknames = state.walletNicknames || {}
+ walletNicknames[hexAddress] = label
+ this.store.updateState({ walletNicknames })
+ // update state on memStore
+ this.identities[hexAddress].name = label
+ return Promise.resolve(label)
+ } catch (err) {
+ return Promise.reject(err)
+ }
}
// Export Account
@@ -269,7 +280,7 @@ class KeyringController extends EventEmitter {
try {
return this.getKeyringForAccount(address)
.then((keyring) => {
- return keyring.exportAccount(normalize(address))
+ return keyring.exportAccount(normalizeAddress(address))
})
} catch (e) {
return Promise.reject(e)
@@ -283,7 +294,7 @@ class KeyringController extends EventEmitter {
// TX Manager to update the state after signing
signTransaction (ethTx, _fromAddress) {
- const fromAddress = normalize(_fromAddress)
+ const fromAddress = normalizeAddress(_fromAddress)
return this.getKeyringForAccount(fromAddress)
.then((keyring) => {
return keyring.signTransaction(fromAddress, ethTx)
@@ -356,7 +367,7 @@ class KeyringController extends EventEmitter {
delete msgParams.metamaskId
const approvalCb = this._unconfMsgCbs[msgId] || noop
- const address = normalize(msgParams.from)
+ const address = normalizeAddress(msgParams.from)
return this.getKeyringForAccount(address)
.then((keyring) => {
return keyring.signMessage(address, msgParams.data)
@@ -394,8 +405,8 @@ class KeyringController extends EventEmitter {
.then((accounts) => {
const firstAccount = accounts[0]
if (!firstAccount) throw new Error('KeyringController - No account found on keychain.')
- const hexAccount = normalize(firstAccount)
- this.configManager.setSelectedAccount(hexAccount)
+ const hexAccount = normalizeAddress(firstAccount)
+ this.setSelectedAccount(hexAccount)
this.emit('newAccount', hexAccount)
return this.setupAccounts(accounts)
})
@@ -431,7 +442,7 @@ class KeyringController extends EventEmitter {
if (!account) {
throw new Error('Problem loading account.')
}
- const address = normalize(account)
+ const address = normalizeAddress(account)
this.ethStore.addAccount(address)
return this.createNickname(address)
}
@@ -443,10 +454,11 @@ class KeyringController extends EventEmitter {
//
// Takes an address, and assigns it an incremented nickname, persisting it.
createNickname (address) {
- const hexAddress = normalize(address)
- var i = Object.keys(this.identities).length
- const oldNickname = this.configManager.nicknameForWallet(address)
- const name = oldNickname || `Account ${++i}`
+ const hexAddress = normalizeAddress(address)
+ const currentIdentityCount = Object.keys(this.identities).length + 1
+ const nicknames = this.store.getState().walletNicknames || {}
+ const existingNickname = nicknames[hexAddress]
+ const name = existingNickname || `Account ${currentIdentityCount}`
this.identities[hexAddress] = {
address: hexAddress,
name,
@@ -481,7 +493,7 @@ class KeyringController extends EventEmitter {
return this.encryptor.encrypt(this.password, serializedKeyrings)
})
.then((encryptedString) => {
- this.configManager.setVault(encryptedString)
+ this.store.updateState({ vault: encryptedString })
return true
})
}
@@ -494,7 +506,7 @@ class KeyringController extends EventEmitter {
// Attempts to unlock the persisted encrypted storage,
// initializing the persisted keyrings to RAM.
unlockKeyrings (password) {
- const encryptedVault = this.configManager.getVault()
+ const encryptedVault = this.store.getState().vault
if (!encryptedVault) {
throw new Error('Cannot unlock without a previous vault.')
}
@@ -574,7 +586,7 @@ class KeyringController extends EventEmitter {
// Returns the currently initialized keyring that manages
// the specified `address` if one exists.
getKeyringForAccount (address) {
- const hexed = normalize(address)
+ const hexed = normalizeAddress(address)
return Promise.all(this.keyrings.map((keyring) => {
return Promise.all([
@@ -583,7 +595,7 @@ class KeyringController extends EventEmitter {
])
}))
.then(filter((candidate) => {
- const accounts = candidate[1].map(normalize)
+ const accounts = candidate[1].map(normalizeAddress)
return accounts.includes(hexed)
}))
.then((winners) => {
@@ -641,35 +653,9 @@ class KeyringController extends EventEmitter {
this.keyrings = []
this.identities = {}
- this.configManager.setSelectedAccount()
+ this.setSelectedAccount()
}
}
-//
-// Static Class Methods
-//
-
-KeyringController.selectFromState = (state) => {
- const config = state.config
- return {
- vault: state.vault,
- selectedAccount: config.selectedAccount,
- walletNicknames: state.walletNicknames,
- }
-}
-
-KeyringController.flattenToOldState = (state) => {
- const data = {
- vault: state.vault,
- walletNicknames: state.walletNicknames,
- config: {
- selectedAccount: state.selectedAccount,
- },
- }
- return data
-}
-
-
module.exports = KeyringController
-
diff --git a/app/scripts/migrations/005.js b/app/scripts/migrations/005.js
new file mode 100644
index 000000000..65f62a861
--- /dev/null
+++ b/app/scripts/migrations/005.js
@@ -0,0 +1,41 @@
+const version = 5
+
+/*
+
+This migration moves state from the flat state trie into KeyringController substate
+
+*/
+
+const extend = require('xtend')
+
+module.exports = {
+ version,
+
+ migrate: function (versionedData) {
+ versionedData.meta.version = version
+ try {
+ const state = versionedData.data
+ const newState = selectSubstateForKeyringController(state)
+ versionedData.data = newState
+ } catch (err) {
+ console.warn('MetaMask Migration #5' + err.stack)
+ }
+ return Promise.resolve(versionedData)
+ },
+}
+
+function selectSubstateForKeyringController (state) {
+ const config = state.config
+ const newState = extend(state, {
+ KeyringController: {
+ vault: state.vault,
+ selectedAccount: config.selectedAccount,
+ walletNicknames: state.walletNicknames,
+ },
+ })
+ delete newState.vault
+ delete newState.walletNicknames
+ delete newState.config.selectedAccount
+
+ return newState
+}
diff --git a/app/scripts/migrations/index.js b/app/scripts/migrations/index.js
index d2ac221b9..a7ce745e7 100644
--- a/app/scripts/migrations/index.js
+++ b/app/scripts/migrations/index.js
@@ -15,4 +15,5 @@ module.exports = [
require('./002'),
require('./003'),
require('./004'),
+ require('./005'),
]
diff --git a/package.json b/package.json
index bf4b3986c..2a46ab6bd 100644
--- a/package.json
+++ b/package.json
@@ -70,7 +70,7 @@
"mississippi": "^1.2.0",
"mkdirp": "^0.5.1",
"multiplex": "^6.7.0",
- "obs-store": "^2.2.3",
+ "obs-store": "^2.3.0",
"once": "^1.3.3",
"ping-pong-stream": "^1.0.0",
"pojo-migrator": "^2.1.0",
diff --git a/test/unit/idStore-migration-test.js b/test/unit/idStore-migration-test.js
index 47894a458..3aaf4bb94 100644
--- a/test/unit/idStore-migration-test.js
+++ b/test/unit/idStore-migration-test.js
@@ -89,6 +89,9 @@ describe('IdentityStore to KeyringController migration', function() {
assert(!state.lostAccounts, 'no lost accounts')
done()
})
+ .catch((err) => {
+ done(err)
+ })
})
})
})
diff --git a/test/unit/keyring-controller-test.js b/test/unit/keyring-controller-test.js
index d6d2db817..347aa2bdf 100644
--- a/test/unit/keyring-controller-test.js
+++ b/test/unit/keyring-controller-test.js
@@ -1,6 +1,6 @@
-var assert = require('assert')
-var KeyringController = require('../../app/scripts/keyring-controller')
-var configManagerGen = require('../lib/mock-config-manager')
+const assert = require('assert')
+const KeyringController = require('../../app/scripts/keyring-controller')
+const configManagerGen = require('../lib/mock-config-manager')
const ethUtil = require('ethereumjs-util')
const BN = ethUtil.BN
const async = require('async')
@@ -55,17 +55,16 @@ describe('KeyringController', function() {
this.timeout(10000)
it('should set a vault on the configManager', function(done) {
- keyringController.configManager.setVault(null)
- assert(!keyringController.configManager.getVault(), 'no previous vault')
+ keyringController.store.updateState({ vault: null })
+ assert(!keyringController.store.getState().vault, 'no previous vault')
keyringController.createNewVaultAndKeychain(password)
.then(() => {
- const vault = keyringController.configManager.getVault()
+ const vault = keyringController.store.getState().vault
assert(vault, 'vault created')
done()
})
.catch((reason) => {
- assert.ifError(reason)
- done()
+ done(reason)
})
})
})
@@ -96,8 +95,7 @@ describe('KeyringController', function() {
done()
})
.catch((reason) => {
- assert.ifError(reason)
- done()
+ done(reason)
})
})
})
@@ -109,9 +107,6 @@ describe('KeyringController', function() {
const identities = keyringController.identities
const identity = identities[fakeAddress]
assert.equal(identity.address, fakeAddress)
-
- const nick = keyringController.configManager.nicknameForWallet(fakeAddress)
- assert.equal(typeof nick, 'string')
})
})
@@ -122,34 +117,17 @@ describe('KeyringController', function() {
keyringController.identities[ethUtil.addHexPrefix(account)] = {}
keyringController.saveAccountLabel(account, nick)
.then((label) => {
- assert.equal(label, nick)
- const persisted = keyringController.configManager.nicknameForWallet(account)
- assert.equal(persisted, nick)
- done()
- })
- .catch((reason) => {
- assert.ifError(reason)
- done()
- })
- })
-
- this.timeout(10000)
- it('retrieves the persisted nickname', function(done) {
- const account = addresses[0]
- var nick = 'Test nickname'
- keyringController.configManager.setNicknameForWallet(account, nick)
- keyringController.createNewVaultAndRestore(password, seedWords)
- .then((state) => {
-
- const identity = keyringController.identities['0x' + account]
- assert.equal(identity.name, nick)
-
- assert(accounts)
- done()
+ try {
+ assert.equal(label, nick)
+ const persisted = keyringController.store.getState().walletNicknames[account]
+ assert.equal(persisted, nick)
+ done()
+ } catch (err) {
+ done()
+ }
})
.catch((reason) => {
- assert.ifError(reason)
- done()
+ done(reason)
})
})
})
diff --git a/ui/app/account-detail.js b/ui/app/account-detail.js
index 387a1720a..0bcfbcaab 100644
--- a/ui/app/account-detail.js
+++ b/ui/app/account-detail.js
@@ -41,6 +41,7 @@ function AccountDetailScreen () {
AccountDetailScreen.prototype.render = function () {
var props = this.props
var selected = props.address || Object.keys(props.accounts)[0]
+ var checksumAddress = selected && ethUtil.toChecksumAddress(selected)
var identity = props.identities[selected]
var account = props.accounts[selected]
const { network } = props
@@ -116,7 +117,7 @@ AccountDetailScreen.prototype.render = function () {
marginBottom: '15px',
color: '#AEAEAE',
},
- }, ethUtil.toChecksumAddress(selected)),
+ }, checksumAddress),
// copy and export
@@ -129,7 +130,7 @@ AccountDetailScreen.prototype.render = function () {
h(AccountInfoLink, { selected, network }),
h(CopyButton, {
- value: ethUtil.toChecksumAddress(selected),
+ value: checksumAddress,
}),
h(Tooltip, {
diff --git a/ui/app/accounts/account-list-item.js b/ui/app/accounts/account-list-item.js
index 16019c88a..74ecef07f 100644
--- a/ui/app/accounts/account-list-item.js
+++ b/ui/app/accounts/account-list-item.js
@@ -17,6 +17,7 @@ function AccountListItem () {
AccountListItem.prototype.render = function () {
const { identity, selectedAccount, accounts, onShowDetail } = this.props
+ const checksumAddress = identity && identity.address && ethUtil.toChecksumAddress(identity.address)
const isSelected = selectedAccount === identity.address
const account = accounts[identity.address]
const selectedClass = isSelected ? '.selected' : ''
@@ -48,7 +49,7 @@ AccountListItem.prototype.render = function () {
overflow: 'hidden',
textOverflow: 'ellipsis',
},
- }, ethUtil.toChecksumAddress(identity.address)),
+ }, checksumAddress),
h(EthBalance, {
value: account && account.balance,
style: {
@@ -65,7 +66,7 @@ AccountListItem.prototype.render = function () {
},
}, [
h(CopyButton, {
- value: ethUtil.toChecksumAddress(identity.address),
+ value: checksumAddress,
}),
]),
])
diff --git a/ui/app/first-time/init-menu.js b/ui/app/first-time/init-menu.js
index 152d28809..cc7c51bd3 100644
--- a/ui/app/first-time/init-menu.js
+++ b/ui/app/first-time/init-menu.js
@@ -152,7 +152,6 @@ InitializeMenuScreen.prototype.createNewVaultAndKeychain = function () {
var password = passwordBox.value
var passwordConfirmBox = document.getElementById('password-box-confirm')
var passwordConfirm = passwordConfirmBox.value
- // var entropy = document.getElementById('entropy-text-entry').value
if (password.length < 8) {
this.warning = 'password not long enough'