From 2dbb151e0b68908be2bef48fc4ea317d2daf17d2 Mon Sep 17 00:00:00 2001 From: Mark Stacey Date: Thu, 25 Jun 2020 21:05:42 -0300 Subject: [PATCH 1/2] Fix account order on unconnected account alert (#8863) The account list on the unconnected account alert was in the wrong order; they were in the order provided by the permissions controller rather than by last active. The accounts are now sorted correctly; first by last active, second by the keyring controller order. The `getPermittedIdentitiesForCurrentTab` selector was removed because it is no longer used. --- .../unconnected-account-alert.js | 4 ++-- ui/app/selectors/permissions.js | 10 +--------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/ui/app/components/app/alerts/unconnected-account-alert/unconnected-account-alert.js b/ui/app/components/app/alerts/unconnected-account-alert/unconnected-account-alert.js index 38a8fda6e..9d8483648 100644 --- a/ui/app/components/app/alerts/unconnected-account-alert/unconnected-account-alert.js +++ b/ui/app/components/app/alerts/unconnected-account-alert/unconnected-account-alert.js @@ -11,7 +11,7 @@ import { } from '../../../../ducks/alerts/unconnected-account' import { getOriginOfCurrentTab, - getPermittedIdentitiesForCurrentTab, + getOrderedConnectedAccountsForActiveTab, getSelectedAddress, getSelectedIdentity, } from '../../../../selectors' @@ -32,7 +32,7 @@ const UnconnectedAccountAlert = () => { const t = useI18nContext() const dispatch = useDispatch() const alertState = useSelector(getAlertState) - const connectedAccounts = useSelector(getPermittedIdentitiesForCurrentTab) + const connectedAccounts = useSelector(getOrderedConnectedAccountsForActiveTab) const origin = useSelector(getOriginOfCurrentTab) const selectedIdentity = useSelector(getSelectedIdentity) const selectedAddress = useSelector(getSelectedAddress) diff --git a/ui/app/selectors/permissions.js b/ui/app/selectors/permissions.js index 2960a753f..8c294b762 100644 --- a/ui/app/selectors/permissions.js +++ b/ui/app/selectors/permissions.js @@ -1,5 +1,5 @@ import { forOwn } from 'lodash' -import { getMetaMaskAccountsOrdered, getMetaMaskIdentities, getOriginOfCurrentTab, getSelectedAddress } from '.' +import { getMetaMaskAccountsOrdered, getOriginOfCurrentTab, getSelectedAddress } from '.' import { CAVEAT_NAMES, } from '../../../app/scripts/controllers/permissions/enums' @@ -119,14 +119,6 @@ export function getConnectedDomainsForSelectedAddress (state) { return connectedDomains } -export function getPermittedIdentitiesForCurrentTab (state) { - const permittedAccounts = getPermittedAccountsForCurrentTab(state) - const identities = getMetaMaskIdentities(state) - return permittedAccounts - .map((address) => identities[address]) - .filter((identity) => Boolean(identity)) -} - /** * Returns an object mapping addresses to objects mapping origins to connected * domain info. Domain info objects have the following properties: From 73257b1cd116d50dad9c2cef2d11b9d3ea8f64fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20Mi=C3=B1o?= Date: Thu, 25 Jun 2020 21:04:17 -0400 Subject: [PATCH 2/2] feature/sync imported accounts with mobile (#8631) * sync imported accounts * Update app/scripts/metamask-controller.js Co-authored-by: Mark Stacey * exportAccounts action Co-authored-by: Mark Stacey --- app/scripts/metamask-controller.js | 7 ++++- .../mobile-sync/mobile-sync.component.js | 20 ++++++++++++- .../mobile-sync/mobile-sync.container.js | 5 +++- ui/app/store/actions.js | 28 +++++++++++++++++++ 4 files changed, 57 insertions(+), 3 deletions(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 6b2da2946..20d249ed8 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -725,10 +725,15 @@ export default class MetamaskController extends EventEmitter { // Accounts const hdKeyring = this.keyringController.getKeyringsByType('HD Key Tree')[0] + const simpleKeyPairKeyrings = this.keyringController.getKeyringsByType('Simple Key Pair') const hdAccounts = await hdKeyring.getAccounts() + const simpleKeyPairKeyringAccounts = await Promise.all( + simpleKeyPairKeyrings.map((keyring) => keyring.getAccounts()) + ) + const simpleKeyPairAccounts = simpleKeyPairKeyringAccounts.reduce((acc, accounts) => [...acc, ...accounts], []) const accounts = { hd: hdAccounts.filter((item, pos) => (hdAccounts.indexOf(item) === pos)).map((address) => ethUtil.toChecksumAddress(address)), - simpleKeyPair: [], + simpleKeyPair: simpleKeyPairAccounts.filter((item, pos) => (simpleKeyPairAccounts.indexOf(item) === pos)).map((address) => ethUtil.toChecksumAddress(address)), ledger: [], trezor: [], } diff --git a/ui/app/pages/mobile-sync/mobile-sync.component.js b/ui/app/pages/mobile-sync/mobile-sync.component.js index 4afbf93ed..53e36364a 100644 --- a/ui/app/pages/mobile-sync/mobile-sync.component.js +++ b/ui/app/pages/mobile-sync/mobile-sync.component.js @@ -25,6 +25,8 @@ export default class MobileSyncPage extends Component { fetchInfoToSync: PropTypes.func.isRequired, mostRecentOverviewPage: PropTypes.string.isRequired, requestRevealSeedWords: PropTypes.func.isRequired, + exportAccounts: PropTypes.func.isRequired, + keyrings: PropTypes.array, } @@ -32,6 +34,7 @@ export default class MobileSyncPage extends Component { screen: PASSWORD_PROMPT_SCREEN, password: '', seedWords: null, + importedAccounts: [], error: null, syncing: false, completed: false, @@ -62,11 +65,25 @@ export default class MobileSyncPage extends Component { .then((seedWords) => { this.startKeysGeneration() this.startIdleTimeout() - this.setState({ seedWords, screen: REVEAL_SEED_SCREEN }) + this.exportAccounts() + .then((importedAccounts) => { + this.setState({ seedWords, importedAccounts, screen: REVEAL_SEED_SCREEN }) + }) }) .catch((error) => this.setState({ error: error.message })) } + async exportAccounts () { + const addresses = [] + this.props.keyrings.forEach((keyring) => { + if (keyring.type === 'Simple Key Pair') { + addresses.push(keyring.accounts[0]) + } + }) + const importedAccounts = await this.props.exportAccounts(this.state.password, addresses) + return importedAccounts + } + startKeysGeneration () { this.keysGenerationTimeout && clearTimeout(this.keysGenerationTimeout) this.disconnectWebsockets() @@ -201,6 +218,7 @@ export default class MobileSyncPage extends Component { udata: { pwd: this.state.password, seed: this.state.seedWords, + importedAccounts: this.state.importedAccounts, }, }) diff --git a/ui/app/pages/mobile-sync/mobile-sync.container.js b/ui/app/pages/mobile-sync/mobile-sync.container.js index 28c306b1b..053f05d81 100644 --- a/ui/app/pages/mobile-sync/mobile-sync.container.js +++ b/ui/app/pages/mobile-sync/mobile-sync.container.js @@ -1,13 +1,15 @@ import { connect } from 'react-redux' -import { displayWarning, requestRevealSeedWords, fetchInfoToSync } from '../../store/actions' +import { displayWarning, requestRevealSeedWords, fetchInfoToSync, exportAccounts } from '../../store/actions' import MobileSyncPage from './mobile-sync.component' import { getMostRecentOverviewPage } from '../../ducks/history/history' +import { getMetaMaskKeyrings } from '../../selectors' const mapDispatchToProps = (dispatch) => { return { requestRevealSeedWords: (password) => dispatch(requestRevealSeedWords(password)), fetchInfoToSync: () => dispatch(fetchInfoToSync()), displayWarning: (message) => dispatch(displayWarning(message || null)), + exportAccounts: (password, addresses) => dispatch(exportAccounts(password, addresses)), } } @@ -21,6 +23,7 @@ const mapStateToProps = (state) => { return { mostRecentOverviewPage: getMostRecentOverviewPage(state), selectedAddress, + keyrings: getMetaMaskKeyrings(state), } } diff --git a/ui/app/store/actions.js b/ui/app/store/actions.js index b118b0227..f139d71a0 100644 --- a/ui/app/store/actions.js +++ b/ui/app/store/actions.js @@ -1708,6 +1708,34 @@ export function exportAccount (password, address) { } } +export function exportAccounts (password, addresses) { + return function (dispatch) { + log.debug(`background.submitPassword`) + return new Promise((resolve, reject) => { + background.submitPassword(password, function (err) { + if (err) { + log.error('Error in submitting password.') + return reject(err) + } + log.debug(`background.exportAccounts`) + const accountPromises = addresses.map((address) => + new Promise( + (resolve, reject) => background.exportAccount(address, function (err, result) { + if (err) { + log.error(err) + dispatch(displayWarning('Had a problem exporting the account.')) + return reject(err) + } + return resolve(result) + }) + ) + ) + return resolve(Promise.all(accountPromises)) + }) + }) + } +} + export function showPrivateKey (key) { return { type: actionConstants.SHOW_PRIVATE_KEY,