aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWhymarrh Whitby <whymarrh.whitby@gmail.com>2018-08-23 02:58:17 +0800
committerGitHub <noreply@github.com>2018-08-23 02:58:17 +0800
commit171f6711d988cdfe04badee6f1b445a3abf513ad (patch)
tree7844a2eb8e5dfa3487f3f204a923600c3ca59456
parent21a6fdc1748424e84d12156552d344c622c03dd1 (diff)
parente803b8e047b5acad9143fe28d99d9e7d65211f46 (diff)
downloadtangerine-wallet-browser-171f6711d988cdfe04badee6f1b445a3abf513ad.tar.gz
tangerine-wallet-browser-171f6711d988cdfe04badee6f1b445a3abf513ad.tar.zst
tangerine-wallet-browser-171f6711d988cdfe04badee6f1b445a3abf513ad.zip
Merge pull request #5066 from whymarrh/fix-key-export
Don't re-render the export modal when the selected identity changes
-rw-r--r--app/scripts/metamask-controller.js42
-rw-r--r--test/unit/app/controllers/metamask-controller-test.js71
-rw-r--r--ui/app/components/modals/account-modal-container.js4
-rw-r--r--ui/app/components/modals/export-private-key-modal.js25
4 files changed, 119 insertions, 23 deletions
diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js
index 29838ad2d..4ee88186a 100644
--- a/app/scripts/metamask-controller.js
+++ b/app/scripts/metamask-controller.js
@@ -137,19 +137,7 @@ module.exports = class MetamaskController extends EventEmitter {
encryptor: opts.encryptor || undefined,
})
- // If only one account exists, make sure it is selected.
- this.keyringController.memStore.subscribe((state) => {
- const addresses = state.keyrings.reduce((res, keyring) => {
- return res.concat(keyring.accounts)
- }, [])
- if (addresses.length === 1) {
- const address = addresses[0]
- this.preferencesController.setSelectedAddress(address)
- }
- // ensure preferences + identities controller know about all addresses
- this.preferencesController.addAddresses(addresses)
- this.accountTracker.syncWithAddresses(addresses)
- })
+ this.keyringController.memStore.subscribe((s) => this._onKeyringControllerUpdate(s))
// detect tokens controller
this.detectTokensController = new DetectTokensController({
@@ -1279,6 +1267,34 @@ module.exports = class MetamaskController extends EventEmitter {
}
/**
+ * Handle a KeyringController update
+ * @param {object} state the KC state
+ * @return {Promise<void>}
+ * @private
+ */
+ async _onKeyringControllerUpdate (state) {
+ const {isUnlocked, keyrings} = state
+ const addresses = keyrings.reduce((acc, {accounts}) => acc.concat(accounts), [])
+
+ if (!addresses.length) {
+ return
+ }
+
+ // Ensure preferences + identities controller know about all addresses
+ this.preferencesController.addAddresses(addresses)
+ this.accountTracker.syncWithAddresses(addresses)
+
+ const wasLocked = !isUnlocked
+ if (wasLocked) {
+ const oldSelectedAddress = this.preferencesController.getSelectedAddress()
+ if (!addresses.includes(oldSelectedAddress)) {
+ const address = addresses[0]
+ await this.preferencesController.setSelectedAddress(address)
+ }
+ }
+ }
+
+ /**
* A method for emitting the full MetaMask state to all registered listeners.
* @private
*/
diff --git a/test/unit/app/controllers/metamask-controller-test.js b/test/unit/app/controllers/metamask-controller-test.js
index a798d41e2..85c78fe1e 100644
--- a/test/unit/app/controllers/metamask-controller-test.js
+++ b/test/unit/app/controllers/metamask-controller-test.js
@@ -814,6 +814,77 @@ describe('MetaMaskController', function () {
})
})
+ describe('#_onKeyringControllerUpdate', function () {
+ it('should do nothing if there are no keyrings in state', async function () {
+ const addAddresses = sinon.fake()
+ const syncWithAddresses = sinon.fake()
+ sandbox.replace(metamaskController, 'preferencesController', {
+ addAddresses,
+ })
+ sandbox.replace(metamaskController, 'accountTracker', {
+ syncWithAddresses,
+ })
+
+ const oldState = metamaskController.getState()
+ await metamaskController._onKeyringControllerUpdate({keyrings: []})
+
+ assert.ok(addAddresses.notCalled)
+ assert.ok(syncWithAddresses.notCalled)
+ assert.deepEqual(metamaskController.getState(), oldState)
+ })
+
+ it('should update selected address if keyrings was locked', async function () {
+ const addAddresses = sinon.fake()
+ const getSelectedAddress = sinon.fake.returns('0x42')
+ const setSelectedAddress = sinon.fake()
+ const syncWithAddresses = sinon.fake()
+ sandbox.replace(metamaskController, 'preferencesController', {
+ addAddresses,
+ getSelectedAddress,
+ setSelectedAddress,
+ })
+ sandbox.replace(metamaskController, 'accountTracker', {
+ syncWithAddresses,
+ })
+
+ const oldState = metamaskController.getState()
+ await metamaskController._onKeyringControllerUpdate({
+ isUnlocked: false,
+ keyrings: [{
+ accounts: ['0x1', '0x2'],
+ }],
+ })
+
+ assert.deepEqual(addAddresses.args, [[['0x1', '0x2']]])
+ assert.deepEqual(syncWithAddresses.args, [[['0x1', '0x2']]])
+ assert.deepEqual(setSelectedAddress.args, [['0x1']])
+ assert.deepEqual(metamaskController.getState(), oldState)
+ })
+
+ it('should NOT update selected address if already unlocked', async function () {
+ const addAddresses = sinon.fake()
+ const syncWithAddresses = sinon.fake()
+ sandbox.replace(metamaskController, 'preferencesController', {
+ addAddresses,
+ })
+ sandbox.replace(metamaskController, 'accountTracker', {
+ syncWithAddresses,
+ })
+
+ const oldState = metamaskController.getState()
+ await metamaskController._onKeyringControllerUpdate({
+ isUnlocked: true,
+ keyrings: [{
+ accounts: ['0x1', '0x2'],
+ }],
+ })
+
+ assert.deepEqual(addAddresses.args, [[['0x1', '0x2']]])
+ assert.deepEqual(syncWithAddresses.args, [[['0x1', '0x2']]])
+ assert.deepEqual(metamaskController.getState(), oldState)
+ })
+ })
+
})
function deferredPromise () {
diff --git a/ui/app/components/modals/account-modal-container.js b/ui/app/components/modals/account-modal-container.js
index a9856b20f..aa0593df8 100644
--- a/ui/app/components/modals/account-modal-container.js
+++ b/ui/app/components/modals/account-modal-container.js
@@ -7,9 +7,9 @@ const actions = require('../../actions')
const { getSelectedIdentity } = require('../../selectors')
const Identicon = require('../identicon')
-function mapStateToProps (state) {
+function mapStateToProps (state, ownProps) {
return {
- selectedIdentity: getSelectedIdentity(state),
+ selectedIdentity: ownProps.selectedIdentity || getSelectedIdentity(state),
}
}
diff --git a/ui/app/components/modals/export-private-key-modal.js b/ui/app/components/modals/export-private-key-modal.js
index 80ece425f..99b61bf9d 100644
--- a/ui/app/components/modals/export-private-key-modal.js
+++ b/ui/app/components/modals/export-private-key-modal.js
@@ -11,13 +11,21 @@ const ReadOnlyInput = require('../readonly-input')
const copyToClipboard = require('copy-to-clipboard')
const { checksumAddress } = require('../../util')
-function mapStateToProps (state) {
- return {
- warning: state.appState.warning,
- privateKey: state.appState.accountDetail.privateKey,
- network: state.metamask.network,
- selectedIdentity: getSelectedIdentity(state),
- previousModalState: state.appState.modal.previousModalState.name,
+function mapStateToPropsFactory () {
+ let selectedIdentity = null
+ return function mapStateToProps (state) {
+ // We should **not** change the identity displayed here even if it changes from underneath us.
+ // If we do, we will be showing the user one private key and a **different** address and name.
+ // Note that the selected identity **will** change from underneath us when we unlock the keyring
+ // which is the expected behavior that we are side-stepping.
+ selectedIdentity = selectedIdentity || getSelectedIdentity(state)
+ return {
+ warning: state.appState.warning,
+ privateKey: state.appState.accountDetail.privateKey,
+ network: state.metamask.network,
+ selectedIdentity,
+ previousModalState: state.appState.modal.previousModalState.name,
+ }
}
}
@@ -43,7 +51,7 @@ ExportPrivateKeyModal.contextTypes = {
t: PropTypes.func,
}
-module.exports = connect(mapStateToProps, mapDispatchToProps)(ExportPrivateKeyModal)
+module.exports = connect(mapStateToPropsFactory, mapDispatchToProps)(ExportPrivateKeyModal)
ExportPrivateKeyModal.prototype.exportAccountAndGetPrivateKey = function (password, address) {
@@ -113,6 +121,7 @@ ExportPrivateKeyModal.prototype.render = function () {
const { privateKey } = this.state
return h(AccountModalContainer, {
+ selectedIdentity,
showBackButton: previousModalState === 'ACCOUNT_DETAILS',
backButtonAction: () => showAccountDetailModal(),
}, [