From b40bcbdb4a52ef73982dd882124ea2c2742eef1a Mon Sep 17 00:00:00 2001 From: Victor Baranov Date: Mon, 13 Apr 2020 22:22:23 +0300 Subject: [PATCH] Fix `accountsChanged` event emittance (a part of EIP-1193) --- CHANGELOG.md | 1 + app/scripts/background.js | 4 +- app/scripts/controllers/permissions/index.js | 35 +- app/scripts/inpage.js | 17 - app/scripts/lib/ComposableObservableStore.js | 30 +- app/scripts/metamask-controller.js | 323 ++++++++++--------- package-lock.json | 48 +-- package.json | 2 +- ui/app/actions.js | 35 ++ 9 files changed, 238 insertions(+), 257 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 288423913..9a48e7261 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Current Master +- [#354](https://github.com/poanetwork/nifty-wallet/pull/354) - Fix `accountsChanged` event emittance (a part of EIP-1193) - [#353](https://github.com/poanetwork/nifty-wallet/pull/353) - Fix synchronous eth_accounts request ## 5.0.1 Mon Apr 06 2020 diff --git a/app/scripts/background.js b/app/scripts/background.js index becb4320e..c30ac7bce 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -145,7 +145,6 @@ setupMetamaskMeshMetrics() * @property {Object} infuraNetworkStatus - An object of infura network status checks. * @property {Block[]} recentBlocks - An array of recent blocks, used to calculate an effective but cheap gas price. * @property {Array} shapeShiftTxList - An array of objects describing shapeshift exchange attempts. - * @property {Array} lostAccounts - TODO: Remove this feature. A leftover from the version-3 migration where our seed-phrase library changed to fix a bug where some accounts were mis-generated, but we recovered the old accounts as "lost" instead of losing them. * @property {boolean} forgottenPassword - Returns true if the user has initiated the password recovery screen, is recovering from seed phrase. */ @@ -267,6 +266,9 @@ function setupController (initState, initLangCode) { getRequestAccountTabIds: () => { return requestAccountTabIds }, + getOpenMetamaskTabsIds: () => { + return openMetamaskTabsIDs + }, encryptor: isEdge ? new EdgeEncryptor() : undefined, }) global.metamaskController = controller diff --git a/app/scripts/controllers/permissions/index.js b/app/scripts/controllers/permissions/index.js index 6448360ec..792bba371 100644 --- a/app/scripts/controllers/permissions/index.js +++ b/app/scripts/controllers/permissions/index.js @@ -298,13 +298,18 @@ export class PermissionsController { */ async updatePermittedAccounts (origin, accounts) { - await this.validatePermittedAccounts(accounts) + // await this.validatePermittedAccounts(accounts) - this.permissions.updateCaveatFor( - origin, 'eth_accounts', CAVEAT_NAMES.exposedAccounts, accounts, - ) + // this.permissions.updateCaveatFor( + // origin, 'eth_accounts', CAVEAT_NAMES.exposedAccounts, accounts, + // ) - this.notifyDomain(origin, { + // this.notifyDomain(origin, { + // method: NOTIFICATION_NAMES.accountsChanged, + // result: accounts, + // }) + + this.notifyAllDomains({ method: NOTIFICATION_NAMES.accountsChanged, result: accounts, }) @@ -378,14 +383,14 @@ export class PermissionsController { // if the accounts changed from the perspective of the dapp, // update "last seen" time for the origin and account(s) // exception: no accounts -> no times to update - if ( - payload.method === NOTIFICATION_NAMES.accountsChanged && - Array.isArray(payload.result) - ) { - this.permissionsLog.updateAccountsHistory( - origin, payload.result, - ) - } + // if ( + // payload.method === NOTIFICATION_NAMES.accountsChanged && + // Array.isArray(payload.result) + // ) { + // this.permissionsLog.updateAccountsHistory( + // origin, payload.result, + // ) + // } this._notifyDomain(origin, payload) @@ -448,8 +453,8 @@ export class PermissionsController { // do nothing if the account is not permitted for the origin, or // if it's already first in the array of permitted accounts if ( - !permittedAccounts.includes(account) || - permittedAccounts[0] === account + !permittedAccounts.includes(account) + // || permittedAccounts[0] === account ) { return } diff --git a/app/scripts/inpage.js b/app/scripts/inpage.js index 8daefe853..750ed48f7 100644 --- a/app/scripts/inpage.js +++ b/app/scripts/inpage.js @@ -61,23 +61,6 @@ const inpageProvider = new MetamaskInpageProvider(metamaskStream) // set a high max listener count to avoid unnecesary warnings inpageProvider.setMaxListeners(100) -// Augment the provider with its enable method -inpageProvider.enable = function (options = {}) { - return new Promise((resolve, reject) => { - if (options.mockRejection) { - reject('User rejected account access') - } else { - inpageProvider.sendAsync({ method: 'eth_accounts', params: [] }, (error, response) => { - if (error) { - reject(error) - } else { - resolve(response.result) - } - }) - } - }) -} - // Work around for web3@1.0 deleting the bound `sendAsync` but not the unbound // `sendAsync` method on the prototype, causing `this` reference issues const proxiedInpageProvider = new Proxy(inpageProvider, { diff --git a/app/scripts/lib/ComposableObservableStore.js b/app/scripts/lib/ComposableObservableStore.js index ab9ca88f3..f996f153c 100644 --- a/app/scripts/lib/ComposableObservableStore.js +++ b/app/scripts/lib/ComposableObservableStore.js @@ -1,4 +1,4 @@ -const ObservableStore = require('obs-store') +import ObservableStore from 'obs-store' /** * An ObservableStore that can composes a flat @@ -46,34 +46,6 @@ class ComposableObservableStore extends ObservableStore { } return flatState } - - /** - * Merges all child store state into a single object rather than - * returning an object keyed by child store class name - * Removes heavy objects that are not needed on UI - * - * @returns {Object} - Object containing merged child store state - */ - getFilteredFlatState () { - let flatState = {} - for (const key in this.config) { - let nextState - if (key === 'RecentBlocksController') { - nextState = {} - } else if (key === 'TxController') { - const state = this.config[key].getState() - const txList = state.selectedAddressTxList.map(item => ({...item, history: null, nonceDetails: null})) - nextState = { - ...state, - selectedAddressTxList: txList, - } - } else { - nextState = this.config[key].getState() - } - flatState = { ...flatState, ...nextState } - } - return flatState - } } module.exports = ComposableObservableStore diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index d2919a0cf..6f4d4c941 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -42,8 +42,8 @@ const TransactionController = require('./controllers/transactions') const BalancesController = require('./controllers/computed-balances') const TokenRatesController = require('./controllers/token-rates') const DetectTokensController = require('./controllers/detect-tokens') -// import { PermissionsController } from './controllers/permissions' -// import getRestrictedMethods from './controllers/permissions/restrictedMethods' +import { PermissionsController } from './controllers/permissions' +import getRestrictedMethods from './controllers/permissions/restrictedMethods' const nodeify = require('./lib/nodeify') const accountImporter = require('./account-import-strategies') import { Mutex } from 'await-semaphore' @@ -57,7 +57,6 @@ import log from 'loglevel' const TrezorKeyring = require('eth-trezor-keyring') const LedgerBridgeKeyring = require('eth-ledger-bridge-keyring') import EthQuery from 'eth-query' -const sigUtil = require('eth-sig-util') import nanoid from 'nanoid' const { importTypes } = require('../../old-ui/app/accounts/import/enums') const { LEDGER, TREZOR } = require('../../old-ui/app/components/connect-hardware/enum') @@ -208,13 +207,13 @@ module.exports = class MetamaskController extends EventEmitter { this.keyringController.memStore.subscribe((s) => this._onKeyringControllerUpdate(s)) this.keyringController.on('unlock', () => this.emit('unlock')) - // this.permissionsController = new PermissionsController({ - // getKeyringAccounts: this.keyringController.getAccounts.bind(this.keyringController), - // getRestrictedMethods, - // notifyDomain: this.notifyConnections.bind(this), - // notifyAllDomains: this.notifyAllConnections.bind(this), - // platform: opts.platform, - // }, initState.PermissionsController, initState.PermissionsMetadata) + this.permissionsController = new PermissionsController({ + getKeyringAccounts: this.keyringController.getAccounts.bind(this.keyringController), + getRestrictedMethods, + notifyDomain: this.notifyConnections.bind(this), + notifyAllDomains: this.notifyAllConnections.bind(this), + platform: opts.platform, + }, initState.PermissionsController, initState.PermissionsMetadata) // detect tokens controller this.detectTokensController = new DetectTokensController({ @@ -295,8 +294,8 @@ module.exports = class MetamaskController extends EventEmitter { NetworkController: this.networkController.store, InfuraController: this.infuraController.store, CachedBalancesController: this.cachedBalancesController.store, - // PermissionsController: this.permissionsController.permissions, - // PermissionsMetadata: this.permissionsController.store, + PermissionsController: this.permissionsController.permissions, + PermissionsMetadata: this.permissionsController.store, }) this.memStore = new ComposableObservableStore(null, { @@ -319,8 +318,8 @@ module.exports = class MetamaskController extends EventEmitter { NoticeController: this.noticeController.memStore, ShapeshiftController: this.shapeshiftController.store, InfuraController: this.infuraController.store, - // PermissionsController: this.permissionsController.permissions, - // PermissionsMetadata: this.permissionsController.store, + PermissionsController: this.permissionsController.permissions, + PermissionsMetadata: this.permissionsController.store, }) this.memStore.subscribe(this.sendUpdate.bind(this)) } @@ -407,11 +406,7 @@ module.exports = class MetamaskController extends EventEmitter { return { ...{ isInitialized }, - ...this.memStore.getFilteredFlatState(), - ...{ - // TODO: Remove usages of lost accounts - lostAccounts: [], - }, + ...this.memStore.getFlatState(), } } @@ -530,7 +525,7 @@ module.exports = class MetamaskController extends EventEmitter { checkNotices: noticeController.updateNoticesList.bind(noticeController), markNoticeRead: noticeController.markNoticeRead.bind(noticeController), - // // permissions + // permissions // approvePermissionsRequest: nodeify(permissionsController.approvePermissionsRequest, permissionsController), // clearPermissions: permissionsController.clearPermissions.bind(permissionsController), // getApprovedAccounts: nodeify(permissionsController.getAccounts.bind(permissionsController)), @@ -538,7 +533,7 @@ module.exports = class MetamaskController extends EventEmitter { // removePermissionsFor: permissionsController.removePermissionsFor.bind(permissionsController), // updatePermittedAccounts: nodeify(permissionsController.updatePermittedAccounts, permissionsController), // legacyExposeAccounts: nodeify(permissionsController.legacyExposeAccounts, permissionsController), - // handleNewAccountSelected: nodeify(this.handleNewAccountSelected, this), + handleNewAccountSelected: nodeify(this.handleNewAccountSelected, this), } } @@ -1101,6 +1096,17 @@ module.exports = class MetamaskController extends EventEmitter { await this.preferencesController.setSelectedAddress(accounts[0]) } + /** + * Handle when a new account is selected for the given origin in the UI. + * Stores the address by origin and notifies external providers associated + * with the origin. + * @param {string} origin - The origin for which the address was selected. + * @param {string} address - The new selected address. + */ + async handleNewAccountSelected (origin, address) { + this.permissionsController.handleNewAccountSelected(origin, address) + } + // --------------------------------------------------------------------------- // Identity Management (signature operations) @@ -1137,8 +1143,8 @@ module.exports = class MetamaskController extends EventEmitter { /** * Signifies user intent to complete an eth_sign method. * - * @param {Object} msgParams The params passed to eth_call. - * @returns {Promise} Full state update. + * @param {Object} msgParams - The params passed to eth_call. + * @returns {Promise} - Full state update. */ signMessage (msgParams) { log.info('MetaMaskController - signMessage') @@ -1147,16 +1153,16 @@ module.exports = class MetamaskController extends EventEmitter { // sets the status op the message to 'approved' // and removes the metamaskId for signing return this.messageManager.approveMessage(msgParams) - .then((cleanMsgParams) => { + .then((cleanMsgParams) => { // signs the message - return this.keyringController.signMessage(cleanMsgParams) - }) - .then((rawSig) => { + return this.keyringController.signMessage(cleanMsgParams) + }) + .then((rawSig) => { // tells the listener that the message has been signed // and can be returned to the dapp - this.messageManager.setMsgStatusSigned(msgId, rawSig) - return this.getState() - }) + this.messageManager.setMsgStatusSigned(msgId, rawSig) + return this.getState() + }) } /** @@ -1205,16 +1211,16 @@ module.exports = class MetamaskController extends EventEmitter { // sets the status op the message to 'approved' // and removes the metamaskId for signing return this.personalMessageManager.approveMessage(msgParams) - .then((cleanMsgParams) => { + .then((cleanMsgParams) => { // signs the message - return this.keyringController.signPersonalMessage(cleanMsgParams) - }) - .then((rawSig) => { + return this.keyringController.signPersonalMessage(cleanMsgParams) + }) + .then((rawSig) => { // tells the listener that the message has been signed // and can be returned to the dapp - this.personalMessageManager.setMsgStatusSigned(msgId, rawSig) - return this.getState() - }) + this.personalMessageManager.setMsgStatusSigned(msgId, rawSig) + return this.getState() + }) } /** @@ -1239,80 +1245,80 @@ module.exports = class MetamaskController extends EventEmitter { * @param {Object} req - (optional) the original request, containing the origin * Passed back to the requesting Dapp. */ - async newRequestDecryptMessage (msgParams, req) { - const promise = this.decryptMessageManager.addUnapprovedMessageAsync(msgParams, req) - this.sendUpdate() - this.opts.showUnconfirmedMessage() - return promise -} - -/** -* Only decypt message and don't touch transaction state -* -* @param {Object} msgParams - The params of the message to decrypt. -* @returns {Promise} - A full state update. -*/ -async decryptMessageInline (msgParams) { - log.info('MetaMaskController - decryptMessageInline') - // decrypt the message inline - const msgId = msgParams.metamaskId - const msg = this.decryptMessageManager.getMsg(msgId) - try { - const stripped = ethUtil.stripHexPrefix(msgParams.data) - const buff = Buffer.from(stripped, 'hex') - msgParams.data = JSON.parse(buff.toString('utf8')) - - msg.rawData = await this.keyringController.decryptMessage(msgParams) - } catch (e) { - msg.error = e.message + async newRequestDecryptMessage (msgParams, req) { + const promise = this.decryptMessageManager.addUnapprovedMessageAsync(msgParams, req) + this.sendUpdate() + this.opts.showUnconfirmedMessage() + return promise } - this.decryptMessageManager._updateMsg(msg) - return this.getState() -} + /** + * Only decypt message and don't touch transaction state + * + * @param {Object} msgParams - The params of the message to decrypt. + * @returns {Promise} - A full state update. + */ + async decryptMessageInline (msgParams) { + log.info('MetaMaskController - decryptMessageInline') + // decrypt the message inline + const msgId = msgParams.metamaskId + const msg = this.decryptMessageManager.getMsg(msgId) + try { + const stripped = ethUtil.stripHexPrefix(msgParams.data) + const buff = Buffer.from(stripped, 'hex') + msgParams.data = JSON.parse(buff.toString('utf8')) -/** -* Signifies a user's approval to decrypt a message in queue. -* Triggers decrypt, and the callback function from newUnsignedDecryptMessage. -* -* @param {Object} msgParams - The params of the message to decrypt & return to the Dapp. -* @returns {Promise} - A full state update. -*/ -async decryptMessage (msgParams) { - log.info('MetaMaskController - decryptMessage') - const msgId = msgParams.metamaskId - // sets the status op the message to 'approved' - // and removes the metamaskId for decryption - try { - const cleanMsgParams = await this.decryptMessageManager.approveMessage(msgParams) + msg.rawData = await this.keyringController.decryptMessage(msgParams) + } catch (e) { + msg.error = e.message + } + this.decryptMessageManager._updateMsg(msg) - const stripped = ethUtil.stripHexPrefix(cleanMsgParams.data) - const buff = Buffer.from(stripped, 'hex') - cleanMsgParams.data = JSON.parse(buff.toString('utf8')) - - // decrypt the message - const rawMess = await this.keyringController.decryptMessage(cleanMsgParams) - // tells the listener that the message has been decrypted and can be returned to the dapp - this.decryptMessageManager.setMsgStatusDecrypted(msgId, rawMess) - } catch (error) { - log.info('MetaMaskController - eth_decrypt failed.', error) - this.decryptMessageManager.errorMessage(msgId, error) + return this.getState() } - return this.getState() -} -/** - * Used to cancel a eth_decrypt type message. - * @param {string} msgId - The ID of the message to cancel. - * @param {Function} cb - The callback function called with a full state update. - */ -cancelDecryptMessage (msgId, cb) { - const messageManager = this.decryptMessageManager - messageManager.rejectMsg(msgId) - if (cb && typeof cb === 'function') { - cb(null, this.getState()) + /** + * Signifies a user's approval to decrypt a message in queue. + * Triggers decrypt, and the callback function from newUnsignedDecryptMessage. + * + * @param {Object} msgParams - The params of the message to decrypt & return to the Dapp. + * @returns {Promise} - A full state update. + */ + async decryptMessage (msgParams) { + log.info('MetaMaskController - decryptMessage') + const msgId = msgParams.metamaskId + // sets the status op the message to 'approved' + // and removes the metamaskId for decryption + try { + const cleanMsgParams = await this.decryptMessageManager.approveMessage(msgParams) + + const stripped = ethUtil.stripHexPrefix(cleanMsgParams.data) + const buff = Buffer.from(stripped, 'hex') + cleanMsgParams.data = JSON.parse(buff.toString('utf8')) + + // decrypt the message + const rawMess = await this.keyringController.decryptMessage(cleanMsgParams) + // tells the listener that the message has been decrypted and can be returned to the dapp + this.decryptMessageManager.setMsgStatusDecrypted(msgId, rawMess) + } catch (error) { + log.info('MetaMaskController - eth_decrypt failed.', error) + this.decryptMessageManager.errorMessage(msgId, error) + } + return this.getState() + } + + /** + * Used to cancel a eth_decrypt type message. + * @param {string} msgId - The ID of the message to cancel. + * @param {Function} cb - The callback function called with a full state update. + */ + cancelDecryptMessage (msgId, cb) { + const messageManager = this.decryptMessageManager + messageManager.rejectMsg(msgId) + if (cb && typeof cb === 'function') { + cb(null, this.getState()) + } } -} // eth_getEncryptionPublicKey methods @@ -1323,53 +1329,53 @@ cancelDecryptMessage (msgId, cb) { * @param {Object} req - (optional) the original request, containing the origin * Passed back to the requesting Dapp. */ - async newRequestEncryptionPublicKey (msgParams, req) { - const promise = this.encryptionPublicKeyManager.addUnapprovedMessageAsync(msgParams, req) - this.sendUpdate() - this.opts.showUnconfirmedMessage() - return promise -} - -/** -* Signifies a user's approval to receiving encryption public key in queue. -* Triggers receiving, and the callback function from newUnsignedEncryptionPublicKey. -* -* @param {Object} msgParams - The params of the message to receive & return to the Dapp. -* @returns {Promise} - A full state update. -*/ -async encryptionPublicKey (msgParams) { - log.info('MetaMaskController - encryptionPublicKey') - const msgId = msgParams.metamaskId - // sets the status op the message to 'approved' - // and removes the metamaskId for decryption - try { - const params = await this.encryptionPublicKeyManager.approveMessage(msgParams) - - // EncryptionPublicKey message - const publicKey = await this.keyringController.getEncryptionPublicKey(params.data) - - // tells the listener that the message has been processed - // and can be returned to the dapp - this.encryptionPublicKeyManager.setMsgStatusReceived(msgId, publicKey) - } catch (error) { - log.info('MetaMaskController - eth_getEncryptionPublicKey failed.', error) - this.encryptionPublicKeyManager.errorMessage(msgId, error) + async newRequestEncryptionPublicKey (msgParams, req) { + const promise = this.encryptionPublicKeyManager.addUnapprovedMessageAsync(msgParams, req) + this.sendUpdate() + this.opts.showUnconfirmedMessage() + return promise } - return this.getState() -} -/** - * Used to cancel a eth_getEncryptionPublicKey type message. - * @param {string} msgId - The ID of the message to cancel. - * @param {Function} cb - The callback function called with a full state update. - */ -cancelEncryptionPublicKey (msgId, cb) { - const messageManager = this.encryptionPublicKeyManager - messageManager.rejectMsg(msgId) - if (cb && typeof cb === 'function') { - cb(null, this.getState()) + /** + * Signifies a user's approval to receiving encryption public key in queue. + * Triggers receiving, and the callback function from newUnsignedEncryptionPublicKey. + * + * @param {Object} msgParams - The params of the message to receive & return to the Dapp. + * @returns {Promise} - A full state update. + */ + async encryptionPublicKey (msgParams) { + log.info('MetaMaskController - encryptionPublicKey') + const msgId = msgParams.metamaskId + // sets the status op the message to 'approved' + // and removes the metamaskId for decryption + try { + const params = await this.encryptionPublicKeyManager.approveMessage(msgParams) + + // EncryptionPublicKey message + const publicKey = await this.keyringController.getEncryptionPublicKey(params.data) + + // tells the listener that the message has been processed + // and can be returned to the dapp + this.encryptionPublicKeyManager.setMsgStatusReceived(msgId, publicKey) + } catch (error) { + log.info('MetaMaskController - eth_getEncryptionPublicKey failed.', error) + this.encryptionPublicKeyManager.errorMessage(msgId, error) + } + return this.getState() + } + + /** + * Used to cancel a eth_getEncryptionPublicKey type message. + * @param {string} msgId - The ID of the message to cancel. + * @param {Function} cb - The callback function called with a full state update. + */ + cancelEncryptionPublicKey (msgId, cb) { + const messageManager = this.encryptionPublicKeyManager + messageManager.rejectMsg(msgId) + if (cb && typeof cb === 'function') { + cb(null, this.getState()) + } } -} // eth_signTypedData methods @@ -1399,19 +1405,16 @@ cancelEncryptionPublicKey (msgId, cb) { const version = msgParams.version try { const cleanMsgParams = await this.typedMessageManager.approveMessage(msgParams) - const address = sigUtil.normalize(cleanMsgParams.from) - const keyring = await this.keyringController.getKeyringForAccount(address) - const wallet = keyring._getWalletForAccount(address) - const privKey = ethUtil.toBuffer(wallet.getPrivateKey()) - let signature - switch (version) { - case 'V1': - signature = sigUtil.signTypedDataLegacy(privKey, { data: cleanMsgParams.data }) - break - case 'V3': - signature = sigUtil.signTypedData(privKey, { data: JSON.parse(cleanMsgParams.data) }) - break + + // For some reason every version after V1 used stringified params. + if (version !== 'V1') { + // But we don't have to require that. We can stop suggesting it now: + if (typeof cleanMsgParams.data === 'string') { + cleanMsgParams.data = JSON.parse(cleanMsgParams.data) + } } + + const signature = await this.keyringController.signTypedMessage(cleanMsgParams, { version }) this.typedMessageManager.setMsgStatusSigned(msgId, signature) return this.getState() } catch (error) { diff --git a/package-lock.json b/package-lock.json index d4e2f5f96..cc7201413 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11369,11 +11369,12 @@ } }, "eth-hd-keyring": { - "version": "github:vbaranov/eth-hd-keyring#3a77a565439d5555e52b955f3457f2fcd2753a81", - "from": "github:vbaranov/eth-hd-keyring#2.0.2", + "version": "github:vbaranov/eth-hd-keyring#2c761c59e7cc978da6a612bf6d9833d8ea95efb5", + "from": "github:vbaranov/eth-hd-keyring#2.1.0", "requires": { "bip39": "^2.2.0", - "eth-sig-util": "^2.0.1", + "eth-sig-util": "^2.4.4", + "eth-simple-keyring": "^3.5.0", "ethereumjs-abi": "^0.6.5", "ethereumjs-util": "^5.1.1", "ethereumjs-wallet": "^0.6.0", @@ -11631,30 +11632,21 @@ } }, "eth-keychain-controller": { - "version": "github:vbaranov/KeyringController#9b54d5596212f033a0b17f2ae27b3dd2de8df270", - "from": "github:vbaranov/KeyringController#5.1.0", + "version": "github:vbaranov/KeyringController#a39087f825b1cbffc663ef002d7d66ade3c5944b", + "from": "github:vbaranov/KeyringController#5.2.0", "requires": { "bip39": "^2.4.0", "bluebird": "^3.5.0", "browser-passworder": "^2.0.3", - "eth-hd-keyring": "github:vbaranov/eth-hd-keyring#2.0.2", + "eth-hd-keyring": "github:vbaranov/eth-hd-keyring#2.1.0", "eth-sig-util": "^1.4.0", - "eth-simple-keyring": "^2.0.0", + "eth-simple-keyring": "^3.5.0", "ethereumjs-util": "^5.1.2", "loglevel": "^1.5.0", - "obs-store": "^2.4.1", + "obs-store": "^4.0.3", "promise-filter": "^1.1.0" }, "dependencies": { - "babelify": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", - "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=", - "requires": { - "babel-core": "^6.0.14", - "object-assign": "^4.0.0" - } - }, "eth-sig-util": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", @@ -11687,18 +11679,6 @@ } } } - }, - "obs-store": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/obs-store/-/obs-store-2.4.1.tgz", - "integrity": "sha512-wpA8G4uSn8cnCKZ0pFTvqsamvy0Sm1hR2ot0Qonbfj5yBMwdAp/eD4vDI+U/ZCbV1hb2V5GapL8YKUdGCvahgg==", - "requires": { - "babel-preset-es2015": "^6.22.0", - "babelify": "^7.3.0", - "readable-stream": "^2.2.2", - "through2": "^2.0.3", - "xtend": "^4.0.1" - } } } }, @@ -11916,11 +11896,11 @@ } }, "eth-simple-keyring": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eth-simple-keyring/-/eth-simple-keyring-2.1.0.tgz", - "integrity": "sha512-31emUxGHOVhYzlPoEGyfrn1Usi2ZI9qDqMnDHwG0R0HdIuF/I10qlf401MkiD9lcMDuvgJkLpqqAvGxrKrFCwA==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/eth-simple-keyring/-/eth-simple-keyring-3.5.0.tgz", + "integrity": "sha512-z9IPt9aoMWAw5Zc3Jk/HKbWPJNc7ivZ5ECNtl3ZoQUGRnwoWO71W5+liVPJtXFNacGOOGsBfqTqrXL9C4EnYYQ==", "requires": { - "eth-sig-util": "^2.0.1", + "eth-sig-util": "^2.5.0", "ethereumjs-abi": "^0.6.5", "ethereumjs-util": "^5.1.1", "ethereumjs-wallet": "^0.6.0", @@ -45006,7 +44986,7 @@ "dev": true }, "nifty-wallet-inpage-provider": { - "version": "github:poanetwork/nifty-wallet-inpage-provider#77cc9859e40ecd9720e3c5cc690b0abf5693014b", + "version": "github:poanetwork/nifty-wallet-inpage-provider#68b7b0733c7cc7ce9712a316e851d87b4cb0b191", "from": "github:poanetwork/nifty-wallet-inpage-provider#1.5.0", "requires": { "eth-json-rpc-errors": "^2.0.2", diff --git a/package.json b/package.json index bc70fbedd..60a3a9abb 100644 --- a/package.json +++ b/package.json @@ -115,7 +115,7 @@ "eth-json-rpc-filters": "github:poanetwork/eth-json-rpc-filters#3.0.2", "eth-json-rpc-infura": "^4.0.2", "eth-json-rpc-middleware": "^4.4.1", - "eth-keychain-controller": "github:vbaranov/KeyringController#5.1.0", + "eth-keychain-controller": "github:vbaranov/KeyringController#5.2.0", "eth-ledger-bridge-keyring": "github:vbaranov/eth-ledger-bridge-keyring#0.1.0-clear-accounts-flag", "eth-method-registry": "^1.0.0", "eth-net-props": "^1.0.33", diff --git a/ui/app/actions.js b/ui/app/actions.js index 059751a38..2dd696087 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -364,6 +364,12 @@ var actions = { confirmChangePassword, createCancelTransaction, + + SET_REQUEST_ACCOUNT_TABS: 'SET_REQUEST_ACCOUNT_TABS', + setRequestAccountTabIds, + getRequestAccountTabIds, + setOpenMetamaskTabsIDs, + getOpenMetamaskTabsIds, } module.exports = actions @@ -1723,6 +1729,7 @@ function showAccountDetail (address) { if (err) { return dispatch(actions.displayWarning(err.message)) } + background.handleNewAccountSelected(origin, address) dispatch(updateTokens(tokens)) dispatch({ type: actions.SHOW_ACCOUNT_DETAIL, @@ -2761,3 +2768,31 @@ function confirmChangePassword () { type: actions.CONFIRM_CHANGE_PASSWORD, } } + +function setRequestAccountTabIds (requestAccountTabIds) { + return { + type: actions.SET_REQUEST_ACCOUNT_TABS, + value: requestAccountTabIds, + } +} + +function getRequestAccountTabIds () { + return async (dispatch) => { + const requestAccountTabIds = await pify(background.getRequestAccountTabIds).call(background) + dispatch(setRequestAccountTabIds(requestAccountTabIds)) + } +} + +function setOpenMetamaskTabsIDs (openMetaMaskTabIDs) { + return { + type: actions.SET_OPEN_METAMASK_TAB_IDS, + value: openMetaMaskTabIDs, + } +} + +function getOpenMetamaskTabsIds () { + return async (dispatch) => { + const openMetaMaskTabIDs = await pify(background.getOpenMetamaskTabsIds).call(background) + dispatch(setOpenMetamaskTabsIDs(openMetaMaskTabIDs)) + } +}