From ad7d38c0dc206074379c813b307ed9350c7efeb0 Mon Sep 17 00:00:00 2001 From: Jakub Stasiak Date: Wed, 11 Apr 2018 18:32:27 +0200 Subject: [PATCH 01/74] Update: allow other extension to connect --- app/manifest.json | 3 ++- app/scripts/background.js | 14 ++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/app/manifest.json b/app/manifest.json index dc46f1ca4..950bab2f1 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -67,6 +67,7 @@ "externally_connectable": { "matches": [ "https://metamask.io/*" - ] + ], + "ids": ["*"] } } \ No newline at end of file diff --git a/app/scripts/background.js b/app/scripts/background.js index 6550e8944..6296eaa21 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -197,6 +197,7 @@ function setupController (initState, initLangCode) { // connect to other contexts // extension.runtime.onConnect.addListener(connectRemote) + extension.runtime.onConnectExternal.addListener(connectExternal) const metamaskInternalProcessHash = { [ENVIRONMENT_TYPE_POPUP]: true, @@ -211,9 +212,9 @@ function setupController (initState, initLangCode) { function connectRemote (remotePort) { const processName = remotePort.name const isMetaMaskInternalProcess = metamaskInternalProcessHash[processName] - const portStream = new PortStream(remotePort) if (isMetaMaskInternalProcess) { + const portStream = new PortStream(remotePort) // communication with popup controller.isClientOpen = true controller.setupTrustedCommunication(portStream, 'MetaMask') @@ -246,12 +247,17 @@ function setupController (initState, initLangCode) { }) } } else { - // communication with page - const originDomain = urlUtil.parse(remotePort.sender.url).hostname - controller.setupUntrustedCommunication(portStream, originDomain) + connectExternal(remotePort) } } + // communication with page or other extension + function connectExternal(remotePort) { + const originDomain = urlUtil.parse(remotePort.sender.url).hostname + const portStream = new PortStream(remotePort) + controller.setupUntrustedCommunication(portStream, originDomain) + } + // // User Interface setup // From 7eb735651bcd1c3a4ef2b4da1be5d7444e282b44 Mon Sep 17 00:00:00 2001 From: frankiebee Date: Sun, 29 Apr 2018 16:00:13 -0700 Subject: [PATCH 02/74] transactions - run event emitters outside context of _setTxStatus --- .../controllers/transactions/tx-state-manager.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/app/scripts/controllers/transactions/tx-state-manager.js b/app/scripts/controllers/transactions/tx-state-manager.js index 53428c333..17938e70f 100644 --- a/app/scripts/controllers/transactions/tx-state-manager.js +++ b/app/scripts/controllers/transactions/tx-state-manager.js @@ -398,13 +398,15 @@ class TransactionStateManager extends EventEmitter { _setTxStatus (txId, status) { const txMeta = this.getTx(txId) txMeta.status = status - this.emit(`${txMeta.id}:${status}`, txId) - this.emit(`tx:status-update`, txId, status) - if (['submitted', 'rejected', 'failed'].includes(status)) { - this.emit(`${txMeta.id}:finished`, txMeta) - } - this.updateTx(txMeta, `txStateManager: setting status to ${status}`) - this.emit('update:badge') + setTimeout(() => { + this.updateTx(txMeta, `txStateManager: setting status to ${status}`) + this.emit(`${txMeta.id}:${status}`, txId) + this.emit(`tx:status-update`, txId, status) + if (['submitted', 'rejected', 'failed'].includes(status)) { + this.emit(`${txMeta.id}:finished`, txMeta) + } + this.emit('update:badge') + }) } /** From 706647785cee23d177d646c3a06f5dc2a2586feb Mon Sep 17 00:00:00 2001 From: frankiebee Date: Sun, 29 Apr 2018 16:33:46 -0700 Subject: [PATCH 03/74] log emitter errors --- .../controllers/transactions/tx-state-manager.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/app/scripts/controllers/transactions/tx-state-manager.js b/app/scripts/controllers/transactions/tx-state-manager.js index 17938e70f..28b6d6d4f 100644 --- a/app/scripts/controllers/transactions/tx-state-manager.js +++ b/app/scripts/controllers/transactions/tx-state-manager.js @@ -399,13 +399,17 @@ class TransactionStateManager extends EventEmitter { const txMeta = this.getTx(txId) txMeta.status = status setTimeout(() => { - this.updateTx(txMeta, `txStateManager: setting status to ${status}`) - this.emit(`${txMeta.id}:${status}`, txId) - this.emit(`tx:status-update`, txId, status) - if (['submitted', 'rejected', 'failed'].includes(status)) { - this.emit(`${txMeta.id}:finished`, txMeta) + try { + this.updateTx(txMeta, `txStateManager: setting status to ${status}`) + this.emit(`${txMeta.id}:${status}`, txId) + this.emit(`tx:status-update`, txId, status) + if (['submitted', 'rejected', 'failed'].includes(status)) { + this.emit(`${txMeta.id}:finished`, txMeta) + } + this.emit('update:badge') + } catch (error) { + log.error(error) } - this.emit('update:badge') }) } From 98ae853b6c67bce137df00c2527e5ece25f1129e Mon Sep 17 00:00:00 2001 From: frankiebee Date: Mon, 30 Apr 2018 09:57:36 -0700 Subject: [PATCH 04/74] require log --- app/scripts/controllers/transactions/tx-state-manager.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/scripts/controllers/transactions/tx-state-manager.js b/app/scripts/controllers/transactions/tx-state-manager.js index 28b6d6d4f..f05c7d095 100644 --- a/app/scripts/controllers/transactions/tx-state-manager.js +++ b/app/scripts/controllers/transactions/tx-state-manager.js @@ -2,6 +2,7 @@ const extend = require('xtend') const EventEmitter = require('events') const ObservableStore = require('obs-store') const ethUtil = require('ethereumjs-util') +const log = require('loglevel') const txStateHistoryHelper = require('./lib/tx-state-history-helper') const createId = require('../../lib/random-id') const { getFinalStates } = require('./lib/util') From 477063a5a0e9f218af2a49886c44a9bc153c13d3 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 30 Apr 2018 13:29:22 -0700 Subject: [PATCH 05/74] Version 4.6.1 --- CHANGELOG.md | 9 ++++++++- app/manifest.json | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0bb50fd5b..e4dd7ae98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ ## Current Master +## 4.6.1 Mon Apr 30 2018 + +- Fix bug where sending a transaction resulted in an infinite spinner +- Allow transactions with a 0 gwei gas price +- Handle encoding errors in ERC20 symbol + digits +- Fix ShapeShift forms (new + old ui) +- Fix sourcemaps + ## 4.6.0 Thu Apr 26 2018 - Correctly format currency conversion for locally selected preferred currency. @@ -9,7 +17,6 @@ - Fetch token prices based on contract address, not symbol - Fix bug that prevents setting language locale in settings. - Show checksum addresses throughout the UI -- Allow transactions with a 0 gwei gas price ## 4.5.5 Fri Apr 06 2018 diff --git a/app/manifest.json b/app/manifest.json index 3e5eed205..8a14323f0 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,7 +1,7 @@ { "name": "__MSG_appName__", "short_name": "__MSG_appName__", - "version": "4.6.0", + "version": "4.6.1", "manifest_version": 2, "author": "https://metamask.io", "description": "__MSG_appDescription__", From 07cda8264d074e59376d8653c41eb9dde76013a5 Mon Sep 17 00:00:00 2001 From: Dan Finlay <542863+danfinlay@users.noreply.github.com> Date: Wed, 23 May 2018 14:48:05 -0700 Subject: [PATCH 06/74] Update publishing guide --- docs/publishing.md | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/docs/publishing.md b/docs/publishing.md index 3022b7eda..076f48772 100644 --- a/docs/publishing.md +++ b/docs/publishing.md @@ -2,18 +2,32 @@ When publishing a new version of MetaMask, we follow this procedure: +## Preparation + +We try to ensure certain criteria are met before deploying: + +- Deploy early in the week, to give time for emergency responses to unforeseen bugs. +- Deploy early in the day, for the same reason. +- Make sure at least one member of the support team is "on duty" to watch for new user issues coming through the support system. +- Roll out incrementally when possible, to a small number of users first, and gradually to more users. + ## Incrementing Version & Changelog Version can be automatically incremented [using our bump script](./bumping-version.md). npm run version:bump $BUMP_TYPE` where `$BUMP_TYPE` is one of `major`, `minor`, or `patch`. +## Building + +While we develop on the main `develop` branch, our production version is maintained on the `master` branch. + +With each pull request, the @MetaMaskBot will comment with a build of that new pull request, so after bumping the version on `develop`, open a pull request against `master`, and once the pull request is reviewed and merged, you can download those builds for publication. + ## Publishing -1. `npm run dist` to generate the latest build. -2. Publish to chrome store. +1. Publish to chrome store. - Visit [the chrome developer dashboard](https://chrome.google.com/webstore/developer/dashboard?authuser=2). -3. Publish to firefox addon marketplace. -4. Post on Github releases page. -5. `npm run announce`, post that announcement in our public places. - +2. Publish to [firefox addon marketplace](http://addons.mozilla.org/en-us/firefox/addon/ether-metamask). +3. Publish to [Opera store](https://addons.opera.com/en/extensions/details/metamask/). +3. Post on [Github releases](https://github.com/MetaMask/metamask-extension/releases) page. +4. Run the `npm run announce` script, and post that announcement in our public places. From 4cc2273c20a62745368c668ef09ec4239ec59090 Mon Sep 17 00:00:00 2001 From: Dan Finlay <542863+danfinlay@users.noreply.github.com> Date: Wed, 23 May 2018 14:58:09 -0700 Subject: [PATCH 07/74] Update publishing.md --- docs/publishing.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/publishing.md b/docs/publishing.md index 076f48772..45662900d 100644 --- a/docs/publishing.md +++ b/docs/publishing.md @@ -26,8 +26,8 @@ With each pull request, the @MetaMaskBot will comment with a build of that new p ## Publishing 1. Publish to chrome store. - - Visit [the chrome developer dashboard](https://chrome.google.com/webstore/developer/dashboard?authuser=2). -2. Publish to [firefox addon marketplace](http://addons.mozilla.org/en-us/firefox/addon/ether-metamask). -3. Publish to [Opera store](https://addons.opera.com/en/extensions/details/metamask/). -3. Post on [Github releases](https://github.com/MetaMask/metamask-extension/releases) page. -4. Run the `npm run announce` script, and post that announcement in our public places. +2. Visit [the chrome developer dashboard](https://chrome.google.com/webstore/developer/dashboard?authuser=2). +3. Publish to [firefox addon marketplace](http://addons.mozilla.org/en-us/firefox/addon/ether-metamask). +4. Publish to [Opera store](https://addons.opera.com/en/extensions/details/metamask/). +5. Post on [Github releases](https://github.com/MetaMask/metamask-extension/releases) page. +6. Run the `npm run announce` script, and post that announcement in our public places. From 1cd4b03b3759691f03457eadc8860dcea9570ae9 Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 25 May 2018 12:58:16 -0700 Subject: [PATCH 08/74] test - unit - fail if tests contain a .only call --- package-lock.json | 6 ++++++ package.json | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index a1fdf0059..e138ec3ad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7134,6 +7134,12 @@ "domelementtype": "1.3.0" } }, + "dot-only-hunter": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/dot-only-hunter/-/dot-only-hunter-1.0.3.tgz", + "integrity": "sha1-9k0h7b5v8xFJlfEGGmGpNcMAIEs=", + "dev": true + }, "dotenv": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-5.0.1.tgz", diff --git a/package.json b/package.json index 372ffbfa5..5ad1f9639 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "dist": "gulp dist", "doc": "jsdoc -c development/tools/.jsdoc.json", "test": "npm run test:unit && npm run test:integration && npm run lint", - "test:unit": "cross-env METAMASK_ENV=test mocha --exit --require test/setup.js --recursive \"test/unit/**/*.js\"", + "test:unit": "cross-env METAMASK_ENV=test mocha --exit --require test/setup.js --recursive \"test/unit/**/*.js\" && dot-only-hunter", "test:single": "cross-env METAMASK_ENV=test mocha --require test/helper.js", "test:integration": "npm run test:integration:build && npm run test:flat && npm run test:mascara", "test:integration:build": "gulp build:scss", @@ -219,6 +219,7 @@ "css-loader": "^0.28.11", "deep-freeze-strict": "^1.1.1", "del": "^3.0.0", + "dot-only-hunter": "^1.0.3", "envify": "^4.0.0", "enzyme": "^3.3.0", "enzyme-adapter-react-15": "^1.0.5", From 62dc6e20eb1f7188c6452519782e8ebe54c1c540 Mon Sep 17 00:00:00 2001 From: Anton Date: Mon, 28 May 2018 17:57:45 +0200 Subject: [PATCH 09/74] Clean up user rejection error message --- app/scripts/controllers/transactions/index.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index 541f1db73..586a80baf 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -111,6 +111,15 @@ class TransactionController extends EventEmitter { this.txStateManager.wipeTransactions(address) } + /** + Returns error without stack trace for better UI display + @param {Error} err - error which stack will be cleaned + */ + cleanErrorStack(err){ + err.stack = err.name + ': ' + err.message + return err + } + /** add a new unapproved transaction to the pipeline @@ -118,6 +127,8 @@ class TransactionController extends EventEmitter { @param txParams {object} - txParams for the transaction @param opts {object} - with the key origin to put the origin on the txMeta */ + + async newUnapprovedTransaction (txParams, opts = {}) { log.debug(`MetaMaskController newUnapprovedTransaction ${JSON.stringify(txParams)}`) const initialTxMeta = await this.addUnapprovedTransaction(txParams) @@ -130,11 +141,11 @@ class TransactionController extends EventEmitter { case 'submitted': return resolve(finishedTxMeta.hash) case 'rejected': - return reject(new Error('MetaMask Tx Signature: User denied transaction signature.')) + return reject(this.cleanErrorStack(new Error('MetaMask Tx Signature: User denied transaction signature.'))) case 'failed': - return reject(new Error(finishedTxMeta.err.message)) + return reject(this.cleanErrorStack(new Error(finishedTxMeta.err.message))) default: - return reject(new Error(`MetaMask Tx Signature: Unknown problem: ${JSON.stringify(finishedTxMeta.txParams)}`)) + return reject(this.cleanErrorStack(`MetaMask Tx Signature: Unknown problem: ${JSON.stringify(finishedTxMeta.txParams)}`)) } }) }) From 1d23a5c81b03b8b52225e942603c84b237d4e63c Mon Sep 17 00:00:00 2001 From: Anton Date: Mon, 28 May 2018 18:08:33 +0200 Subject: [PATCH 10/74] error message fix --- app/scripts/controllers/transactions/index.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index 586a80baf..6609b80b0 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -128,7 +128,6 @@ class TransactionController extends EventEmitter { @param opts {object} - with the key origin to put the origin on the txMeta */ - async newUnapprovedTransaction (txParams, opts = {}) { log.debug(`MetaMaskController newUnapprovedTransaction ${JSON.stringify(txParams)}`) const initialTxMeta = await this.addUnapprovedTransaction(txParams) @@ -145,7 +144,7 @@ class TransactionController extends EventEmitter { case 'failed': return reject(this.cleanErrorStack(new Error(finishedTxMeta.err.message))) default: - return reject(this.cleanErrorStack(`MetaMask Tx Signature: Unknown problem: ${JSON.stringify(finishedTxMeta.txParams)}`)) + return reject(this.cleanErrorStack(new Error(`MetaMask Tx Signature: Unknown problem: ${JSON.stringify(finishedTxMeta.txParams)}`))) } }) }) From 71a6e97327a4c759942784ee81505e3bc5ed545e Mon Sep 17 00:00:00 2001 From: Anton Date: Mon, 28 May 2018 22:57:08 +0200 Subject: [PATCH 11/74] cleanErrorStack moved to separate library module more errors traces cleaned up --- app/scripts/controllers/transactions/index.js | 16 ++++--------- app/scripts/lib/cleanErrorStack.js | 24 +++++++++++++++++++ app/scripts/metamask-controller.js | 15 ++++++------ 3 files changed, 36 insertions(+), 19 deletions(-) create mode 100644 app/scripts/lib/cleanErrorStack.js diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index 6609b80b0..aff5db984 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -8,6 +8,7 @@ const TxGasUtil = require('./tx-gas-utils') const PendingTransactionTracker = require('./pending-tx-tracker') const NonceTracker = require('./nonce-tracker') const txUtils = require('./lib/util') +const cleanErrorStack = require('../../lib/cleanErrorStack') const log = require('loglevel') /** @@ -111,15 +112,6 @@ class TransactionController extends EventEmitter { this.txStateManager.wipeTransactions(address) } - /** - Returns error without stack trace for better UI display - @param {Error} err - error which stack will be cleaned - */ - cleanErrorStack(err){ - err.stack = err.name + ': ' + err.message - return err - } - /** add a new unapproved transaction to the pipeline @@ -140,11 +132,11 @@ class TransactionController extends EventEmitter { case 'submitted': return resolve(finishedTxMeta.hash) case 'rejected': - return reject(this.cleanErrorStack(new Error('MetaMask Tx Signature: User denied transaction signature.'))) + return reject(cleanErrorStack(new Error('MetaMask Tx Signature: User denied transaction signature.'))) case 'failed': - return reject(this.cleanErrorStack(new Error(finishedTxMeta.err.message))) + return reject(cleanErrorStack(new Error(finishedTxMeta.err.message))) default: - return reject(this.cleanErrorStack(new Error(`MetaMask Tx Signature: Unknown problem: ${JSON.stringify(finishedTxMeta.txParams)}`))) + return reject(cleanErrorStack(new Error(`MetaMask Tx Signature: Unknown problem: ${JSON.stringify(finishedTxMeta.txParams)}`))) } }) }) diff --git a/app/scripts/lib/cleanErrorStack.js b/app/scripts/lib/cleanErrorStack.js new file mode 100644 index 000000000..fe1bfb0ce --- /dev/null +++ b/app/scripts/lib/cleanErrorStack.js @@ -0,0 +1,24 @@ +/** + * Returns error without stack trace for better UI display + * @param {Error} err - error + * @returns {Error} Error with clean stack trace. + */ +function cleanErrorStack(err){ + var name = err.name + name = (name === undefined) ? 'Error' : String(name) + + var msg = err.message + msg = (msg === undefined) ? '' : String(msg) + + if (name === '') { + err.stack = err.message + } else if (msg === '') { + err.stack = err.name + } else { + err.stack = err.name + ': ' + err.message + } + + return err +} + +module.exports = cleanErrorStack diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index c4a73d8ea..b0666d9f9 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -45,6 +45,7 @@ const BN = require('ethereumjs-util').BN const GWEI_BN = new BN('1000000000') const percentile = require('percentile') const seedPhraseVerifier = require('./lib/seed-phrase-verifier') +const cleanErrorStack = require('./lib/cleanErrorStack') const log = require('loglevel') module.exports = class MetamaskController extends EventEmitter { @@ -637,9 +638,9 @@ module.exports = class MetamaskController extends EventEmitter { case 'signed': return cb(null, data.rawSig) case 'rejected': - return cb(new Error('MetaMask Message Signature: User denied message signature.')) + return cb(cleanErrorStack(new Error('MetaMask Message Signature: User denied message signature.'))) default: - return cb(new Error(`MetaMask Message Signature: Unknown problem: ${JSON.stringify(msgParams)}`)) + return cb(cleanErrorStack(new Error(`MetaMask Message Signature: Unknown problem: ${JSON.stringify(msgParams)}`))) } }) } @@ -697,7 +698,7 @@ module.exports = class MetamaskController extends EventEmitter { */ newUnsignedPersonalMessage (msgParams, cb) { if (!msgParams.from) { - return cb(new Error('MetaMask Message Signature: from field is required.')) + return cb(cleanErrorStack(new Error('MetaMask Message Signature: from field is required.'))) } const msgId = this.personalMessageManager.addUnapprovedMessage(msgParams) @@ -708,9 +709,9 @@ module.exports = class MetamaskController extends EventEmitter { case 'signed': return cb(null, data.rawSig) case 'rejected': - return cb(new Error('MetaMask Message Signature: User denied message signature.')) + return cb(cleanErrorStack(new Error('MetaMask Message Signature: User denied message signature.'))) default: - return cb(new Error(`MetaMask Message Signature: Unknown problem: ${JSON.stringify(msgParams)}`)) + return cb(cleanErrorStack(new Error(`MetaMask Message Signature: Unknown problem: ${JSON.stringify(msgParams)}`))) } }) } @@ -776,9 +777,9 @@ module.exports = class MetamaskController extends EventEmitter { case 'signed': return cb(null, data.rawSig) case 'rejected': - return cb(new Error('MetaMask Message Signature: User denied message signature.')) + return cb(cleanErrorStack(new Error('MetaMask Message Signature: User denied message signature.'))) default: - return cb(new Error(`MetaMask Message Signature: Unknown problem: ${JSON.stringify(msgParams)}`)) + return cb(cleanErrorStack(new Error(`MetaMask Message Signature: Unknown problem: ${JSON.stringify(msgParams)}`))) } }) } From e3ecc94a521b040d8937bd7aaed2ecc7f029c586 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 28 May 2018 21:50:23 -0700 Subject: [PATCH 12/74] i18n - getFirstPreferredLangCode - guard against missing i18n api fix for brave --- app/scripts/lib/get-first-preferred-lang-code.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/app/scripts/lib/get-first-preferred-lang-code.js b/app/scripts/lib/get-first-preferred-lang-code.js index 5473fccf0..1e6a83ba6 100644 --- a/app/scripts/lib/get-first-preferred-lang-code.js +++ b/app/scripts/lib/get-first-preferred-lang-code.js @@ -2,6 +2,12 @@ const extension = require('extensionizer') const promisify = require('pify') const allLocales = require('../../_locales/index.json') +const isSupported = extension.i18n && extension.i18n.getAcceptLanguages +const getPreferredLocales = isSupported ? promisify( + extension.i18n.getAcceptLanguages, + { errorFirst: false } +) : async () => [] + const existingLocaleCodes = allLocales.map(locale => locale.code.toLowerCase().replace('_', '-')) /** @@ -12,10 +18,7 @@ const existingLocaleCodes = allLocales.map(locale => locale.code.toLowerCase().r * */ async function getFirstPreferredLangCode () { - const userPreferredLocaleCodes = await promisify( - extension.i18n.getAcceptLanguages, - { errorFirst: false } - )() + const userPreferredLocaleCodes = await getPreferredLocales() const firstPreferredLangCode = userPreferredLocaleCodes .map(code => code.toLowerCase()) .find(code => existingLocaleCodes.includes(code)) From 09601439e38e2681c434f23bc77c3b7665f8c98a Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 28 May 2018 22:58:14 -0700 Subject: [PATCH 13/74] metamask-controller - update preferences controller addresses after import account --- app/scripts/metamask-controller.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 1b1d26886..01adc3596 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -350,7 +350,7 @@ module.exports = class MetamaskController extends EventEmitter { verifySeedPhrase: nodeify(this.verifySeedPhrase, this), clearSeedWordCache: this.clearSeedWordCache.bind(this), resetAccount: nodeify(this.resetAccount, this), - importAccountWithStrategy: this.importAccountWithStrategy.bind(this), + importAccountWithStrategy: nodeify(this.importAccountWithStrategy, this), // vault management submitPassword: nodeify(keyringController.submitPassword, keyringController), @@ -608,15 +608,15 @@ module.exports = class MetamaskController extends EventEmitter { * @param {any} args - The data required by that strategy to import an account. * @param {Function} cb - A callback function called with a state update on success. */ - importAccountWithStrategy (strategy, args, cb) { - accountImporter.importAccount(strategy, args) - .then((privateKey) => { - return this.keyringController.addNewKeyring('Simple Key Pair', [ privateKey ]) - }) - .then(keyring => keyring.getAccounts()) - .then((accounts) => this.preferencesController.setSelectedAddress(accounts[0])) - .then(() => { cb(null, this.keyringController.fullUpdate()) }) - .catch((reason) => { cb(reason) }) + async importAccountWithStrategy (strategy, args) { + const privateKey = await accountImporter.importAccount(strategy, args) + const keyring = await this.keyringController.addNewKeyring('Simple Key Pair', [ privateKey ]) + const accounts = await keyring.getAccounts() + // update accounts in preferences controller + const allAccounts = await keyringController.getAccounts() + this.preferencesController.setAddresses(allAccounts) + // set new account as selected + await this.preferencesController.setSelectedAddress(accounts[0]) } // --------------------------------------------------------------------------- From 7e87600042805727a9e99e62c8bf23819f6d0b0f Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 28 May 2018 23:14:38 -0700 Subject: [PATCH 14/74] metamask-controller - lint fix --- app/scripts/metamask-controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 01adc3596..0457b4476 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -613,7 +613,7 @@ module.exports = class MetamaskController extends EventEmitter { const keyring = await this.keyringController.addNewKeyring('Simple Key Pair', [ privateKey ]) const accounts = await keyring.getAccounts() // update accounts in preferences controller - const allAccounts = await keyringController.getAccounts() + const allAccounts = await this.keyringController.getAccounts() this.preferencesController.setAddresses(allAccounts) // set new account as selected await this.preferencesController.setSelectedAddress(accounts[0]) From a7b7c8f0349ac8db16f264268745fd4b14e89422 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 28 May 2018 23:34:40 -0700 Subject: [PATCH 15/74] newui - unlock - dont catch errors unrelated to tryUnlockMetamask --- ui/app/components/pages/unlock-page/unlock-page.component.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/app/components/pages/unlock-page/unlock-page.component.js b/ui/app/components/pages/unlock-page/unlock-page.component.js index a2f009d8f..b6384b32d 100644 --- a/ui/app/components/pages/unlock-page/unlock-page.component.js +++ b/ui/app/components/pages/unlock-page/unlock-page.component.js @@ -37,8 +37,8 @@ class UnlockPage extends Component { tryUnlockMetamask (password) { const { tryUnlockMetamask, history } = this.props tryUnlockMetamask(password) - .then(() => history.push(DEFAULT_ROUTE)) .catch(({ message }) => this.setState({ error: message })) + .then(() => history.push(DEFAULT_ROUTE)) } handleSubmit (event) { @@ -55,8 +55,8 @@ class UnlockPage extends Component { this.setState({ error: null }) tryUnlockMetamask(password) - .then(() => history.push(DEFAULT_ROUTE)) .catch(({ message }) => this.setState({ error: message })) + .then(() => history.push(DEFAULT_ROUTE)) } handleInputChange ({ target }) { From d1f5d8ccc663bdc379864e155f12f580af127e8c Mon Sep 17 00:00:00 2001 From: Alexander Tseung Date: Tue, 29 May 2018 09:35:18 -0500 Subject: [PATCH 16/74] Fix text field labels of first time flow. Add text fields to storybook (#4389) --- .../app/first-time/create-password-screen.js | 2 + .../first-time/import-seed-phrase-screen.js | 2 + .../text-field/text-field.component.js | 95 ++++++++++--------- .../text-field/text-field.stories.js | 29 ++++++ 4 files changed, 84 insertions(+), 44 deletions(-) diff --git a/mascara/src/app/first-time/create-password-screen.js b/mascara/src/app/first-time/create-password-screen.js index 99d210ed1..6b284f7c5 100644 --- a/mascara/src/app/first-time/create-password-screen.js +++ b/mascara/src/app/first-time/create-password-screen.js @@ -143,6 +143,7 @@ class CreatePasswordScreen extends Component { autoComplete="new-password" margin="normal" fullWidth + largeLabel /> + + + ) + } +} + +TransactionConfirmed.propTypes = { + hideModal: PropTypes.func.isRequired, + onHide: PropTypes.func.isRequired, +} + +TransactionConfirmed.contextTypes = { + t: PropTypes.func, +} + +export default TransactionConfirmed diff --git a/ui/app/components/modals/transaction-confirmed/transaction-confirmed.container.js b/ui/app/components/modals/transaction-confirmed/transaction-confirmed.container.js new file mode 100644 index 000000000..63872f7f2 --- /dev/null +++ b/ui/app/components/modals/transaction-confirmed/transaction-confirmed.container.js @@ -0,0 +1,20 @@ +import { connect } from 'react-redux' +import TransactionConfirmed from './transaction-confirmed.component' + +const { hideModal } = require('../../../actions') + +const mapStateToProps = state => { + const { appState: { modal: { modalState: { props } } } } = state + const { onHide } = props + return { + onHide, + } +} + +const mapDispatchToProps = dispatch => { + return { + hideModal: () => dispatch(hideModal()), + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(TransactionConfirmed) diff --git a/ui/app/components/pending-tx/confirm-send-ether.js b/ui/app/components/pending-tx/confirm-send-ether.js index c07c96ccc..5ad35c269 100644 --- a/ui/app/components/pending-tx/confirm-send-ether.js +++ b/ui/app/components/pending-tx/confirm-send-ether.js @@ -291,18 +291,48 @@ ConfirmSendEther.prototype.convertToRenderableCurrency = function (value, curren : value } -ConfirmSendEther.prototype.editTransaction = function (txMeta) { +ConfirmSendEther.prototype.editTransaction = function () { const { editTransaction, history } = this.props + const txMeta = this.gatherTxMeta() editTransaction(txMeta) history.push(SEND_ROUTE) } -ConfirmSendEther.prototype.renderNetworkDisplay = function () { +ConfirmSendEther.prototype.renderHeaderRow = function (isTxReprice) { const windowType = window.METAMASK_UI_TYPE + const isFullScreen = windowType !== ENVIRONMENT_TYPE_NOTIFICATION && + windowType !== ENVIRONMENT_TYPE_POPUP - return (windowType === ENVIRONMENT_TYPE_NOTIFICATION || windowType === ENVIRONMENT_TYPE_POPUP) - ? h(NetworkDisplay) - : null + if (isTxReprice && isFullScreen) { + return null + } + + return ( + h('.page-container__header-row', [ + h('span.page-container__back-button', { + onClick: () => this.editTransaction(), + style: { + visibility: isTxReprice ? 'hidden' : 'initial', + }, + }, 'Edit'), + !isFullScreen && h(NetworkDisplay), + ]) + ) +} + +ConfirmSendEther.prototype.renderHeader = function (isTxReprice) { + const title = isTxReprice ? this.context.t('speedUpTitle') : this.context.t('confirm') + const subtitle = isTxReprice + ? this.context.t('speedUpSubtitle') + : this.context.t('pleaseReviewTransaction') + + return ( + h('.page-container__header', [ + this.renderHeaderRow(isTxReprice), + h('.page-container__title', title), + h('.page-container__subtitle', subtitle), + ]) + ) } ConfirmSendEther.prototype.render = function () { @@ -320,6 +350,7 @@ ConfirmSendEther.prototype.render = function () { }, } = this.props const txMeta = this.gatherTxMeta() + const isTxReprice = Boolean(txMeta.lastGasPrice) const txParams = txMeta.txParams || {} const { @@ -338,11 +369,6 @@ ConfirmSendEther.prototype.render = function () { totalInETH, } = this.getData() - const title = txMeta.lastGasPrice ? 'Reprice Transaction' : 'Confirm' - const subtitle = txMeta.lastGasPrice - ? 'Increase your gas fee to attempt to overwrite and speed up your transaction' - : 'Please review your transaction.' - const convertedAmountInFiat = this.convertToRenderableCurrency(amountInFIAT, currentCurrency) const convertedTotalInFiat = this.convertToRenderableCurrency(totalInFIAT, currentCurrency) @@ -362,19 +388,7 @@ ConfirmSendEther.prototype.render = function () { return ( // Main Send token Card h('.page-container', [ - h('.page-container__header', [ - h('.page-container__header-row', [ - h('span.page-container__back-button', { - onClick: () => this.editTransaction(txMeta), - style: { - visibility: !txMeta.lastGasPrice ? 'initial' : 'hidden', - }, - }, 'Edit'), - this.renderNetworkDisplay(), - ]), - h('.page-container__title', title), - h('.page-container__subtitle', subtitle), - ]), + this.renderHeader(isTxReprice), h('.page-container__content', [ h(SenderToRecipient, { senderName: fromName, diff --git a/ui/app/components/pending-tx/confirm-send-token.js b/ui/app/components/pending-tx/confirm-send-token.js index 656093b3d..ddaa13d22 100644 --- a/ui/app/components/pending-tx/confirm-send-token.js +++ b/ui/app/components/pending-tx/confirm-send-token.js @@ -12,6 +12,7 @@ const actions = require('../../actions') const clone = require('clone') const Identicon = require('../identicon') const GasFeeDisplay = require('../send/gas-fee-display-v2.js') +const NetworkDisplay = require('../network-display') const ethUtil = require('ethereumjs-util') const BN = ethUtil.BN const { @@ -39,6 +40,11 @@ const { } = require('../../selectors') const { SEND_ROUTE, DEFAULT_ROUTE } = require('../../routes') +const { + ENVIRONMENT_TYPE_POPUP, + ENVIRONMENT_TYPE_NOTIFICATION, +} = require('../../../../app/scripts/lib/enums') + ConfirmSendToken.contextTypes = { t: PropTypes.func, } @@ -430,6 +436,43 @@ ConfirmSendToken.prototype.convertToRenderableCurrency = function (value, curren : value } +ConfirmSendToken.prototype.renderHeaderRow = function (isTxReprice) { + const windowType = window.METAMASK_UI_TYPE + const isFullScreen = windowType !== ENVIRONMENT_TYPE_NOTIFICATION && + windowType !== ENVIRONMENT_TYPE_POPUP + + if (isTxReprice && isFullScreen) { + return null + } + + return ( + h('.page-container__header-row', [ + h('span.page-container__back-button', { + onClick: () => this.editTransaction(), + style: { + visibility: isTxReprice ? 'hidden' : 'initial', + }, + }, 'Edit'), + !isFullScreen && h(NetworkDisplay), + ]) + ) +} + +ConfirmSendToken.prototype.renderHeader = function (isTxReprice) { + const title = isTxReprice ? this.context.t('speedUpTitle') : this.context.t('confirm') + const subtitle = isTxReprice + ? this.context.t('speedUpSubtitle') + : this.context.t('pleaseReviewTransaction') + + return ( + h('.page-container__header', [ + this.renderHeaderRow(isTxReprice), + h('.page-container__title', title), + h('.page-container__subtitle', subtitle), + ]) + ) +} + ConfirmSendToken.prototype.render = function () { const txMeta = this.gatherTxMeta() const { @@ -443,25 +486,13 @@ ConfirmSendToken.prototype.render = function () { }, } = this.getData() - this.inputs = [] - const isTxReprice = Boolean(txMeta.lastGasPrice) - const title = isTxReprice ? this.context.t('reprice_title') : this.context.t('confirm') - const subtitle = isTxReprice - ? this.context.t('reprice_subtitle') - : this.context.t('pleaseReviewTransaction') return ( h('div.confirm-screen-container.confirm-send-token', [ // Main Send token Card h('div.page-container', [ - h('div.page-container__header', [ - !txMeta.lastGasPrice && h('button.confirm-screen-back-button', { - onClick: () => this.editTransaction(txMeta), - }, this.context.t('edit')), - h('div.page-container__title', title), - h('div.page-container__subtitle', subtitle), - ]), + this.renderHeader(isTxReprice), h('.page-container__content', [ h('div.flex-row.flex-center.confirm-screen-identicons', [ h('div.confirm-screen-account-wrapper', [ diff --git a/ui/app/components/tx-list-item.js b/ui/app/components/tx-list-item.js index bd4ea80a6..ef441ff73 100644 --- a/ui/app/components/tx-list-item.js +++ b/ui/app/components/tx-list-item.js @@ -1,5 +1,7 @@ const Component = require('react').Component const PropTypes = require('prop-types') +const { compose } = require('recompose') +const { withRouter } = require('react-router-dom') const h = require('react-hyperscript') const connect = require('react-redux').connect const inherits = require('util').inherits @@ -16,13 +18,16 @@ const { conversionUtil, multiplyCurrencies } = require('../conversion-util') const { calcTokenAmount } = require('../token-util') const { getCurrentCurrency } = require('../selectors') +const { CONFIRM_TRANSACTION_ROUTE } = require('../routes') TxListItem.contextTypes = { t: PropTypes.func, } -module.exports = connect(mapStateToProps, mapDispatchToProps)(TxListItem) - +module.exports = compose( + withRouter, + connect(mapStateToProps, mapDispatchToProps) +)(TxListItem) function mapStateToProps (state) { return { @@ -216,6 +221,7 @@ TxListItem.prototype.setSelectedToken = function (tokenAddress) { TxListItem.prototype.resubmit = function () { const { transactionId } = this.props this.props.retryTransaction(transactionId) + .then(id => this.props.history.push(`${CONFIRM_TRANSACTION_ROUTE}/${id}`)) } TxListItem.prototype.render = function () { diff --git a/ui/app/conf-tx.js b/ui/app/conf-tx.js index fb38aaa76..461587cb1 100644 --- a/ui/app/conf-tx.js +++ b/ui/app/conf-tx.js @@ -7,6 +7,7 @@ const { compose } = require('recompose') const actions = require('./actions') const txHelper = require('../lib/tx-helper') const log = require('loglevel') +const R = require('ramda') const PendingTx = require('./components/pending-tx') const SignatureRequest = require('./components/signature-request') @@ -87,37 +88,74 @@ ConfirmTxScreen.prototype.componentDidUpdate = function (prevProps) { network, selectedAddressTxList, send, + history, + match: { params: { id: transactionId } = {} }, } = this.props - const { index: prevIndex, unapprovedTxs: prevUnapprovedTxs } = prevProps - const prevUnconfTxList = txHelper(prevUnapprovedTxs, {}, {}, {}, network) - const prevTxData = prevUnconfTxList[prevIndex] || {} - const prevTx = selectedAddressTxList.find(({ id }) => id === prevTxData.id) || {} + + let prevTx + + if (transactionId) { + prevTx = R.find(({ id }) => id + '' === transactionId)(selectedAddressTxList) + } else { + const { index: prevIndex, unapprovedTxs: prevUnapprovedTxs } = prevProps + const prevUnconfTxList = txHelper(prevUnapprovedTxs, {}, {}, {}, network) + const prevTxData = prevUnconfTxList[prevIndex] || {} + prevTx = selectedAddressTxList.find(({ id }) => id === prevTxData.id) || {} + } + const unconfTxList = txHelper(unapprovedTxs, {}, {}, {}, network) - if (unconfTxList.length === 0 && - (prevTx.status === 'dropped' || !send.to && this.getUnapprovedMessagesTotal() === 0)) { + if (prevTx.status === 'dropped') { + this.props.dispatch(actions.showModal({ + name: 'TRANSACTION_CONFIRMED', + onHide: () => history.push(DEFAULT_ROUTE), + })) + + return + } + + if (unconfTxList.length === 0 && !send.to && this.getUnapprovedMessagesTotal() === 0) { this.props.history.push(DEFAULT_ROUTE) } } -ConfirmTxScreen.prototype.render = function () { - const props = this.props +ConfirmTxScreen.prototype.getTxData = function () { const { network, + index, + unapprovedTxs, + unapprovedMsgs, + unapprovedPersonalMsgs, + unapprovedTypedMessages, + match: { params: { id: transactionId } = {} }, + } = this.props + + const unconfTxList = txHelper( unapprovedTxs, - currentCurrency, unapprovedMsgs, unapprovedPersonalMsgs, unapprovedTypedMessages, + network + ) + + log.info(`rendering a combined ${unconfTxList.length} unconf msgs & txs`) + + return transactionId + ? R.find(({ id }) => id + '' === transactionId)(unconfTxList) + : unconfTxList[index] +} + +ConfirmTxScreen.prototype.render = function () { + const props = this.props + const { + currentCurrency, conversionRate, blockGasLimit, // provider, // computedBalances, } = props - var unconfTxList = txHelper(unapprovedTxs, unapprovedMsgs, unapprovedPersonalMsgs, unapprovedTypedMessages, network) - - var txData = unconfTxList[props.index] || {} + var txData = this.getTxData() || {} var txParams = txData.params || {} // var isNotification = isPopupOrNotification() === 'notification' @@ -136,7 +174,6 @@ ConfirmTxScreen.prototype.render = function () { ]), */ - log.info(`rendering a combined ${unconfTxList.length} unconf msg & txs`) return currentTxView({ // Properties diff --git a/ui/app/reducers/app.js b/ui/app/reducers/app.js index 2b39eb8db..4e9d0848c 100644 --- a/ui/app/reducers/app.js +++ b/ui/app/reducers/app.js @@ -42,6 +42,7 @@ function reduceApp (state, action) { open: false, modalState: { name: null, + props: {}, }, previousModalState: { name: null, @@ -88,13 +89,17 @@ function reduceApp (state, action) { // modal methods: case actions.MODAL_OPEN: + const { name, ...modalProps } = action.payload + return extend(appState, { - modal: Object.assign( - state.appState.modal, - { open: true }, - { modalState: action.payload }, - { previousModalState: appState.modal.modalState}, - ), + modal: { + open: true, + modalState: { + name: name, + props: { ...modalProps }, + }, + previousModalState: { ...appState.modal.modalState }, + }, }) case actions.MODAL_CLOSE: @@ -102,7 +107,7 @@ function reduceApp (state, action) { modal: Object.assign( state.appState.modal, { open: false }, - { modalState: { name: null } }, + { modalState: { name: null, props: {} } }, { previousModalState: appState.modal.modalState}, ), }) From e3cc89cc7b3836bf0dc2051b420f3982413b2ffc Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Tue, 29 May 2018 21:59:53 -0230 Subject: [PATCH 21/74] Update changelog --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7574e4815..af4c886bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,17 @@ ## Current Master +- Adds error messages when passwords don't match in onboarding flow. +- Adds modal notification if a retry in the process of being confirmed is dropped. +- New unlock screen design. +- Design improvements to the add token screen. +- Fix inconsistencies in confirm screen between extension and browser window modes. +- Fix scrolling in deposit ether modal. +- Fix styling of app spinner. +- Font weight changed from 300 to 400. +- New reveal screen design. +- Styling improvements to labels in first time flow and signature request headers. + ## 4.6.1 Mon Apr 30 2018 - Fix bug where sending a transaction resulted in an infinite spinner From d6965c7cdbd7c01a9901ea1125ac77000e0f8b25 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 29 May 2018 17:38:00 -0700 Subject: [PATCH 22/74] deps - bump eth-keyring-controller + update package-lock --- package-lock.json | 103 +++++++++++++++++++++++++--------------------- package.json | 2 +- 2 files changed, 56 insertions(+), 49 deletions(-) diff --git a/package-lock.json b/package-lock.json index e3e1b4eec..790e2e079 100644 --- a/package-lock.json +++ b/package-lock.json @@ -309,7 +309,7 @@ }, "@sinonjs/formatio": { "version": "2.0.0", - "resolved": "http://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", "integrity": "sha512-ls6CAMA6/5gG+O/IdsBcblvnd8qcO/l1TYoNeAzp3wcISOxlPXQEus0mLcdwazEkWjaBdaJ3TaxmNgCLWwvWzg==", "dev": true, "requires": { @@ -1500,7 +1500,8 @@ }, "dependencies": { "bignumber.js": { - "version": "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2" + "version": "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2", + "from": "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2" }, "chai": { "version": "3.5.0", @@ -8007,6 +8008,7 @@ "dependencies": { "async-eventemitter": { "version": "github:ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c", + "from": "async-eventemitter@github:ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c", "requires": { "async": "2.6.0" } @@ -8161,20 +8163,20 @@ } }, "eth-keyring-controller": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/eth-keyring-controller/-/eth-keyring-controller-3.1.1.tgz", - "integrity": "sha512-Z9HTzrop/V4Ld8Wq7uwetKecfWIyx25/uL8aFoZxV3kegZGoXaWoRmNy+4oW0WNLp4BcJ1lk6QfsGEdlymGjmA==", - "requires": { - "bip39": "2.4.0", - "bluebird": "3.5.1", - "browser-passworder": "2.0.3", - "eth-hd-keyring": "1.2.2", - "eth-sig-util": "1.4.2", - "eth-simple-keyring": "1.2.1", - "ethereumjs-util": "5.2.0", - "loglevel": "1.6.0", - "obs-store": "2.4.1", - "promise-filter": "1.1.0" + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/eth-keyring-controller/-/eth-keyring-controller-3.1.3.tgz", + "integrity": "sha512-5xzUeT2mq+S2GvTRnvhdZjrasZg+TqeSTH5sZRbDSXgXC9TYobFvEcK6g2wP/RkOQ3dt0xo/6/TWgwiXFfNZjw==", + "requires": { + "bip39": "^2.4.0", + "bluebird": "^3.5.0", + "browser-passworder": "^2.0.3", + "eth-hd-keyring": "^1.2.2", + "eth-sig-util": "^1.4.0", + "eth-simple-keyring": "^1.2.1", + "ethereumjs-util": "^5.1.2", + "loglevel": "^1.5.0", + "obs-store": "^2.4.1", + "promise-filter": "^1.1.0" }, "dependencies": { "babelify": { @@ -8182,8 +8184,8 @@ "resolved": "https://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=", "requires": { - "babel-core": "6.26.0", - "object-assign": "4.1.1" + "babel-core": "^6.0.14", + "object-assign": "^4.0.0" } }, "ethereumjs-util": { @@ -8191,13 +8193,13 @@ "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", "requires": { - "bn.js": "4.11.8", - "create-hash": "1.1.3", - "ethjs-util": "0.1.4", - "keccak": "1.4.0", - "rlp": "2.0.0", - "safe-buffer": "5.1.1", - "secp256k1": "3.4.0" + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "ethjs-util": "^0.1.3", + "keccak": "^1.0.2", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1", + "secp256k1": "^3.0.1" } }, "obs-store": { @@ -8205,11 +8207,11 @@ "resolved": "https://registry.npmjs.org/obs-store/-/obs-store-2.4.1.tgz", "integrity": "sha512-wpA8G4uSn8cnCKZ0pFTvqsamvy0Sm1hR2ot0Qonbfj5yBMwdAp/eD4vDI+U/ZCbV1hb2V5GapL8YKUdGCvahgg==", "requires": { - "babel-preset-es2015": "6.24.1", - "babelify": "7.3.0", - "readable-stream": "2.3.3", - "through2": "2.0.3", - "xtend": "4.0.1" + "babel-preset-es2015": "^6.22.0", + "babelify": "^7.3.0", + "readable-stream": "^2.2.2", + "through2": "^2.0.3", + "xtend": "^4.0.1" } } } @@ -8256,6 +8258,7 @@ "dependencies": { "ethereumjs-abi": { "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#4ea2fdfed09e8f99117d9362d17c6b01b64a2bcf", + "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "requires": { "bn.js": "4.11.8", "ethereumjs-util": "5.1.3" @@ -8282,11 +8285,11 @@ "resolved": "https://registry.npmjs.org/eth-simple-keyring/-/eth-simple-keyring-1.2.1.tgz", "integrity": "sha1-bXs1LcWppQINYfafryHvsvY2P0U=", "requires": { - "eth-sig-util": "1.4.2", - "ethereumjs-util": "5.2.0", - "ethereumjs-wallet": "0.6.0", - "events": "1.1.1", - "xtend": "4.0.1" + "eth-sig-util": "^1.4.2", + "ethereumjs-util": "^5.1.1", + "ethereumjs-wallet": "^0.6.0", + "events": "^1.1.1", + "xtend": "^4.0.1" }, "dependencies": { "ethereumjs-util": { @@ -8294,13 +8297,13 @@ "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", "requires": { - "bn.js": "4.11.8", - "create-hash": "1.1.3", - "ethjs-util": "0.1.4", - "keccak": "1.4.0", - "rlp": "2.0.0", - "safe-buffer": "5.1.1", - "secp256k1": "3.4.0" + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "ethjs-util": "^0.1.3", + "keccak": "^1.0.2", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1", + "secp256k1": "^3.0.1" } } } @@ -8487,7 +8490,7 @@ "eth-query": "2.1.2", "ethereumjs-block": "1.7.0", "ethereumjs-tx": "1.3.3", - "ethereumjs-util": "github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9", + "ethereumjs-util": "^5.0.1", "ethereumjs-vm": "2.3.5", "through2": "2.0.3", "treeify": "1.1.0", @@ -8636,7 +8639,7 @@ "async": "2.6.0", "ethereum-common": "0.2.0", "ethereumjs-tx": "1.3.3", - "ethereumjs-util": "github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9", + "ethereumjs-util": "^5.0.0", "merkle-patricia-tree": "2.3.0" } }, @@ -8646,7 +8649,7 @@ "integrity": "sha1-7OBR0+/b53GtKlGNYWMsoqt17Ls=", "requires": { "ethereum-common": "0.0.18", - "ethereumjs-util": "github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9" + "ethereumjs-util": "^5.0.0" }, "dependencies": { "ethereum-common": { @@ -8658,6 +8661,7 @@ }, "ethereumjs-util": { "version": "github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9", + "from": "github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9", "requires": { "bn.js": "4.11.8", "create-hash": "1.1.3", @@ -9095,7 +9099,7 @@ }, "event-stream": { "version": "3.3.4", - "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", + "resolved": "http://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", "dev": true, "requires": { @@ -11811,6 +11815,7 @@ }, "gulp": { "version": "github:gulpjs/gulp#71c094a51c7972d26f557899ddecab0210ef3776", + "from": "github:gulpjs/gulp#4.0", "requires": { "glob-watcher": "4.0.0", "gulp-cli": "2.0.1", @@ -18193,7 +18198,7 @@ "integrity": "sha512-LKd2OoIT9Re/OG38zXbd5pyHIk2IfcOUczCwkYXl5iJIbufg9nqpweh66VfPwMkUlrEvc7YVvtQdmSrB9V9TkQ==", "requires": { "async": "1.5.2", - "ethereumjs-util": "github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9", + "ethereumjs-util": "^5.0.0", "level-ws": "0.0.0", "levelup": "1.3.9", "memdown": "1.4.1", @@ -31215,7 +31220,8 @@ }, "dependencies": { "bignumber.js": { - "version": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934" + "version": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934", + "from": "git+https://github.com/frozeman/bignumber.js-nolookahead.git" } } }, @@ -31696,6 +31702,7 @@ }, "websocket": { "version": "git://github.com/frozeman/WebSocket-Node.git#7004c39c42ac98875ab61126e5b4a925430f592c", + "from": "websocket@git://github.com/frozeman/WebSocket-Node.git#7004c39c42ac98875ab61126e5b4a925430f592c", "requires": { "debug": "2.6.9", "nan": "2.8.0", diff --git a/package.json b/package.json index 5fbbabe80..ed127e059 100644 --- a/package.json +++ b/package.json @@ -98,7 +98,7 @@ "eth-hd-keyring": "^1.2.1", "eth-json-rpc-filters": "^1.2.6", "eth-json-rpc-infura": "^3.0.0", - "eth-keyring-controller": "^3.1.1", + "eth-keyring-controller": "^3.1.3", "eth-phishing-detect": "^1.1.4", "eth-query": "^2.1.2", "eth-sig-util": "^1.4.2", From f90ad6191cde32830cff4a82d3d8c6a31155bc29 Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 29 May 2018 18:20:54 -0700 Subject: [PATCH 23/74] Add account --- test/e2e/metamask.spec.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/e2e/metamask.spec.js b/test/e2e/metamask.spec.js index 8ec7de16c..d2ca29104 100644 --- a/test/e2e/metamask.spec.js +++ b/test/e2e/metamask.spec.js @@ -121,6 +121,12 @@ describe('Metamask popup page', function () { await delay(300) }) + it('adds a second account', async function () { + await driver.findElement(By.css('#app-content > div > div.full-width > div > div:nth-child(2) > span > div')).click() + await delay(300) + await driver.findElement(By.css('#app-content > div > div.full-width > div > div:nth-child(2) > span > div > div > span > div > li:nth-child(3) > span')).click() + }) + it('shows account address', async function () { accountAddress = await driver.findElement(By.css('#app-content > div > div.app-primary.from-left > div > div > div:nth-child(1) > flex-column > div.flex-row > div')).getText() }) From a19b911febbd2f29ef838a0f6059319c6d1c054e Mon Sep 17 00:00:00 2001 From: Alexander Tseung Date: Tue, 29 May 2018 18:31:32 -0700 Subject: [PATCH 24/74] Add rpc key to i18n messages (#4375) --- app/_locales/en/messages.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 34b7477a6..4851508a3 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -679,6 +679,9 @@ "ropsten": { "message": "Ropsten Test Network" }, + "rpc": { + "message": "Custom RPC" + }, "currentRpc": { "message": "Current RPC" }, From 73afb263cb80a54cc52e50349c3d9f4fe173bd98 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 29 May 2018 22:13:58 -0700 Subject: [PATCH 25/74] ci - job-screens - use e2e funcs --- test/screens/new-ui.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/test/screens/new-ui.js b/test/screens/new-ui.js index 6b873ac85..65a542e49 100644 --- a/test/screens/new-ui.js +++ b/test/screens/new-ui.js @@ -11,9 +11,8 @@ const GIFEncoder = require('gifencoder') const pngFileStream = require('png-file-stream') const sizeOfPng = require('image-size/lib/types/png') const By = webdriver.By -const { delay, buildWebDriver } = require('./func') const localesIndex = require('../../app/_locales/index.json') -// const localesIndex = [] +const { delay, buildChromeWebDriver, buildFirefoxWebdriver, installWebExt, getExtensionIdChrome, getExtensionIdFirefox } = require('../e2e/func') const eth = new Ethjs(new Ethjs.HttpProvider('http://localhost:8545')) @@ -50,11 +49,10 @@ async function captureAllScreens() { await cleanScreenShotDir() - // setup selenium and install extension const extPath = path.resolve('dist/chrome') - driver = buildWebDriver(extPath) - await driver.get('chrome://extensions-frame') - const extensionId = await driver.executeScript('return document.querySelector("extensions-manager").shadowRoot.querySelector("extensions-view-manager extensions-item-list").shadowRoot.querySelector("#container > div.items-container > extensions-item:nth-child(2)").getAttribute("id")') + driver = buildChromeWebDriver(extPath) + const extensionId = await getExtensionIdChrome(driver) + await driver.get(`chrome-extension://${extensionId}/home.html`) await delay(500) tabs = await driver.getAllWindowHandles() From be6776897f16ab73fd6b363a1a9bc685c3afddcd Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 29 May 2018 23:07:45 -0700 Subject: [PATCH 26/74] Delay before getting address text --- test/e2e/metamask.spec.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/e2e/metamask.spec.js b/test/e2e/metamask.spec.js index d2ca29104..a08a34d96 100644 --- a/test/e2e/metamask.spec.js +++ b/test/e2e/metamask.spec.js @@ -128,6 +128,7 @@ describe('Metamask popup page', function () { }) it('shows account address', async function () { + await delay(300) accountAddress = await driver.findElement(By.css('#app-content > div > div.app-primary.from-left > div > div > div:nth-child(1) > flex-column > div.flex-row > div')).getText() }) From d40971e7f30f86629f661a53e4c7b51f34397d87 Mon Sep 17 00:00:00 2001 From: Alexander Tseung Date: Wed, 30 May 2018 09:23:31 -0700 Subject: [PATCH 27/74] Fix error handling on incorrect password (#4401) --- .../unlock-page/unlock-page.component.js | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/ui/app/components/pages/unlock-page/unlock-page.component.js b/ui/app/components/pages/unlock-page/unlock-page.component.js index b6384b32d..8bc3897da 100644 --- a/ui/app/components/pages/unlock-page/unlock-page.component.js +++ b/ui/app/components/pages/unlock-page/unlock-page.component.js @@ -34,14 +34,7 @@ class UnlockPage extends Component { } } - tryUnlockMetamask (password) { - const { tryUnlockMetamask, history } = this.props - tryUnlockMetamask(password) - .catch(({ message }) => this.setState({ error: message })) - .then(() => history.push(DEFAULT_ROUTE)) - } - - handleSubmit (event) { + async handleSubmit (event) { event.preventDefault() event.stopPropagation() @@ -54,9 +47,14 @@ class UnlockPage extends Component { this.setState({ error: null }) - tryUnlockMetamask(password) - .catch(({ message }) => this.setState({ error: message })) - .then(() => history.push(DEFAULT_ROUTE)) + try { + await tryUnlockMetamask(password) + } catch ({ message }) { + this.setState({ error: message }) + return + } + + history.push(DEFAULT_ROUTE) } handleInputChange ({ target }) { From 389346913bf076fde6190a61afc4e3e4cd210afc Mon Sep 17 00:00:00 2001 From: Alexander Tseung Date: Wed, 30 May 2018 10:38:53 -0700 Subject: [PATCH 28/74] Prevent loading screen from overlaying the app bar (#4417) --- ui/app/app.js | 1 - .../components/loading-screen/loading-screen.component.js | 6 +----- ui/app/components/pending-tx/index.js | 5 +---- ui/app/css/itcss/components/loading-overlay.scss | 4 ++-- 4 files changed, 4 insertions(+), 12 deletions(-) diff --git a/ui/app/app.js b/ui/app/app.js index aa2b24422..0e8b907df 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -137,7 +137,6 @@ class App extends Component { (isLoading || isLoadingNetwork) && h(Loading, { loadingMessage: loadMessage, - fullScreen: true, }), // content diff --git a/ui/app/components/loading-screen/loading-screen.component.js b/ui/app/components/loading-screen/loading-screen.component.js index bce2a4aac..6b843cfee 100644 --- a/ui/app/components/loading-screen/loading-screen.component.js +++ b/ui/app/components/loading-screen/loading-screen.component.js @@ -1,7 +1,6 @@ const { Component } = require('react') const h = require('react-hyperscript') const PropTypes = require('prop-types') -const classnames = require('classnames') const Spinner = require('../spinner') class LoadingScreen extends Component { @@ -12,9 +11,7 @@ class LoadingScreen extends Component { render () { return ( - h('.loading-overlay', { - className: classnames({ 'loading-overlay--full-screen': this.props.fullScreen }), - }, [ + h('.loading-overlay', [ h('.loading-overlay__container', [ h(Spinner, { color: '#F7C06C', @@ -29,7 +26,6 @@ class LoadingScreen extends Component { LoadingScreen.propTypes = { loadingMessage: PropTypes.string, - fullScreen: PropTypes.bool, } module.exports = LoadingScreen diff --git a/ui/app/components/pending-tx/index.js b/ui/app/components/pending-tx/index.js index 893538bcf..3f8cd8823 100644 --- a/ui/app/components/pending-tx/index.js +++ b/ui/app/components/pending-tx/index.js @@ -130,7 +130,6 @@ PendingTx.prototype.render = function () { if (isFetching) { return h(Loading, { - fullScreen: true, loadingMessage: this.context.t('generatingTransaction'), }) } @@ -157,9 +156,7 @@ PendingTx.prototype.render = function () { sendTransaction, }) default: - return h(Loading, { - fullScreen: true, - }) + return h(Loading) } } diff --git a/ui/app/css/itcss/components/loading-overlay.scss b/ui/app/css/itcss/components/loading-overlay.scss index c18b7fa59..b07d6af17 100644 --- a/ui/app/css/itcss/components/loading-overlay.scss +++ b/ui/app/css/itcss/components/loading-overlay.scss @@ -11,8 +11,8 @@ background: rgba(255, 255, 255, .8); @media screen and (max-width: 575px) { - margin-top: 56px; - height: calc(100% - 56px); + margin-top: 66px; + height: calc(100% - 66px); } @media screen and (min-width: 576px) { From b69da50095ff5077428e08cbc20d7dd839518884 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 30 May 2018 14:29:14 -0700 Subject: [PATCH 29/74] deps - bump eth-keyring-controller for bugfix --- package-lock.json | 20 +++++++++++++------- package.json | 2 +- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index f501b923c..4b27c769e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8169,16 +8169,17 @@ } }, "eth-keyring-controller": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/eth-keyring-controller/-/eth-keyring-controller-3.1.3.tgz", - "integrity": "sha512-5xzUeT2mq+S2GvTRnvhdZjrasZg+TqeSTH5sZRbDSXgXC9TYobFvEcK6g2wP/RkOQ3dt0xo/6/TWgwiXFfNZjw==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/eth-keyring-controller/-/eth-keyring-controller-3.1.4.tgz", + "integrity": "sha512-NNlVB/TBc8p9CblwECjPlUR+7MNQKiBa7tEFxIzZ9MjjNCEYPWDXTm0vJZzuDtVmFxYwIA53UD0QEn0QNxWNEQ==", + "dev": true, "requires": { "bip39": "^2.4.0", "bluebird": "^3.5.0", "browser-passworder": "^2.0.3", "eth-hd-keyring": "^1.2.2", "eth-sig-util": "^1.4.0", - "eth-simple-keyring": "^1.2.1", + "eth-simple-keyring": "^1.2.2", "ethereumjs-util": "^5.1.2", "loglevel": "^1.5.0", "obs-store": "^2.4.1", @@ -8189,6 +8190,7 @@ "version": "7.3.0", "resolved": "https://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=", + "dev": true, "requires": { "babel-core": "^6.0.14", "object-assign": "^4.0.0" @@ -8198,6 +8200,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", + "dev": true, "requires": { "bn.js": "^4.11.0", "create-hash": "^1.1.2", @@ -8212,6 +8215,7 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/obs-store/-/obs-store-2.4.1.tgz", "integrity": "sha512-wpA8G4uSn8cnCKZ0pFTvqsamvy0Sm1hR2ot0Qonbfj5yBMwdAp/eD4vDI+U/ZCbV1hb2V5GapL8YKUdGCvahgg==", + "dev": true, "requires": { "babel-preset-es2015": "^6.22.0", "babelify": "^7.3.0", @@ -8287,9 +8291,10 @@ } }, "eth-simple-keyring": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/eth-simple-keyring/-/eth-simple-keyring-1.2.1.tgz", - "integrity": "sha1-bXs1LcWppQINYfafryHvsvY2P0U=", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/eth-simple-keyring/-/eth-simple-keyring-1.2.2.tgz", + "integrity": "sha512-uQVBYshHUOaXVoat1BpLA/QNMCr4hgdFBgwIB7rRmQ+m3vQQAseUsOM+biPDYzq6end+6LjcccElLpQaIZe6dg==", + "dev": true, "requires": { "eth-sig-util": "^1.4.2", "ethereumjs-util": "^5.1.1", @@ -8302,6 +8307,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", + "dev": true, "requires": { "bn.js": "^4.11.0", "create-hash": "^1.1.2", diff --git a/package.json b/package.json index 0b0ac839a..ba764f45b 100644 --- a/package.json +++ b/package.json @@ -98,7 +98,6 @@ "eth-hd-keyring": "^1.2.1", "eth-json-rpc-filters": "^1.2.6", "eth-json-rpc-infura": "^3.0.0", - "eth-keyring-controller": "^3.1.3", "eth-phishing-detect": "^1.1.4", "eth-query": "^2.1.2", "eth-sig-util": "^1.4.2", @@ -230,6 +229,7 @@ "eslint-plugin-mocha": "^5.0.0", "eslint-plugin-react": "^7.4.0", "eth-json-rpc-middleware": "^1.6.0", + "eth-keyring-controller": "^3.1.4", "file-loader": "^1.1.11", "fs-promise": "^2.0.3", "ganache-cli": "^6.1.0", From adfa033829e36edc9417c97fc93e8e8c5ee1f471 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 30 May 2018 15:07:46 -0700 Subject: [PATCH 30/74] changelog - add note on brave --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index af4c886bc..412392c15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Current Master +- Fix Brave support - Adds error messages when passwords don't match in onboarding flow. - Adds modal notification if a retry in the process of being confirmed is dropped. - New unlock screen design. From e59f606adb65de85484b0fb258980543967ee5e1 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 30 May 2018 15:08:44 -0700 Subject: [PATCH 31/74] 4.7.0 --- CHANGELOG.md | 2 ++ app/manifest.json | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 412392c15..868983c15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Current Master +## 4.7.0 Wed May 30 2018 + - Fix Brave support - Adds error messages when passwords don't match in onboarding flow. - Adds modal notification if a retry in the process of being confirmed is dropped. diff --git a/app/manifest.json b/app/manifest.json index 141026d10..52ce8cc0a 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,7 +1,7 @@ { "name": "__MSG_appName__", "short_name": "__MSG_appName__", - "version": "4.6.1", + "version": "4.7.0", "manifest_version": 2, "author": "https://metamask.io", "description": "__MSG_appDescription__", @@ -68,6 +68,8 @@ "matches": [ "https://metamask.io/*" ], - "ids": ["*"] + "ids": [ + "*" + ] } } \ No newline at end of file From e2e4496c875355c5b73524bf5c721239ad5d3e09 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 30 May 2018 17:42:41 -0700 Subject: [PATCH 32/74] sentry - message rewrite - guard against missing message --- app/scripts/lib/setupRaven.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/lib/setupRaven.js b/app/scripts/lib/setupRaven.js index d164827ab..77aefb00a 100644 --- a/app/scripts/lib/setupRaven.js +++ b/app/scripts/lib/setupRaven.js @@ -66,7 +66,7 @@ function simplifyErrorMessages(report) { function rewriteErrorMessages(report, rewriteFn) { // rewrite top level message - report.message = rewriteFn(report.message) + if (report.message) report.message = rewriteFn(report.message) // rewrite each exception message if (report.exception && report.exception.values) { report.exception.values.forEach(item => { From d454b5de2b03111a05c4e8a8b0a91e612b8f0266 Mon Sep 17 00:00:00 2001 From: Dan Date: Thu, 31 May 2018 13:20:15 -0230 Subject: [PATCH 33/74] Token name is not hidden in wallet if balance is exceptionally long. --- ui/app/components/token-cell.js | 4 ++-- ui/app/css/itcss/components/token-list.scss | 10 +++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/ui/app/components/token-cell.js b/ui/app/components/token-cell.js index c84117d84..4100d76a5 100644 --- a/ui/app/components/token-cell.js +++ b/ui/app/components/token-cell.js @@ -101,8 +101,8 @@ TokenCell.prototype.render = function () { h('div.token-list-item__balance-ellipsis', null, [ h('div.token-list-item__balance-wrapper', null, [ - h('h3.token-list-item__token-balance', `${string || 0} ${symbol}`), - + h('div.token-list-item__token-balance', `${string || 0}`), + h('div.token-list-item__token-symbol', symbol), showFiat && h('div.token-list-item__fiat-amount', { style: {}, }, formattedFiat), diff --git a/ui/app/css/itcss/components/token-list.scss b/ui/app/css/itcss/components/token-list.scss index e8de317e3..214bbc774 100644 --- a/ui/app/css/itcss/components/token-list.scss +++ b/ui/app/css/itcss/components/token-list.scss @@ -14,10 +14,16 @@ $wallet-balance-breakpoint-range: "screen and (min-width: #{$break-large}) and ( min-width: 0; &__token-balance { - font-size: 1.5rem; + margin-right: 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; + flex: 1; + } + + &__token-balance, &__token-symbol { + font-size: 1.5rem; + display: inline-flex; @media #{$wallet-balance-breakpoint-range} { font-size: 95%; @@ -68,6 +74,8 @@ $wallet-balance-breakpoint-range: "screen and (min-width: #{$break-large}) and ( &__balance-wrapper { flex: 1 1 auto; min-width: 0; + overflow: hidden; + text-overflow: ellipsis; } } From f4d833cb09758beb62a65ad4011d16bdb81b33ff Mon Sep 17 00:00:00 2001 From: Alexander Tseung Date: Tue, 29 May 2018 14:33:29 -0700 Subject: [PATCH 34/74] Change btn-secondary styles to btn-default. Make btn-secondary red warning style buttons --- ui/app/components/button/button.component.js | 23 +++++---- ui/app/components/button/button.stories.js | 19 ++++++- .../components/customize-gas-modal/index.js | 2 +- .../components/modals/deposit-ether-modal.js | 2 +- .../modals/export-private-key-modal.js | 6 +-- .../pages/add-token/add-token.component.js | 2 +- .../confirm-add-token.component.js | 2 +- .../create-account/import-account/json.js | 4 +- .../import-account/private-key.js | 6 +-- .../pages/create-account/new-account.js | 4 +- .../components/pages/keychains/reveal-seed.js | 6 +-- ui/app/components/pages/settings/settings.js | 8 +-- ui/app/components/shapeshift-form.js | 2 +- ui/app/components/signature-request.js | 4 +- ui/app/css/itcss/components/buttons.scss | 49 ++++++++++--------- ui/app/send-v2.js | 2 +- 16 files changed, 79 insertions(+), 62 deletions(-) diff --git a/ui/app/components/button/button.component.js b/ui/app/components/button/button.component.js index fe3bf363c..e8e798445 100644 --- a/ui/app/components/button/button.component.js +++ b/ui/app/components/button/button.component.js @@ -2,20 +2,15 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' import classnames from 'classnames' -const SECONDARY = 'secondary' +const CLASSNAME_DEFAULT = 'btn-default' const CLASSNAME_PRIMARY = 'btn-primary' -const CLASSNAME_PRIMARY_LARGE = 'btn-primary--lg' const CLASSNAME_SECONDARY = 'btn-secondary' -const CLASSNAME_SECONDARY_LARGE = 'btn-secondary--lg' +const CLASSNAME_LARGE = 'btn--large' -const getClassName = (type, large = false) => { - let output = type === SECONDARY ? CLASSNAME_SECONDARY : CLASSNAME_PRIMARY - - if (large) { - output += ` ${type === SECONDARY ? CLASSNAME_SECONDARY_LARGE : CLASSNAME_PRIMARY_LARGE}` - } - - return output +const typeHash = { + default: CLASSNAME_DEFAULT, + primary: CLASSNAME_PRIMARY, + secondary: CLASSNAME_SECONDARY, } class Button extends Component { @@ -24,7 +19,11 @@ class Button extends Component { return ( ) - .add('secondary', () => ( + .add('secondary', () => + ) + .add('default', () => ( + )) .add('large primary', () => ( + )) diff --git a/ui/app/components/customize-gas-modal/index.js b/ui/app/components/customize-gas-modal/index.js index 1ff8eea87..e3529041b 100644 --- a/ui/app/components/customize-gas-modal/index.js +++ b/ui/app/components/customize-gas-modal/index.js @@ -308,7 +308,7 @@ CustomizeGasModal.prototype.render = function () { }, [this.context.t('revert')]), h('div.send-v2__customize-gas__buttons', [ - h('button.btn-secondary.send-v2__customize-gas__cancel', { + h('button.btn-default.send-v2__customize-gas__cancel', { onClick: this.props.hideModal, style: { marginRight: '10px', diff --git a/ui/app/components/modals/deposit-ether-modal.js b/ui/app/components/modals/deposit-ether-modal.js index ad5f9b695..2daa7fa1d 100644 --- a/ui/app/components/modals/deposit-ether-modal.js +++ b/ui/app/components/modals/deposit-ether-modal.js @@ -109,7 +109,7 @@ DepositEtherModal.prototype.renderRow = function ({ ]), !hideButton && h('div.deposit-ether-modal__buy-row__button', [ - h('button.btn-primary--lg.deposit-ether-modal__deposit-button', { + h('button.btn-primary.btn--large.deposit-ether-modal__deposit-button', { onClick: onButtonClick, }, [buttonLabel]), ]), diff --git a/ui/app/components/modals/export-private-key-modal.js b/ui/app/components/modals/export-private-key-modal.js index 447e43b7a..80ece425f 100644 --- a/ui/app/components/modals/export-private-key-modal.js +++ b/ui/app/components/modals/export-private-key-modal.js @@ -87,14 +87,14 @@ ExportPrivateKeyModal.prototype.renderButton = function (className, onClick, lab ExportPrivateKeyModal.prototype.renderButtons = function (privateKey, password, address, hideModal) { return h('div.export-private-key-buttons', {}, [ !privateKey && this.renderButton( - 'btn-secondary--lg export-private-key__button export-private-key__button--cancel', + 'btn-default btn--large export-private-key__button export-private-key__button--cancel', () => hideModal(), 'Cancel' ), (privateKey - ? this.renderButton('btn-primary--lg export-private-key__button', () => hideModal(), this.context.t('done')) - : this.renderButton('btn-primary--lg export-private-key__button', () => this.exportAccountAndGetPrivateKey(this.state.password, address), this.context.t('confirm')) + ? this.renderButton('btn-primary btn--large export-private-key__button', () => hideModal(), this.context.t('done')) + : this.renderButton('btn-primary btn--large export-private-key__button', () => this.exportAccountAndGetPrivateKey(this.state.password, address), this.context.t('confirm')) ), ]) diff --git a/ui/app/components/pages/add-token/add-token.component.js b/ui/app/components/pages/add-token/add-token.component.js index 0677b4317..1f4b37b53 100644 --- a/ui/app/components/pages/add-token/add-token.component.js +++ b/ui/app/components/pages/add-token/add-token.component.js @@ -323,7 +323,7 @@ class AddToken extends Component {
+ +
+ + ) + } +} + +export default ConfirmResetAccount diff --git a/ui/app/components/modals/confirm-reset-account/confirm-reset-account.container.js b/ui/app/components/modals/confirm-reset-account/confirm-reset-account.container.js new file mode 100644 index 000000000..9630a5593 --- /dev/null +++ b/ui/app/components/modals/confirm-reset-account/confirm-reset-account.container.js @@ -0,0 +1,13 @@ +import { connect } from 'react-redux' +import ConfirmResetAccount from './confirm-reset-account.component' + +const { hideModal, resetAccount } = require('../../../actions') + +const mapDispatchToProps = dispatch => { + return { + hideModal: () => dispatch(hideModal()), + resetAccount: () => dispatch(resetAccount()), + } +} + +export default connect(null, mapDispatchToProps)(ConfirmResetAccount) diff --git a/ui/app/components/modals/confirm-reset-account/index.js b/ui/app/components/modals/confirm-reset-account/index.js new file mode 100644 index 000000000..c812ffc55 --- /dev/null +++ b/ui/app/components/modals/confirm-reset-account/index.js @@ -0,0 +1,2 @@ +import ConfirmResetAccount from './confirm-reset-account.container' +module.exports = ConfirmResetAccount diff --git a/ui/app/components/modals/index.scss b/ui/app/components/modals/index.scss index ec6207f7e..ad6fe16d3 100644 --- a/ui/app/components/modals/index.scss +++ b/ui/app/components/modals/index.scss @@ -1 +1,52 @@ -@import './transaction-confirmed/index'; +.modal-container { + width: 100%; + height: 100%; + background-color: #fff; + display: flex; + flex-flow: column; + border-radius: 8px; + + &__title { + font-size: 1.5rem; + font-weight: 500; + padding: 16px 0; + text-align: center; + } + + &__description { + text-align: center; + font-size: .875rem; + } + + &__content { + overflow-y: auto; + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + padding: 32px; + + @media screen and (max-width: 575px) { + justify-content: center; + padding: 28px 20px; + } + } + + &__footer { + display: flex; + flex-flow: row; + justify-content: center; + border-top: 1px solid #d2d8dd; + padding: 16px; + flex: 0 0 auto; + + &-button { + min-width: 0; + margin-right: 16px; + + &:last-of-type { + margin-right: 0; + } + } + } +} diff --git a/ui/app/components/modals/modal.js b/ui/app/components/modals/modal.js index 841189277..85e85597a 100644 --- a/ui/app/components/modals/modal.js +++ b/ui/app/components/modals/modal.js @@ -19,8 +19,30 @@ const ShapeshiftDepositTxModal = require('./shapeshift-deposit-tx-modal.js') const HideTokenConfirmationModal = require('./hide-token-confirmation-modal') const CustomizeGasModal = require('../customize-gas-modal') const NotifcationModal = require('./notification-modal') -const ConfirmResetAccount = require('./notification-modals/confirm-reset-account') +const ConfirmResetAccount = require('./confirm-reset-account') const TransactionConfirmed = require('./transaction-confirmed') +const WelcomeBeta = require('./welcome-beta') +const Notification = require('./notification') + +const modalContainerBaseStyle = { + transform: 'translate3d(-50%, 0, 0px)', + border: '1px solid #CCCFD1', + borderRadius: '8px', + backgroundColor: '#FFFFFF', + boxShadow: '0 2px 22px 0 rgba(0,0,0,0.2)', +} + +const modalContainerLaptopStyle = { + ...modalContainerBaseStyle, + width: '344px', + top: '15%', +} + +const modalContainerMobileStyle = { + ...modalContainerBaseStyle, + width: '309px', + top: '12.5%', +} const accountModalStyle = { mobileModalStyle: { @@ -174,18 +196,18 @@ const MODALS = { BETA_UI_NOTIFICATION_MODAL: { contents: [ - h(NotifcationModal, { - header: 'uiWelcome', - message: 'uiWelcomeMessage', - }), + h(Notification, [ + h(WelcomeBeta), + ]), ], mobileModalStyle: { - width: '95%', - top: getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_POPUP ? '52vh' : '36.5vh', + ...modalContainerMobileStyle, }, laptopModalStyle: { - width: '449px', - top: 'calc(33% + 45px)', + ...modalContainerLaptopStyle, + }, + contentStyle: { + borderRadius: '8px', }, }, @@ -209,12 +231,13 @@ const MODALS = { CONFIRM_RESET_ACCOUNT: { contents: h(ConfirmResetAccount), mobileModalStyle: { - width: '95%', - top: getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_POPUP ? '52vh' : '36.5vh', + ...modalContainerMobileStyle, }, laptopModalStyle: { - width: '473px', - top: 'calc(33% + 45px)', + ...modalContainerLaptopStyle, + }, + contentStyle: { + borderRadius: '8px', }, }, @@ -269,31 +292,18 @@ const MODALS = { TRANSACTION_CONFIRMED: { disableBackdropClick: true, contents: [ - h(TransactionConfirmed, {}, []), + h(Notification, [ + h(TransactionConfirmed), + ]), ], mobileModalStyle: { - width: '100%', - height: '100%', - transform: 'none', - left: '0', - right: '0', - margin: '0 auto', - boxShadow: '0 0 7px 0 rgba(0,0,0,0.08)', - top: '0', - display: 'flex', + ...modalContainerMobileStyle, }, laptopModalStyle: { - width: '344px', - transform: 'translate3d(-50%, 0, 0px)', - top: '15%', - border: '1px solid #CCCFD1', - borderRadius: '8px', - backgroundColor: '#FFFFFF', - boxShadow: '0 2px 22px 0 rgba(0,0,0,0.2)', + ...modalContainerLaptopStyle, }, contentStyle: { borderRadius: '8px', - height: '100%', }, }, diff --git a/ui/app/components/modals/notification-modals/confirm-reset-account.js b/ui/app/components/modals/notification-modals/confirm-reset-account.js deleted file mode 100644 index 89fa9bef1..000000000 --- a/ui/app/components/modals/notification-modals/confirm-reset-account.js +++ /dev/null @@ -1,46 +0,0 @@ -const { Component } = require('react') -const PropTypes = require('prop-types') -const h = require('react-hyperscript') -const connect = require('react-redux').connect -const actions = require('../../../actions') -const NotifcationModal = require('../notification-modal') - -class ConfirmResetAccount extends Component { - render () { - const { resetAccount } = this.props - - return h(NotifcationModal, { - header: 'Are you sure you want to reset account?', - message: h('div', [ - - h('span', `Resetting is for developer use only. This button wipes the current account's transaction history, - which is used to calculate the current account nonce. `), - - h('a.notification-modal__link', { - href: 'http://metamask.helpscoutdocs.com/article/36-resetting-an-account', - target: '_blank', - onClick (event) { global.platform.openWindow({ url: event.target.href }) }, - }, 'Read more.'), - - ]), - showCancelButton: true, - showConfirmButton: true, - onConfirm: resetAccount, - - }) - } -} - -ConfirmResetAccount.propTypes = { - resetAccount: PropTypes.func, -} - -const mapDispatchToProps = dispatch => { - return { - resetAccount: () => { - dispatch(actions.resetAccount()) - }, - } -} - -module.exports = connect(null, mapDispatchToProps)(ConfirmResetAccount) diff --git a/ui/app/components/modals/notification/index.js b/ui/app/components/modals/notification/index.js new file mode 100644 index 000000000..d60a3129b --- /dev/null +++ b/ui/app/components/modals/notification/index.js @@ -0,0 +1,2 @@ +import Notification from './notification.container' +module.exports = Notification diff --git a/ui/app/components/modals/notification/notification.component.js b/ui/app/components/modals/notification/notification.component.js new file mode 100644 index 000000000..1af2f3ca8 --- /dev/null +++ b/ui/app/components/modals/notification/notification.component.js @@ -0,0 +1,30 @@ +import React from 'react' +import PropTypes from 'prop-types' +import Button from '../../button' + +const Notification = (props, context) => { + return ( +
+ { props.children } +
+ +
+
+ ) +} + +Notification.propTypes = { + onHide: PropTypes.func.isRequired, + children: PropTypes.element, +} + +Notification.contextTypes = { + t: PropTypes.func, +} + +export default Notification diff --git a/ui/app/components/modals/notification/notification.container.js b/ui/app/components/modals/notification/notification.container.js new file mode 100644 index 000000000..5b98714da --- /dev/null +++ b/ui/app/components/modals/notification/notification.container.js @@ -0,0 +1,38 @@ +import { connect } from 'react-redux' +import Notification from './notification.component' + +const { hideModal } = require('../../../actions') + +const mapStateToProps = state => { + const { appState: { modal: { modalState: { props } } } } = state + const { onHide } = props + return { + onHide, + } +} + +const mapDispatchToProps = dispatch => { + return { + hideModal: () => dispatch(hideModal()), + } +} + +const mergeProps = (stateProps, dispatchProps, ownProps) => { + const { onHide, ...otherStateProps } = stateProps + const { hideModal, ...otherDispatchProps } = dispatchProps + + return { + ...otherStateProps, + ...otherDispatchProps, + ...ownProps, + onHide: () => { + hideModal() + + if (onHide && typeof onHide === 'function') { + onHide() + } + }, + } +} + +export default connect(mapStateToProps, mapDispatchToProps, mergeProps)(Notification) diff --git a/ui/app/components/modals/transaction-confirmed/index.js b/ui/app/components/modals/transaction-confirmed/index.js index c8db91388..cee8da7f8 100644 --- a/ui/app/components/modals/transaction-confirmed/index.js +++ b/ui/app/components/modals/transaction-confirmed/index.js @@ -1,2 +1,2 @@ -import TransactionConfirmed from './transaction-confirmed.container' +import TransactionConfirmed from './transaction-confirmed.component' module.exports = TransactionConfirmed diff --git a/ui/app/components/modals/transaction-confirmed/index.scss b/ui/app/components/modals/transaction-confirmed/index.scss deleted file mode 100644 index f8cd1f212..000000000 --- a/ui/app/components/modals/transaction-confirmed/index.scss +++ /dev/null @@ -1,21 +0,0 @@ -.transaction-confirmed { - display: flex; - flex-direction: column; - align-items: center; - padding: 32px; - - &__title { - font-size: 2rem; - padding: 16px 0; - } - - &__description { - text-align: center; - font-size: .875rem; - line-height: 1.5rem; - } - - @media screen and (max-width: 575px) { - justify-content: center; - } -} diff --git a/ui/app/components/modals/transaction-confirmed/transaction-confirmed.component.js b/ui/app/components/modals/transaction-confirmed/transaction-confirmed.component.js index 8d3b288ae..c1c8a2976 100644 --- a/ui/app/components/modals/transaction-confirmed/transaction-confirmed.component.js +++ b/ui/app/components/modals/transaction-confirmed/transaction-confirmed.component.js @@ -1,42 +1,20 @@ -import React, { Component } from 'react' +import React from 'react' import PropTypes from 'prop-types' -import Button from '../../button' -class TransactionConfirmed extends Component { - render () { - const { t } = this.context +const TransactionConfirmed = (props, context) => { + const { t } = context - return ( -
-
- -
- { `${t('confirmed')}!` } -
-
- { t('initialTransactionConfirmed') } -
-
-
- -
+ return ( +
+ +
+ { `${t('confirmed')}!` }
- ) - } -} - -TransactionConfirmed.propTypes = { - hideModal: PropTypes.func.isRequired, - onHide: PropTypes.func.isRequired, +
+ { t('initialTransactionConfirmed') } +
+
+ ) } TransactionConfirmed.contextTypes = { diff --git a/ui/app/components/modals/transaction-confirmed/transaction-confirmed.container.js b/ui/app/components/modals/transaction-confirmed/transaction-confirmed.container.js deleted file mode 100644 index 63872f7f2..000000000 --- a/ui/app/components/modals/transaction-confirmed/transaction-confirmed.container.js +++ /dev/null @@ -1,20 +0,0 @@ -import { connect } from 'react-redux' -import TransactionConfirmed from './transaction-confirmed.component' - -const { hideModal } = require('../../../actions') - -const mapStateToProps = state => { - const { appState: { modal: { modalState: { props } } } } = state - const { onHide } = props - return { - onHide, - } -} - -const mapDispatchToProps = dispatch => { - return { - hideModal: () => dispatch(hideModal()), - } -} - -export default connect(mapStateToProps, mapDispatchToProps)(TransactionConfirmed) diff --git a/ui/app/components/modals/welcome-beta/index.js b/ui/app/components/modals/welcome-beta/index.js new file mode 100644 index 000000000..515c9cdaf --- /dev/null +++ b/ui/app/components/modals/welcome-beta/index.js @@ -0,0 +1,2 @@ +import WelcomeBeta from './welcome-beta.component' +module.exports = WelcomeBeta diff --git a/ui/app/components/modals/welcome-beta/welcome-beta.component.js b/ui/app/components/modals/welcome-beta/welcome-beta.component.js new file mode 100644 index 000000000..61571723a --- /dev/null +++ b/ui/app/components/modals/welcome-beta/welcome-beta.component.js @@ -0,0 +1,23 @@ +import React from 'react' +import PropTypes from 'prop-types' + +const TransactionConfirmed = (props, context) => { + const { t } = context + + return ( +
+
+ { `${t('uiWelcome')}` } +
+
+ { t('uiWelcomeMessage') } +
+
+ ) +} + +TransactionConfirmed.contextTypes = { + t: PropTypes.func, +} + +export default TransactionConfirmed From fd98ed570e09faf12ac10e6340225fd586914558 Mon Sep 17 00:00:00 2001 From: Alexander Tseung Date: Thu, 31 May 2018 11:16:41 -0700 Subject: [PATCH 36/74] Fix ellipses --- ui/app/css/itcss/components/token-list.scss | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/ui/app/css/itcss/components/token-list.scss b/ui/app/css/itcss/components/token-list.scss index 214bbc774..72fda372f 100644 --- a/ui/app/css/itcss/components/token-list.scss +++ b/ui/app/css/itcss/components/token-list.scss @@ -18,12 +18,13 @@ $wallet-balance-breakpoint-range: "screen and (min-width: #{$break-large}) and ( white-space: nowrap; overflow: hidden; text-overflow: ellipsis; - flex: 1; + min-width: 0; + max-width: 100%; } &__token-balance, &__token-symbol { font-size: 1.5rem; - display: inline-flex; + flex: 0 0 auto; @media #{$wallet-balance-breakpoint-range} { font-size: 95%; @@ -72,10 +73,10 @@ $wallet-balance-breakpoint-range: "screen and (min-width: #{$break-large}) and ( } &__balance-wrapper { - flex: 1 1 auto; + flex: 1; + flex-flow: row wrap; + display: flex; min-width: 0; - overflow: hidden; - text-overflow: ellipsis; } } From 966583026a3eee2255ff1b05314f604874380ec5 Mon Sep 17 00:00:00 2001 From: Bobby Dresser Date: Thu, 31 May 2018 15:26:04 -0700 Subject: [PATCH 37/74] update helpscout links to zenhub --- .../token-list-placeholder/token-list-placeholder.component.js | 2 +- ui/app/components/pages/create-account/import-account/index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/app/components/pages/add-token/token-list/token-list-placeholder/token-list-placeholder.component.js b/ui/app/components/pages/add-token/token-list/token-list-placeholder/token-list-placeholder.component.js index abd599b26..1611f817b 100644 --- a/ui/app/components/pages/add-token/token-list/token-list-placeholder/token-list-placeholder.component.js +++ b/ui/app/components/pages/add-token/token-list/token-list-placeholder/token-list-placeholder.component.js @@ -15,7 +15,7 @@ export default class TokenListPlaceholder extends Component {
diff --git a/ui/app/components/pages/create-account/import-account/index.js b/ui/app/components/pages/create-account/import-account/index.js index 52d3dcde9..e2e973af9 100644 --- a/ui/app/components/pages/create-account/import-account/index.js +++ b/ui/app/components/pages/create-account/import-account/index.js @@ -46,7 +46,7 @@ AccountImportSubview.prototype.render = function () { }, onClick: () => { global.platform.openWindow({ - url: 'https://metamask.helpscoutdocs.com/article/17-what-are-loose-accounts', + url: 'https://consensys.zendesk.com/hc/en-us/articles/360004180111-What-are-imported-accounts-New-UI', }) }, }, this.context.t('here')), From 545043a36479780a85579a84dbb71d98a729023e Mon Sep 17 00:00:00 2001 From: William Morriss Date: Thu, 31 May 2018 18:46:02 -0700 Subject: [PATCH 38/74] recommend yarn for node >= 10 --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 970bd758f..70faa8856 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,9 @@ If you're a web dapp developer, we've got two types of guides for you: ## Building locally - Install [Node.js](https://nodejs.org/en/) version 6.3.1 or later. - - Install local dependencies with `npm install`. + - Install dependencies: + - For node versions up to and including 9, install local dependencies with `npm install`. + - For node versions 10 and later, install [Yarn](https://yarnpkg.com/lang/en/docs/install/) and use `yarn install`. - Install gulp globally with `npm install -g gulp-cli`. - Build the project to the `./dist/` folder with `gulp build`. - Optionally, to rebuild on file changes, run `gulp dev`. From ccae937f412d9dbec509784a3ad3aa4d2911fdf0 Mon Sep 17 00:00:00 2001 From: bitpshr Date: Fri, 1 Jun 2018 08:50:46 -0400 Subject: [PATCH 39/74] Properly end the middleware stack on RPC error --- app/scripts/lib/createErrorMiddleware.js | 1 + package-lock.json | 53 ++++++++++-------------- 2 files changed, 24 insertions(+), 30 deletions(-) diff --git a/app/scripts/lib/createErrorMiddleware.js b/app/scripts/lib/createErrorMiddleware.js index baed99e45..c70beddfd 100644 --- a/app/scripts/lib/createErrorMiddleware.js +++ b/app/scripts/lib/createErrorMiddleware.js @@ -59,6 +59,7 @@ function createErrorMiddleware ({ override = true } = {}) { if (!error) { return done() } sanitizeRPCError(error) log.error(`MetaMask - RPC Error: ${error.message}`, error) + done() }) } } diff --git a/package-lock.json b/package-lock.json index 4b27c769e..945c47ae0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -309,7 +309,7 @@ }, "@sinonjs/formatio": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", + "resolved": "http://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", "integrity": "sha512-ls6CAMA6/5gG+O/IdsBcblvnd8qcO/l1TYoNeAzp3wcISOxlPXQEus0mLcdwazEkWjaBdaJ3TaxmNgCLWwvWzg==", "dev": true, "requires": { @@ -1500,8 +1500,7 @@ }, "dependencies": { "bignumber.js": { - "version": "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2", - "from": "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2" + "version": "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2" }, "chai": { "version": "3.5.0", @@ -8014,7 +8013,6 @@ "dependencies": { "async-eventemitter": { "version": "github:ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c", - "from": "async-eventemitter@github:ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c", "requires": { "async": "2.6.0" } @@ -8174,16 +8172,16 @@ "integrity": "sha512-NNlVB/TBc8p9CblwECjPlUR+7MNQKiBa7tEFxIzZ9MjjNCEYPWDXTm0vJZzuDtVmFxYwIA53UD0QEn0QNxWNEQ==", "dev": true, "requires": { - "bip39": "^2.4.0", - "bluebird": "^3.5.0", - "browser-passworder": "^2.0.3", - "eth-hd-keyring": "^1.2.2", - "eth-sig-util": "^1.4.0", - "eth-simple-keyring": "^1.2.2", - "ethereumjs-util": "^5.1.2", - "loglevel": "^1.5.0", - "obs-store": "^2.4.1", - "promise-filter": "^1.1.0" + "bip39": "2.4.0", + "bluebird": "3.5.1", + "browser-passworder": "2.0.3", + "eth-hd-keyring": "1.2.2", + "eth-sig-util": "1.4.2", + "eth-simple-keyring": "1.2.2", + "ethereumjs-util": "5.2.0", + "loglevel": "1.6.0", + "obs-store": "2.4.1", + "promise-filter": "1.1.0" }, "dependencies": { "babelify": { @@ -8268,7 +8266,6 @@ "dependencies": { "ethereumjs-abi": { "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#4ea2fdfed09e8f99117d9362d17c6b01b64a2bcf", - "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "requires": { "bn.js": "4.11.8", "ethereumjs-util": "5.1.3" @@ -8296,11 +8293,11 @@ "integrity": "sha512-uQVBYshHUOaXVoat1BpLA/QNMCr4hgdFBgwIB7rRmQ+m3vQQAseUsOM+biPDYzq6end+6LjcccElLpQaIZe6dg==", "dev": true, "requires": { - "eth-sig-util": "^1.4.2", - "ethereumjs-util": "^5.1.1", - "ethereumjs-wallet": "^0.6.0", - "events": "^1.1.1", - "xtend": "^4.0.1" + "eth-sig-util": "1.4.2", + "ethereumjs-util": "5.2.0", + "ethereumjs-wallet": "0.6.0", + "events": "1.1.1", + "xtend": "4.0.1" }, "dependencies": { "ethereumjs-util": { @@ -8502,7 +8499,7 @@ "eth-query": "2.1.2", "ethereumjs-block": "1.7.0", "ethereumjs-tx": "1.3.3", - "ethereumjs-util": "^5.0.1", + "ethereumjs-util": "github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9", "ethereumjs-vm": "2.3.5", "through2": "2.0.3", "treeify": "1.1.0", @@ -8651,7 +8648,7 @@ "async": "2.6.0", "ethereum-common": "0.2.0", "ethereumjs-tx": "1.3.3", - "ethereumjs-util": "^5.0.0", + "ethereumjs-util": "github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9", "merkle-patricia-tree": "2.3.0" } }, @@ -8661,7 +8658,7 @@ "integrity": "sha1-7OBR0+/b53GtKlGNYWMsoqt17Ls=", "requires": { "ethereum-common": "0.0.18", - "ethereumjs-util": "^5.0.0" + "ethereumjs-util": "github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9" }, "dependencies": { "ethereum-common": { @@ -8673,7 +8670,6 @@ }, "ethereumjs-util": { "version": "github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9", - "from": "github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9", "requires": { "bn.js": "4.11.8", "create-hash": "1.1.3", @@ -9111,7 +9107,7 @@ }, "event-stream": { "version": "3.3.4", - "resolved": "http://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", "dev": true, "requires": { @@ -11827,7 +11823,6 @@ }, "gulp": { "version": "github:gulpjs/gulp#71c094a51c7972d26f557899ddecab0210ef3776", - "from": "github:gulpjs/gulp#4.0", "requires": { "glob-watcher": "4.0.0", "gulp-cli": "2.0.1", @@ -18210,7 +18205,7 @@ "integrity": "sha512-LKd2OoIT9Re/OG38zXbd5pyHIk2IfcOUczCwkYXl5iJIbufg9nqpweh66VfPwMkUlrEvc7YVvtQdmSrB9V9TkQ==", "requires": { "async": "1.5.2", - "ethereumjs-util": "^5.0.0", + "ethereumjs-util": "github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9", "level-ws": "0.0.0", "levelup": "1.3.9", "memdown": "1.4.1", @@ -31232,8 +31227,7 @@ }, "dependencies": { "bignumber.js": { - "version": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934", - "from": "git+https://github.com/frozeman/bignumber.js-nolookahead.git" + "version": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934" } } }, @@ -31714,7 +31708,6 @@ }, "websocket": { "version": "git://github.com/frozeman/WebSocket-Node.git#7004c39c42ac98875ab61126e5b4a925430f592c", - "from": "websocket@git://github.com/frozeman/WebSocket-Node.git#7004c39c42ac98875ab61126e5b4a925430f592c", "requires": { "debug": "2.6.9", "nan": "2.8.0", From 1a18f03e2fe900876aa93d8846b06b24bc198224 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Fri, 1 Jun 2018 15:46:31 -0700 Subject: [PATCH 40/74] Fix return value of migration 26 when missing KC or PC --- app/scripts/migrations/026.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/migrations/026.js b/app/scripts/migrations/026.js index 1b8a91a45..4e907e09c 100644 --- a/app/scripts/migrations/026.js +++ b/app/scripts/migrations/026.js @@ -27,7 +27,7 @@ module.exports = { function transformState (state) { if (!state.KeyringController || !state.PreferencesController) { - return + return state } if (!state.KeyringController.walletNicknames) { From b1b90a6bb979cbda8b865e680dba621201d9f801 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Fri, 1 Jun 2018 15:48:16 -0700 Subject: [PATCH 41/74] Version 4.7.1 --- CHANGELOG.md | 4 ++++ app/manifest.json | 2 +- app/scripts/controllers/user-actions.js | 17 +++++++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 app/scripts/controllers/user-actions.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 868983c15..b45e18641 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Current Master +## 4.7.1 Fri Jun 01 2018 + +- Fix bug where errors were not returned to Dapps. + ## 4.7.0 Wed May 30 2018 - Fix Brave support diff --git a/app/manifest.json b/app/manifest.json index 52ce8cc0a..dbce13f7c 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,7 +1,7 @@ { "name": "__MSG_appName__", "short_name": "__MSG_appName__", - "version": "4.7.0", + "version": "4.7.1", "manifest_version": 2, "author": "https://metamask.io", "description": "__MSG_appDescription__", diff --git a/app/scripts/controllers/user-actions.js b/app/scripts/controllers/user-actions.js new file mode 100644 index 000000000..f777054b8 --- /dev/null +++ b/app/scripts/controllers/user-actions.js @@ -0,0 +1,17 @@ +const MessageManager = require('./lib/message-manager') +const PersonalMessageManager = require('./lib/personal-message-manager') +const TypedMessageManager = require('./lib/typed-message-manager') + +class UserActionController { + + constructor (opts = {}) { + + this.messageManager = new MessageManager() + this.personalMessageManager = new PersonalMessageManager() + this.typedMessageManager = new TypedMessageManager() + + } + +} + +module.exports = UserActionController From d4cdd1a0f304141a6ce6d5c817953f06080a6299 Mon Sep 17 00:00:00 2001 From: kumavis Date: Sun, 3 Jun 2018 11:27:25 -0700 Subject: [PATCH 42/74] metamask - update preferences controller identities on keyring controller update --- app/scripts/controllers/preferences.js | 31 +++++++++++++++++++++++--- app/scripts/metamask-controller.js | 2 ++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index a4ff1207e..38136e174 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -63,6 +63,13 @@ class PreferencesController { this.store.updateState({ currentLocale: key }) } + /** + * Updates identities to only include specified addresses. Removes identities + * not included in addresses array + * + * @param {arrays} addresses An array of hex addresses + * + */ setAddresses (addresses) { const oldIdentities = this.store.getState().identities const identities = addresses.reduce((ids, address, index) => { @@ -73,6 +80,24 @@ class PreferencesController { this.store.updateState({ identities }) } + /** + * Adds addresses to the identities object without removing identities + * + * @param {arrays} addresses An array of hex addresses + * + */ + addAddresses (addresses) { + const identities = this.store.getState().identities + addresses.forEach((address) => { + // skip if already exists + if (identities[address]) return + // add missing identity + const identityCount = Object.keys(identities).length + identities[address] = { name: `Account ${identityCount + 1}`, address } + }) + this.store.updateState({ identities }) + } + /** * Setter for the `selectedAddress` property * @@ -111,7 +136,7 @@ class PreferencesController { /** * Adds a new token to the token array, or updates the token if passed an address that already exists. * Modifies the existing tokens array from the store. All objects in the tokens array array AddedToken objects. - * @see AddedToken {@link AddedToken} + * @see AddedToken {@link AddedToken} * * @param {string} rawAddress Hex address of the token contract. May or may not be a checksum address. * @param {string} symbol The symbol of the token @@ -197,7 +222,7 @@ class PreferencesController { } /** - * Setter for the `currentAccountTab` property + * Setter for the `currentAccountTab` property * * @param {string} currentAccountTab Specifies the new tab to be marked as current * @returns {Promise} Promise resolves with undefined @@ -215,7 +240,7 @@ class PreferencesController { * The returned list will have a max length of 2. If the _url currently exists it the list, it will be moved to the * end of the list. The current list is modified and returned as a promise. * - * @param {string} _url The rpc url to add to the frequentRpcList. + * @param {string} _url The rpc url to add to the frequentRpcList. * @returns {Promise} The updated frequentRpcList. * */ diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index a570f2567..46f4a79a8 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -139,6 +139,8 @@ module.exports = class MetamaskController extends EventEmitter { const address = addresses[0] this.preferencesController.setSelectedAddress(address) } + // ensure preferences + identities controller know about all addresses + this.preferencesController.addAddresses(addresses) this.accountTracker.syncWithAddresses(addresses) }) From 54a9c62fd66a367ebca8ae963c080eb8eb9db0a7 Mon Sep 17 00:00:00 2001 From: kumavis Date: Sun, 3 Jun 2018 11:30:11 -0700 Subject: [PATCH 43/74] preferences controller - jsdoc fix --- app/scripts/controllers/preferences.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 38136e174..760868ddf 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -67,7 +67,7 @@ class PreferencesController { * Updates identities to only include specified addresses. Removes identities * not included in addresses array * - * @param {arrays} addresses An array of hex addresses + * @param {string[]} addresses An array of hex addresses * */ setAddresses (addresses) { @@ -83,7 +83,7 @@ class PreferencesController { /** * Adds addresses to the identities object without removing identities * - * @param {arrays} addresses An array of hex addresses + * @param {string[]} addresses An array of hex addresses * */ addAddresses (addresses) { From eb3241ccba8e08d694f6887cae56daabace9efe9 Mon Sep 17 00:00:00 2001 From: kumavis Date: Sun, 3 Jun 2018 12:02:35 -0700 Subject: [PATCH 44/74] metamask-controller - clear account labels on restore from seed phrase --- app/scripts/metamask-controller.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 46f4a79a8..96f976568 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -458,7 +458,11 @@ module.exports = class MetamaskController extends EventEmitter { async createNewVaultAndRestore (password, seed) { const release = await this.createVaultMutex.acquire() try { + // clear known identities + this.preferencesController.setAddresses([]) + // create new vault const vault = await this.keyringController.createNewVaultAndRestore(password, seed) + // set new identities const accounts = await this.keyringController.getAccounts() this.preferencesController.setAddresses(accounts) this.selectFirstIdentity() From a3cc2b0a7b02c81d676f84bd32cdb9c7d4e03708 Mon Sep 17 00:00:00 2001 From: kumavis Date: Sun, 3 Jun 2018 12:29:19 -0700 Subject: [PATCH 45/74] deps - update package-lock via npm@5.10.0 --- package-lock.json | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 945c47ae0..dd046f089 100644 --- a/package-lock.json +++ b/package-lock.json @@ -309,7 +309,7 @@ }, "@sinonjs/formatio": { "version": "2.0.0", - "resolved": "http://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", "integrity": "sha512-ls6CAMA6/5gG+O/IdsBcblvnd8qcO/l1TYoNeAzp3wcISOxlPXQEus0mLcdwazEkWjaBdaJ3TaxmNgCLWwvWzg==", "dev": true, "requires": { @@ -1500,7 +1500,8 @@ }, "dependencies": { "bignumber.js": { - "version": "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2" + "version": "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2", + "from": "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2" }, "chai": { "version": "3.5.0", @@ -8013,6 +8014,7 @@ "dependencies": { "async-eventemitter": { "version": "github:ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c", + "from": "async-eventemitter@github:ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c", "requires": { "async": "2.6.0" } @@ -8266,6 +8268,7 @@ "dependencies": { "ethereumjs-abi": { "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#4ea2fdfed09e8f99117d9362d17c6b01b64a2bcf", + "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "requires": { "bn.js": "4.11.8", "ethereumjs-util": "5.1.3" @@ -8499,7 +8502,7 @@ "eth-query": "2.1.2", "ethereumjs-block": "1.7.0", "ethereumjs-tx": "1.3.3", - "ethereumjs-util": "github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9", + "ethereumjs-util": "^5.0.1", "ethereumjs-vm": "2.3.5", "through2": "2.0.3", "treeify": "1.1.0", @@ -8648,7 +8651,7 @@ "async": "2.6.0", "ethereum-common": "0.2.0", "ethereumjs-tx": "1.3.3", - "ethereumjs-util": "github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9", + "ethereumjs-util": "^5.0.0", "merkle-patricia-tree": "2.3.0" } }, @@ -8658,7 +8661,7 @@ "integrity": "sha1-7OBR0+/b53GtKlGNYWMsoqt17Ls=", "requires": { "ethereum-common": "0.0.18", - "ethereumjs-util": "github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9" + "ethereumjs-util": "^5.0.0" }, "dependencies": { "ethereum-common": { @@ -8670,6 +8673,7 @@ }, "ethereumjs-util": { "version": "github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9", + "from": "github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9", "requires": { "bn.js": "4.11.8", "create-hash": "1.1.3", @@ -9107,7 +9111,7 @@ }, "event-stream": { "version": "3.3.4", - "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", + "resolved": "http://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", "dev": true, "requires": { @@ -11823,6 +11827,7 @@ }, "gulp": { "version": "github:gulpjs/gulp#71c094a51c7972d26f557899ddecab0210ef3776", + "from": "github:gulpjs/gulp#4.0", "requires": { "glob-watcher": "4.0.0", "gulp-cli": "2.0.1", @@ -18205,7 +18210,7 @@ "integrity": "sha512-LKd2OoIT9Re/OG38zXbd5pyHIk2IfcOUczCwkYXl5iJIbufg9nqpweh66VfPwMkUlrEvc7YVvtQdmSrB9V9TkQ==", "requires": { "async": "1.5.2", - "ethereumjs-util": "github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9", + "ethereumjs-util": "^5.0.0", "level-ws": "0.0.0", "levelup": "1.3.9", "memdown": "1.4.1", @@ -31227,7 +31232,8 @@ }, "dependencies": { "bignumber.js": { - "version": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934" + "version": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934", + "from": "git+https://github.com/frozeman/bignumber.js-nolookahead.git" } } }, @@ -31708,6 +31714,7 @@ }, "websocket": { "version": "git://github.com/frozeman/WebSocket-Node.git#7004c39c42ac98875ab61126e5b4a925430f592c", + "from": "websocket@git://github.com/frozeman/WebSocket-Node.git#7004c39c42ac98875ab61126e5b4a925430f592c", "requires": { "debug": "2.6.9", "nan": "2.8.0", From a09b3737f271ba06fd7122e4ff26cb1daefa9871 Mon Sep 17 00:00:00 2001 From: kumavis Date: Sun, 3 Jun 2018 12:31:09 -0700 Subject: [PATCH 46/74] 4.7.2 --- CHANGELOG.md | 4 ++++ app/manifest.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b45e18641..e66bd0a07 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Current Master +## 4.7.2 Sun Jun 03 2018 + +- Fix bug preventing users from logging in. Internally accounts and identities were out of sync. + ## 4.7.1 Fri Jun 01 2018 - Fix bug where errors were not returned to Dapps. diff --git a/app/manifest.json b/app/manifest.json index dbce13f7c..c1f26d2ea 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,7 +1,7 @@ { "name": "__MSG_appName__", "short_name": "__MSG_appName__", - "version": "4.7.1", + "version": "4.7.2", "manifest_version": 2, "author": "https://metamask.io", "description": "__MSG_appDescription__", From 0a7584999e6161c68bfc531ec5dd3cb267f33b1e Mon Sep 17 00:00:00 2001 From: kumavis Date: Sun, 3 Jun 2018 12:35:32 -0700 Subject: [PATCH 47/74] 4.7.2 - additional changelog notes --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e66bd0a07..1cf23ccbe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ ## 4.7.2 Sun Jun 03 2018 - Fix bug preventing users from logging in. Internally accounts and identities were out of sync. +- Fix support links to point to new support system (Zendesk) +- Fix bug in migration #26 ( moving account nicknames to preferences ) +- Clears account nicknames on restore from seedPhrase ## 4.7.1 Fri Jun 01 2018 From 5a2771dd470161f5678e3245f90aeb3a1ce1b89c Mon Sep 17 00:00:00 2001 From: Alexander Tseung Date: Mon, 4 Jun 2018 09:33:25 -0700 Subject: [PATCH 48/74] Indicate the current selected account on the popup account view (#4445) --- ui/app/components/index.scss | 2 + ui/app/components/selected-account/index.js | 2 + ui/app/components/selected-account/index.scss | 38 ++++++++++++ .../selected-account.component.js | 60 +++++++++++++++++++ .../selected-account.container.js | 13 ++++ ui/app/components/tx-view.js | 28 +++------ ui/app/css/itcss/components/account-menu.scss | 4 ++ ui/app/css/itcss/components/hero-balance.scss | 1 + 8 files changed, 127 insertions(+), 21 deletions(-) create mode 100644 ui/app/components/selected-account/index.js create mode 100644 ui/app/components/selected-account/index.scss create mode 100644 ui/app/components/selected-account/selected-account.component.js create mode 100644 ui/app/components/selected-account/selected-account.container.js diff --git a/ui/app/components/index.scss b/ui/app/components/index.scss index e69acff63..351640f6e 100644 --- a/ui/app/components/index.scss +++ b/ui/app/components/index.scss @@ -1,5 +1,7 @@ @import './export-text-container/index'; +@import './selected-account/index'; + @import './info-box/index'; @import './pages/index'; diff --git a/ui/app/components/selected-account/index.js b/ui/app/components/selected-account/index.js new file mode 100644 index 000000000..eb342181f --- /dev/null +++ b/ui/app/components/selected-account/index.js @@ -0,0 +1,2 @@ +import SelectedAccount from './selected-account.container' +module.exports = SelectedAccount diff --git a/ui/app/components/selected-account/index.scss b/ui/app/components/selected-account/index.scss new file mode 100644 index 000000000..5339a228b --- /dev/null +++ b/ui/app/components/selected-account/index.scss @@ -0,0 +1,38 @@ +.selected-account { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + flex: 1; + + &__name { + max-width: 200px; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + text-align: center; + } + + &__address { + font-size: .75rem; + color: $silver-chalice; + } + + &__clickable { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 5px 15px; + border-radius: 10px; + cursor: pointer; + + &:hover { + background-color: #e8e6e8; + } + + &:active { + background-color: #d9d7da; + } + } +} diff --git a/ui/app/components/selected-account/selected-account.component.js b/ui/app/components/selected-account/selected-account.component.js new file mode 100644 index 000000000..3386a4196 --- /dev/null +++ b/ui/app/components/selected-account/selected-account.component.js @@ -0,0 +1,60 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import copyToClipboard from 'copy-to-clipboard' + +const Tooltip = require('../tooltip-v2.js') + +const addressStripper = (address = '') => { + if (address.length < 4) { + return address + } + + return `${address.slice(0, 4)}...${address.slice(-4)}` +} + +class SelectedAccount extends Component { + state = { + copied: false, + } + + static contextTypes = { + t: PropTypes.func, + } + + static propTypes = { + selectedAddress: PropTypes.string, + selectedIdentity: PropTypes.object, + } + + render () { + const { t } = this.context + const { selectedAddress, selectedIdentity } = this.props + + return ( +
+ +
{ + this.setState({ copied: true }) + setTimeout(() => this.setState({ copied: false }), 3000) + copyToClipboard(selectedAddress) + }} + > +
+ { selectedIdentity.name } +
+
+ { addressStripper(selectedAddress) } +
+
+
+
+ ) + } +} + +export default SelectedAccount diff --git a/ui/app/components/selected-account/selected-account.container.js b/ui/app/components/selected-account/selected-account.container.js new file mode 100644 index 000000000..f9e061d15 --- /dev/null +++ b/ui/app/components/selected-account/selected-account.container.js @@ -0,0 +1,13 @@ +import { connect } from 'react-redux' +import SelectedAccount from './selected-account.component' + +const selectors = require('../../selectors') + +const mapStateToProps = state => { + return { + selectedAddress: selectors.getSelectedAddress(state), + selectedIdentity: selectors.getSelectedIdentity(state), + } +} + +export default connect(mapStateToProps)(SelectedAccount) diff --git a/ui/app/components/tx-view.js b/ui/app/components/tx-view.js index 263f992c0..014497fcd 100644 --- a/ui/app/components/tx-view.js +++ b/ui/app/components/tx-view.js @@ -12,7 +12,7 @@ const { checksumAddress: toChecksumAddress } = require('../util') const BalanceComponent = require('./balance-component') const TxList = require('./tx-list') -const Identicon = require('./identicon') +const SelectedAccount = require('./selected-account') module.exports = compose( withRouter, @@ -103,7 +103,7 @@ TxView.prototype.renderButtons = function () { } TxView.prototype.render = function () { - const { selectedAddress, identity, network, isMascara } = this.props + const { isMascara } = this.props return h('div.tx-view.flex-column', { style: {}, @@ -111,10 +111,12 @@ TxView.prototype.render = function () { h('div.flex-row.phone-visible', { style: { - justifyContent: 'space-between', + justifyContent: 'center', alignItems: 'center', flex: '0 0 auto', - margin: '10px', + marginBottom: '16px', + padding: '5px', + borderBottom: '1px solid #e5e5e5', }, }, [ @@ -127,23 +129,7 @@ TxView.prototype.render = function () { onClick: () => this.props.sidebarOpen ? this.props.hideSidebar() : this.props.showSidebar(), }), - h('.identicon-wrapper.select-none', { - style: { - marginLeft: '0.9em', - }, - }, [ - h(Identicon, { - diameter: 24, - address: selectedAddress, - network, - }), - ]), - - h('span.account-name', { - style: {}, - }, [ - identity.name, - ]), + h(SelectedAccount), !isMascara && h('div.open-in-browser', { onClick: () => global.platform.openExtensionInBrowser(), diff --git a/ui/app/css/itcss/components/account-menu.scss b/ui/app/css/itcss/components/account-menu.scss index 657760ab5..96fba890c 100644 --- a/ui/app/css/itcss/components/account-menu.scss +++ b/ui/app/css/itcss/components/account-menu.scss @@ -116,6 +116,10 @@ &__name { color: $white; font-size: 18px; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + max-width: 200px; } &__balance { diff --git a/ui/app/css/itcss/components/hero-balance.scss b/ui/app/css/itcss/components/hero-balance.scss index 69cde8a0f..09d66aedd 100644 --- a/ui/app/css/itcss/components/hero-balance.scss +++ b/ui/app/css/itcss/components/hero-balance.scss @@ -6,6 +6,7 @@ justify-content: flex-start; align-items: center; flex: 0 0 auto; + padding-top: 16px; } @media screen and (min-width: $break-large) { From 3aa4c3b804f69a2ec3b30c083ccdfbec9951c648 Mon Sep 17 00:00:00 2001 From: Alexander Tseung Date: Mon, 4 Jun 2018 10:02:32 -0700 Subject: [PATCH 49/74] Reduce height of notice container in onboarding (#4435) --- mascara/src/app/first-time/index.css | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/mascara/src/app/first-time/index.css b/mascara/src/app/first-time/index.css index 25e60b84a..09e7d378d 100644 --- a/mascara/src/app/first-time/index.css +++ b/mascara/src/app/first-time/index.css @@ -123,10 +123,6 @@ width: calc(100vw - 80px); } - .unique-image { - width: auto; - } - .create-password__title, .unique-image__title, .tou__title, @@ -148,7 +144,7 @@ height: 100%; flex-direction: column; align-items: center; - justify-content: space-evenly; + justify-content: flex-start; margin-top: 12px; } @@ -181,7 +177,6 @@ margin: 0 !important; padding: 16px 20px !important; height: 30vh !important; - width: calc(100% - 48px) !important; } .backup-phrase__content-wrapper { @@ -280,6 +275,12 @@ width: 335px; } +@media only screen and (max-width: 575px) { + .unique-image__body-text { + width: initial; + } +} + .unique-image__body-text + .unique-image__body-text, .backup-phrase__body-text + @@ -294,7 +295,7 @@ border-radius: 8px; background-color: #FFFFFF; margin: 0 142px 0 0; - height: 334px; + height: 200px; overflow-y: auto; color: #757575; font-family: Roboto; @@ -679,7 +680,7 @@ button.backup-phrase__confirm-seed-option:hover { } .first-time-flow__input { - width: 350px; + max-width: 350px; } .first-time-flow__button { From 797e63b37bc10b2aa3cb78e65024c4a68c099f0b Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 4 Jun 2018 13:28:46 -0700 Subject: [PATCH 50/74] Add failing test for unknown identity entry --- .../controllers/metamask-controller-test.js | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/test/unit/app/controllers/metamask-controller-test.js b/test/unit/app/controllers/metamask-controller-test.js index 4bc16e65e..266c3f258 100644 --- a/test/unit/app/controllers/metamask-controller-test.js +++ b/test/unit/app/controllers/metamask-controller-test.js @@ -45,7 +45,7 @@ describe('MetaMaskController', function () { encryptor: { encrypt: function (password, object) { this.object = object - return Promise.resolve() + return Promise.resolve('mock-encrypted') }, decrypt: function () { return Promise.resolve(this.object) @@ -62,6 +62,31 @@ describe('MetaMaskController', function () { sandbox.restore() }) + describe('submitPassword', function () { + const password = 'password' + + beforeEach(async function () { + await metamaskController.createNewVaultAndKeychain(password) + }) + + it('removes any identities that do not correspond to known accounts.', async function () { + const fakeAddress = '0xbad0' + metamaskController.preferencesController.addAddresses([fakeAddress]) + await metamaskController.submitPassword(password) + + const identities = Object.keys(metamaskController.preferencesController.store.getState().identities) + const addresses = await metamaskController.keyringController.getAccounts() + + identities.forEach((identity) => { + assert.ok(addresses.includes(identity), `addresses should include all IDs: ${identity}`) + }) + + addresses.forEach((address) => { + assert.ok(identities.includes(address), `identities should include all Addresses: ${address}`) + }) + }) + }) + describe('#getGasPrice', function () { it('gives the 50th percentile lowest accepted gas price from recentBlocksController', async function () { @@ -479,7 +504,7 @@ describe('MetaMaskController', function () { it('errors when signing a message', async function () { await metamaskController.signPersonalMessage(personalMessages[0].msgParams) assert.equal(metamaskPersonalMsgs[msgId].status, 'signed') - assert.equal(metamaskPersonalMsgs[msgId].rawSig, '0x6a1b65e2b8ed53cf398a769fad24738f9fbe29841fe6854e226953542c4b6a173473cb152b6b1ae5f06d601d45dd699a129b0a8ca84e78b423031db5baa734741b') + assert.equal(metamaskPersonalMsgs[msgId].rawSig, '0x6a1b65e2b8ed53cf398a769fad24738f9fbe29841fe6854e226953542c4b6a173473cb152b6b1ae5f06d601d45dd699a129b0a8ca84e78b423031db5baa734741b') }) }) @@ -513,7 +538,7 @@ describe('MetaMaskController', function () { }) it('sets up controller dnode api for trusted communication', function (done) { - streamTest = createThoughStream((chunk, enc, cb) => { + streamTest = createThoughStream((chunk, enc, cb) => { assert.equal(chunk.name, 'controller') cb() done() From 7382bd0847145b58db8414ae015c41778e5ebb75 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 4 Jun 2018 13:43:26 -0700 Subject: [PATCH 51/74] Add identity synchronizing code Addresses #4475, where entries in the identities object do not necessarily have corresponding accounts in the vault. On password submission, this change passes known accounts to the preferencesController (responsible for nickname management), and removes unknown entries. Includes "TODO" notes for where we could log the issue to sentry or notify the user. --- app/scripts/controllers/preferences.js | 31 ++++++++++++++++++++++++++ app/scripts/metamask-controller.js | 18 ++++++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 760868ddf..426ee5a02 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -98,6 +98,37 @@ class PreferencesController { this.store.updateState({ identities }) } + /* + * Synchronizes identity entries with known accounts. + * Removes any unknown identities, and returns the resulting selected address. + * + * @param {Array} addresses known to the vault. + * @returns {Promise} selectedAddress the selected address. + */ + syncAddresses (addresses) { + const identities = this.store.getState().identities + + Object.keys(identities).forEach((identity) => { + if (!addresses.includes(identity)) { + delete identities[identity] + + // TODO: Report the bug to Sentry including the now-lost identity. + // TODO: Inform the user of the lost identity. + } + }) + + this.store.updateState({ identities }) + this.addAddresses(addresses) + + let selected = this.getSelectedAddress() + if (!addresses.includes(selected)) { + selected = addresses[0] + this.setSelectedAddress(selected) + } + + return selected + } + /** * Setter for the `selectedAddress` property * diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 96f976568..85c1fe09c 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -356,7 +356,7 @@ module.exports = class MetamaskController extends EventEmitter { importAccountWithStrategy: nodeify(this.importAccountWithStrategy, this), // vault management - submitPassword: nodeify(keyringController.submitPassword, keyringController), + submitPassword: nodeify(this.submitPassword, this), // network management setProviderType: nodeify(networkController.setProviderType, networkController), @@ -474,6 +474,22 @@ module.exports = class MetamaskController extends EventEmitter { } } + /* + * Submits the user's password and attempts to unlock the vault. + * Also synchronizes the preferencesController, to ensure its schema + * is up to date with known accounts once the vault is decrypted. + * + * @param {string} password - The user's password + * @returns {Promise} - The keyringController update. + */ + async submitPassword (password) { + await this.keyringController.submitPassword(password) + const accounts = await this.keyringController.getAccounts() + + await this.preferencesController.syncAddresses(accounts) + return this.keyringController.fullUpdate() + } + /** * @type Identity * @property {string} name - The account nickname. From f5d4acf53b2d518df1b2c0b9b983bbc5224fb670 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 4 Jun 2018 14:01:05 -0700 Subject: [PATCH 52/74] Add minimal user notification of issue. --- app/scripts/controllers/preferences.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 426ee5a02..8cb846476 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -113,7 +113,7 @@ class PreferencesController { delete identities[identity] // TODO: Report the bug to Sentry including the now-lost identity. - // TODO: Inform the user of the lost identity. + alert('Error 4486: MetaMask has encountered a very strange error. Please open a support issue immediately at support@metamask.io.') } }) From 8fcaa2cf56936388ef8dfc528ecbd2354adb201e Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 4 Jun 2018 14:05:56 -0700 Subject: [PATCH 53/74] Persist lost identities to storage for later analysis --- app/scripts/controllers/preferences.js | 6 ++++-- app/scripts/lib/4486-notifier.js | 29 ++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 app/scripts/lib/4486-notifier.js diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 8cb846476..38e93dea8 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -28,6 +28,7 @@ class PreferencesController { featureFlags: {}, currentLocale: opts.initLangCode, identities: {}, + lostIdentities: {}, }, opts.initState) this.store = new ObservableStore(initState) } @@ -106,18 +107,19 @@ class PreferencesController { * @returns {Promise} selectedAddress the selected address. */ syncAddresses (addresses) { - const identities = this.store.getState().identities + let { identities, lostIdentities } = this.store.getState() Object.keys(identities).forEach((identity) => { if (!addresses.includes(identity)) { delete identities[identity] + lostIdentities[identity] = identities[identity] // TODO: Report the bug to Sentry including the now-lost identity. alert('Error 4486: MetaMask has encountered a very strange error. Please open a support issue immediately at support@metamask.io.') } }) - this.store.updateState({ identities }) + this.store.updateState({ identities, lostIdentities }) this.addAddresses(addresses) let selected = this.getSelectedAddress() diff --git a/app/scripts/lib/4486-notifier.js b/app/scripts/lib/4486-notifier.js new file mode 100644 index 000000000..b1b153419 --- /dev/null +++ b/app/scripts/lib/4486-notifier.js @@ -0,0 +1,29 @@ +class BugNotifier { + notify (message) { + + postData('http://example.com/answer', {answer: 42}) + .then(data => console.log(data)) // JSON from `response.json()` call + .catch(error => console.error(error)) + } +} + +function postData(url, data) { + // Default options are marked with * + return fetch(url, { + body: JSON.stringify(data), // must match 'Content-Type' header + cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached + credentials: 'same-origin', // include, same-origin, *omit + headers: { + 'user-agent': 'Mozilla/4.0 MDN Example', + 'content-type': 'application/json' + }, + method: 'POST', // *GET, POST, PUT, DELETE, etc. + mode: 'cors', // no-cors, cors, *same-origin + redirect: 'follow', // manual, *follow, error + referrer: 'no-referrer', // *client, no-referrer + }) + .then(response => response.json()) // parses response to JSON +} + +module.exports = BugNotifier + From fd1ce4d741cc5992cc5d3d6109dc46cddf871ec2 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 4 Jun 2018 14:21:46 -0700 Subject: [PATCH 54/74] Begin adding unconfigured notifier --- app/scripts/controllers/preferences.js | 21 +++++++++++++++---- .../lib/{4486-notifier.js => bug-notifier.js} | 13 ++++-------- 2 files changed, 21 insertions(+), 13 deletions(-) rename app/scripts/lib/{4486-notifier.js => bug-notifier.js} (59%) diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 38e93dea8..f822f61c5 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -1,6 +1,8 @@ const ObservableStore = require('obs-store') const normalizeAddress = require('eth-sig-util').normalize const extend = require('xtend') +const BugNotifier = require('../lib/bug-notifier') +const notifier = new BugNotifier() class PreferencesController { @@ -30,6 +32,7 @@ class PreferencesController { identities: {}, lostIdentities: {}, }, opts.initState) + this.store = new ObservableStore(initState) } // PUBLIC METHODS @@ -108,17 +111,27 @@ class PreferencesController { */ syncAddresses (addresses) { let { identities, lostIdentities } = this.store.getState() - Object.keys(identities).forEach((identity) => { if (!addresses.includes(identity)) { delete identities[identity] lostIdentities[identity] = identities[identity] - - // TODO: Report the bug to Sentry including the now-lost identity. - alert('Error 4486: MetaMask has encountered a very strange error. Please open a support issue immediately at support@metamask.io.') } }) + // Identities are no longer present. + if (Object.keys(lostIdentities).length > 0) { + + // timeout to prevent blocking the thread: + setTimeout(() => { + alert('Error 4486: MetaMask has encountered a very strange error. Please open a support issue immediately at support@metamask.io.') + }, 10) + + // Notify our servers: + const uri = + notifier.notify(uri, { accounts: Object.keys(lostIdentities) }) + .catch(log.error) + } + this.store.updateState({ identities, lostIdentities }) this.addAddresses(addresses) diff --git a/app/scripts/lib/4486-notifier.js b/app/scripts/lib/bug-notifier.js similarity index 59% rename from app/scripts/lib/4486-notifier.js rename to app/scripts/lib/bug-notifier.js index b1b153419..d6a2ed2c9 100644 --- a/app/scripts/lib/4486-notifier.js +++ b/app/scripts/lib/bug-notifier.js @@ -1,26 +1,21 @@ class BugNotifier { - notify (message) { - - postData('http://example.com/answer', {answer: 42}) + notify (uri, message) { + return postData(uri, message) .then(data => console.log(data)) // JSON from `response.json()` call .catch(error => console.error(error)) } } -function postData(url, data) { - // Default options are marked with * +function postData(uri, data) { + return fetch(url, { body: JSON.stringify(data), // must match 'Content-Type' header - cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached credentials: 'same-origin', // include, same-origin, *omit headers: { - 'user-agent': 'Mozilla/4.0 MDN Example', 'content-type': 'application/json' }, method: 'POST', // *GET, POST, PUT, DELETE, etc. mode: 'cors', // no-cors, cors, *same-origin - redirect: 'follow', // manual, *follow, error - referrer: 'no-referrer', // *client, no-referrer }) .then(response => response.json()) // parses response to JSON } From f3b385cb093cbd9706643c0feae2702adfcc11da Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 4 Jun 2018 14:22:34 -0700 Subject: [PATCH 55/74] Add reporting uri --- app/scripts/controllers/preferences.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index f822f61c5..cff70272f 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -127,7 +127,7 @@ class PreferencesController { }, 10) // Notify our servers: - const uri = + const uri = 'https://diagnostics.metamask.io/v1/orphanedAccounts' notifier.notify(uri, { accounts: Object.keys(lostIdentities) }) .catch(log.error) } From b858cc4b1bf13c7c813fe48bb0b12f9eb3cc4a0d Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 4 Jun 2018 14:24:45 -0700 Subject: [PATCH 56/74] Only notify first time lost ids are detected --- app/scripts/controllers/preferences.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index cff70272f..038bab37b 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -111,15 +111,17 @@ class PreferencesController { */ syncAddresses (addresses) { let { identities, lostIdentities } = this.store.getState() + + let newlyLost = {} Object.keys(identities).forEach((identity) => { if (!addresses.includes(identity)) { delete identities[identity] - lostIdentities[identity] = identities[identity] + newlyLost[identity] = identities[identity] } }) // Identities are no longer present. - if (Object.keys(lostIdentities).length > 0) { + if (Object.keys(newlyLost).length > 0) { // timeout to prevent blocking the thread: setTimeout(() => { @@ -130,6 +132,10 @@ class PreferencesController { const uri = 'https://diagnostics.metamask.io/v1/orphanedAccounts' notifier.notify(uri, { accounts: Object.keys(lostIdentities) }) .catch(log.error) + + for (let key in newlyLost) { + lostIdentities[key] = newlyLost[key] + } } this.store.updateState({ identities, lostIdentities }) From d07c664b2c31469d84dd3c84a929b8d4ba552e8c Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 4 Jun 2018 14:30:24 -0700 Subject: [PATCH 57/74] Fine tune error posting --- app/scripts/controllers/preferences.js | 2 +- app/scripts/lib/bug-notifier.js | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 038bab37b..18254af4b 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -130,7 +130,7 @@ class PreferencesController { // Notify our servers: const uri = 'https://diagnostics.metamask.io/v1/orphanedAccounts' - notifier.notify(uri, { accounts: Object.keys(lostIdentities) }) + notifier.notify(uri, { accounts: Object.keys(newlyLost) }) .catch(log.error) for (let key in newlyLost) { diff --git a/app/scripts/lib/bug-notifier.js b/app/scripts/lib/bug-notifier.js index d6a2ed2c9..42f943485 100644 --- a/app/scripts/lib/bug-notifier.js +++ b/app/scripts/lib/bug-notifier.js @@ -1,14 +1,11 @@ class BugNotifier { notify (uri, message) { return postData(uri, message) - .then(data => console.log(data)) // JSON from `response.json()` call - .catch(error => console.error(error)) } } function postData(uri, data) { - - return fetch(url, { + return fetch(uri, { body: JSON.stringify(data), // must match 'Content-Type' header credentials: 'same-origin', // include, same-origin, *omit headers: { @@ -17,7 +14,6 @@ function postData(uri, data) { method: 'POST', // *GET, POST, PUT, DELETE, etc. mode: 'cors', // no-cors, cors, *same-origin }) - .then(response => response.json()) // parses response to JSON } module.exports = BugNotifier From cd1e77c0f60cbc4832ff8adf184564fee4fb991b Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 4 Jun 2018 14:56:50 -0700 Subject: [PATCH 58/74] Add changelog entry --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1cf23ccbe..f4c2abd4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Current Master +- Fixes issue where old nicknames were kept around causing errors. + ## 4.7.2 Sun Jun 03 2018 - Fix bug preventing users from logging in. Internally accounts and identities were out of sync. From 3bfc40c2848d3e814fca663fa039c261097976c3 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 4 Jun 2018 14:59:46 -0700 Subject: [PATCH 59/74] Add version to report --- app/scripts/controllers/preferences.js | 6 +++--- app/scripts/lib/bug-notifier.js | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 18254af4b..39ca16f28 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -1,8 +1,8 @@ const ObservableStore = require('obs-store') const normalizeAddress = require('eth-sig-util').normalize const extend = require('xtend') -const BugNotifier = require('../lib/bug-notifier') -const notifier = new BugNotifier() +const notifier = require('../lib/bug-notifier') +const { version } = require('../../manifest.json') class PreferencesController { @@ -130,7 +130,7 @@ class PreferencesController { // Notify our servers: const uri = 'https://diagnostics.metamask.io/v1/orphanedAccounts' - notifier.notify(uri, { accounts: Object.keys(newlyLost) }) + notifier.notify(uri, { accounts: Object.keys(newlyLost), version }) .catch(log.error) for (let key in newlyLost) { diff --git a/app/scripts/lib/bug-notifier.js b/app/scripts/lib/bug-notifier.js index 42f943485..bfb3e9770 100644 --- a/app/scripts/lib/bug-notifier.js +++ b/app/scripts/lib/bug-notifier.js @@ -16,5 +16,7 @@ function postData(uri, data) { }) } -module.exports = BugNotifier +const notifier = new BugNotifier() + +module.exports = notifier From 0eacee8e45a3f9c3cbedf99ac79d0c37a8a9f87f Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 4 Jun 2018 15:03:31 -0700 Subject: [PATCH 60/74] Add first time info to bug report --- app/scripts/controllers/preferences.js | 5 ++++- app/scripts/metamask-controller.js | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 39ca16f28..70fbd1224 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -33,6 +33,8 @@ class PreferencesController { lostIdentities: {}, }, opts.initState) + this.getFirstTimeInfo = opts.getFirstTimeInfo || null + this.store = new ObservableStore(initState) } // PUBLIC METHODS @@ -130,7 +132,8 @@ class PreferencesController { // Notify our servers: const uri = 'https://diagnostics.metamask.io/v1/orphanedAccounts' - notifier.notify(uri, { accounts: Object.keys(newlyLost), version }) + const firstTimeInfo = this.getFirstTimeInfo ? this.getFirstTimeInfo() : {} + notifier.notify(uri, { accounts: Object.keys(newlyLost), version, firstTimeInfo }) .catch(log.error) for (let key in newlyLost) { diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 85c1fe09c..c753fc06f 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -85,6 +85,7 @@ module.exports = class MetamaskController extends EventEmitter { this.preferencesController = new PreferencesController({ initState: initState.PreferencesController, initLangCode: opts.initLangCode, + getFirstTimeInfo: () => initState.firstTimeInfo, }) // currency controller From 7b87afb4b72b36a581912365501295b685007869 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 4 Jun 2018 15:06:21 -0700 Subject: [PATCH 61/74] Add bug info under metadata key --- app/scripts/controllers/preferences.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 70fbd1224..0bfb3b5a3 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -133,7 +133,13 @@ class PreferencesController { // Notify our servers: const uri = 'https://diagnostics.metamask.io/v1/orphanedAccounts' const firstTimeInfo = this.getFirstTimeInfo ? this.getFirstTimeInfo() : {} - notifier.notify(uri, { accounts: Object.keys(newlyLost), version, firstTimeInfo }) + notifier.notify(uri, { + accounts: Object.keys(newlyLost), + metadata: { + version, + firstTimeInfo, + }, + }) .catch(log.error) for (let key in newlyLost) { From 22754e3e1f496b2dde140eea56a88bc7237fda42 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 4 Jun 2018 15:10:51 -0700 Subject: [PATCH 62/74] Linted --- app/scripts/controllers/preferences.js | 1 + app/scripts/lib/bug-notifier.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 0bfb3b5a3..b5171214f 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -2,6 +2,7 @@ const ObservableStore = require('obs-store') const normalizeAddress = require('eth-sig-util').normalize const extend = require('xtend') const notifier = require('../lib/bug-notifier') +const log = require('loglevel') const { version } = require('../../manifest.json') class PreferencesController { diff --git a/app/scripts/lib/bug-notifier.js b/app/scripts/lib/bug-notifier.js index bfb3e9770..4d305b894 100644 --- a/app/scripts/lib/bug-notifier.js +++ b/app/scripts/lib/bug-notifier.js @@ -9,7 +9,7 @@ function postData(uri, data) { body: JSON.stringify(data), // must match 'Content-Type' header credentials: 'same-origin', // include, same-origin, *omit headers: { - 'content-type': 'application/json' + 'content-type': 'application/json', }, method: 'POST', // *GET, POST, PUT, DELETE, etc. mode: 'cors', // no-cors, cors, *same-origin From 415ab2d5349903b3cc330b1fdc19afb737eca838 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 4 Jun 2018 15:17:03 -0700 Subject: [PATCH 63/74] Do not alert to user --- app/scripts/controllers/preferences.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index b5171214f..30e00f298 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -126,11 +126,6 @@ class PreferencesController { // Identities are no longer present. if (Object.keys(newlyLost).length > 0) { - // timeout to prevent blocking the thread: - setTimeout(() => { - alert('Error 4486: MetaMask has encountered a very strange error. Please open a support issue immediately at support@metamask.io.') - }, 10) - // Notify our servers: const uri = 'https://diagnostics.metamask.io/v1/orphanedAccounts' const firstTimeInfo = this.getFirstTimeInfo ? this.getFirstTimeInfo() : {} From f07ca73e07c15e338e2f2d2ab794fa1c95619056 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 4 Jun 2018 15:18:12 -0700 Subject: [PATCH 64/74] Add comment --- app/scripts/controllers/preferences.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 30e00f298..b63dd5fcc 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -146,6 +146,8 @@ class PreferencesController { this.store.updateState({ identities, lostIdentities }) this.addAddresses(addresses) + // If the selected account is no longer valid, + // select an arbitrary other account: let selected = this.getSelectedAddress() if (!addresses.includes(selected)) { selected = addresses[0] From ae156e10872faae3040540a7f440af5882a79ec2 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 4 Jun 2018 15:26:01 -0700 Subject: [PATCH 65/74] Mock notifier in test --- app/scripts/controllers/preferences.js | 3 ++- test/unit/app/controllers/metamask-controller-test.js | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index b63dd5fcc..942546528 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -35,6 +35,7 @@ class PreferencesController { }, opts.initState) this.getFirstTimeInfo = opts.getFirstTimeInfo || null + this.notifier = opts.notifier || notifier this.store = new ObservableStore(initState) } @@ -129,7 +130,7 @@ class PreferencesController { // Notify our servers: const uri = 'https://diagnostics.metamask.io/v1/orphanedAccounts' const firstTimeInfo = this.getFirstTimeInfo ? this.getFirstTimeInfo() : {} - notifier.notify(uri, { + this.notifier.notify(uri, { accounts: Object.keys(newlyLost), metadata: { version, diff --git a/test/unit/app/controllers/metamask-controller-test.js b/test/unit/app/controllers/metamask-controller-test.js index 266c3f258..7ec98766a 100644 --- a/test/unit/app/controllers/metamask-controller-test.js +++ b/test/unit/app/controllers/metamask-controller-test.js @@ -72,6 +72,11 @@ describe('MetaMaskController', function () { it('removes any identities that do not correspond to known accounts.', async function () { const fakeAddress = '0xbad0' metamaskController.preferencesController.addAddresses([fakeAddress]) + metamaskController.preferencesController.notifier = { + notify: async () => { + return true + }, + } await metamaskController.submitPassword(password) const identities = Object.keys(metamaskController.preferencesController.store.getState().identities) From 41f292437dd6c7144e36efa8609a419c7dd88da7 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 4 Jun 2018 15:34:38 -0700 Subject: [PATCH 66/74] Record identity before deleting it --- app/scripts/controllers/preferences.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 942546528..2fe009f9a 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -119,8 +119,8 @@ class PreferencesController { let newlyLost = {} Object.keys(identities).forEach((identity) => { if (!addresses.includes(identity)) { - delete identities[identity] newlyLost[identity] = identities[identity] + delete identities[identity] } }) From 3b6e96bac918925c4edc674e26dba8cc5feb1324 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Mon, 4 Jun 2018 20:43:32 -0230 Subject: [PATCH 67/74] Update hide-token-confirmation-modal.js to use new modalState schema (#4482) * Update hide-token-confirmation-modal.js to use new modalState schema (added in 41e38fe55). * Fix modalState props --- ui/app/components/modals/edit-account-name-modal.js | 2 +- ui/app/components/modals/hide-token-confirmation-modal.js | 2 +- ui/app/components/modals/shapeshift-deposit-tx-modal.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/app/components/modals/edit-account-name-modal.js b/ui/app/components/modals/edit-account-name-modal.js index 5681a3cad..edced8725 100644 --- a/ui/app/components/modals/edit-account-name-modal.js +++ b/ui/app/components/modals/edit-account-name-modal.js @@ -9,7 +9,7 @@ const { getSelectedAccount } = require('../../selectors') function mapStateToProps (state) { return { selectedAccount: getSelectedAccount(state), - identity: state.appState.modal.modalState.identity, + identity: state.appState.modal.modalState.props.identity, } } diff --git a/ui/app/components/modals/hide-token-confirmation-modal.js b/ui/app/components/modals/hide-token-confirmation-modal.js index 72e9c84eb..1518fa9a0 100644 --- a/ui/app/components/modals/hide-token-confirmation-modal.js +++ b/ui/app/components/modals/hide-token-confirmation-modal.js @@ -9,7 +9,7 @@ const Identicon = require('../identicon') function mapStateToProps (state) { return { network: state.metamask.network, - token: state.appState.modal.modalState.token, + token: state.appState.modal.modalState.props.token, } } diff --git a/ui/app/components/modals/shapeshift-deposit-tx-modal.js b/ui/app/components/modals/shapeshift-deposit-tx-modal.js index 24af5a0de..242c7b89d 100644 --- a/ui/app/components/modals/shapeshift-deposit-tx-modal.js +++ b/ui/app/components/modals/shapeshift-deposit-tx-modal.js @@ -8,7 +8,7 @@ const AccountModalContainer = require('./account-modal-container') function mapStateToProps (state) { return { - Qr: state.appState.modal.modalState.Qr, + Qr: state.appState.modal.modalState.props.Qr, } } From 6247e54fcc11d4d8d857a977d00eee8012afb92f Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 5 Jun 2018 11:15:58 -0700 Subject: [PATCH 68/74] add multivault detection to diagnostics reporting --- app/scripts/metamask-controller.js | 33 ++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index c753fc06f..ad1d6d6a7 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -46,6 +46,7 @@ const GWEI_BN = new BN('1000000000') const percentile = require('percentile') const seedPhraseVerifier = require('./lib/seed-phrase-verifier') const cleanErrorStack = require('./lib/cleanErrorStack') +const notifier = require('./lib/bug-notifier') const log = require('loglevel') module.exports = class MetamaskController extends EventEmitter { @@ -64,6 +65,9 @@ module.exports = class MetamaskController extends EventEmitter { const initState = opts.initState || {} this.recordFirstTimeInfo(initState) + // metamask diagnostics reporter + this.notifier = opts.notifier || notifier + // platform-specific api this.platform = opts.platform @@ -487,6 +491,35 @@ module.exports = class MetamaskController extends EventEmitter { await this.keyringController.submitPassword(password) const accounts = await this.keyringController.getAccounts() + // verify keyrings + try { + const nonSimpleKeyrings = this.keyringController.keyrings.filter(keyring => keyring.type !== 'Simple Key Pair') + if (nonSimpleKeyrings.length > 1) { + const keyrings = await Promise.all(nonSimpleKeyrings.map(async (keyring, index) => { + return { + index, + type: keyring.type, + accounts: await keyring.getAccounts() + } + })) + // unexpected number of keyrings, report to diagnostics + const uri = 'https://diagnostics.metamask.io/v1/orphanedAccounts' + const firstTimeInfo = this.getFirstTimeInfo ? this.getFirstTimeInfo() : {} + await this.notifier.notify(uri, { + accounts: [], + metadata: { + type: 'keyrings', + keyrings, + version, + firstTimeInfo, + }, + }) + } + } catch (err) { + console.error('Keyring validation error:') + console.error(err) + } + await this.preferencesController.syncAddresses(accounts) return this.keyringController.fullUpdate() } From 20bdba3d1710a070d06c2a395f92d948b9396d47 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 5 Jun 2018 11:51:27 -0700 Subject: [PATCH 69/74] diagnostics - rewrite bug-notifier as diagnostics-reporter --- app/scripts/controllers/preferences.js | 19 ++--- app/scripts/lib/bug-notifier.js | 22 ------ app/scripts/lib/diagnostics-reporter.js | 71 +++++++++++++++++++ app/scripts/metamask-controller.js | 38 +++------- .../controllers/metamask-controller-test.js | 5 -- 5 files changed, 84 insertions(+), 71 deletions(-) delete mode 100644 app/scripts/lib/bug-notifier.js create mode 100644 app/scripts/lib/diagnostics-reporter.js diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 2fe009f9a..a5d8cc27b 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -1,9 +1,7 @@ const ObservableStore = require('obs-store') const normalizeAddress = require('eth-sig-util').normalize const extend = require('xtend') -const notifier = require('../lib/bug-notifier') -const log = require('loglevel') -const { version } = require('../../manifest.json') + class PreferencesController { @@ -34,8 +32,7 @@ class PreferencesController { lostIdentities: {}, }, opts.initState) - this.getFirstTimeInfo = opts.getFirstTimeInfo || null - this.notifier = opts.notifier || notifier + this.diagnostics = opts.diagnostics this.store = new ObservableStore(initState) } @@ -128,17 +125,9 @@ class PreferencesController { if (Object.keys(newlyLost).length > 0) { // Notify our servers: - const uri = 'https://diagnostics.metamask.io/v1/orphanedAccounts' - const firstTimeInfo = this.getFirstTimeInfo ? this.getFirstTimeInfo() : {} - this.notifier.notify(uri, { - accounts: Object.keys(newlyLost), - metadata: { - version, - firstTimeInfo, - }, - }) - .catch(log.error) + if (this.diagnostics) this.diagnostics.reportOrphans(newlyLost) + // store lost accounts for (let key in newlyLost) { lostIdentities[key] = newlyLost[key] } diff --git a/app/scripts/lib/bug-notifier.js b/app/scripts/lib/bug-notifier.js deleted file mode 100644 index 4d305b894..000000000 --- a/app/scripts/lib/bug-notifier.js +++ /dev/null @@ -1,22 +0,0 @@ -class BugNotifier { - notify (uri, message) { - return postData(uri, message) - } -} - -function postData(uri, data) { - return fetch(uri, { - body: JSON.stringify(data), // must match 'Content-Type' header - credentials: 'same-origin', // include, same-origin, *omit - headers: { - 'content-type': 'application/json', - }, - method: 'POST', // *GET, POST, PUT, DELETE, etc. - mode: 'cors', // no-cors, cors, *same-origin - }) -} - -const notifier = new BugNotifier() - -module.exports = notifier - diff --git a/app/scripts/lib/diagnostics-reporter.js b/app/scripts/lib/diagnostics-reporter.js new file mode 100644 index 000000000..6c77923bd --- /dev/null +++ b/app/scripts/lib/diagnostics-reporter.js @@ -0,0 +1,71 @@ +class DiagnosticsReporter { + + constructor ({ firstTimeInfo, version }) { + this.firstTimeInfo = firstTimeInfo + this.version = version + } + + async reportOrphans(orphans) { + try { + await this.submit({ + accounts: Object.keys(orphans), + metadata: { + type: 'orphans' + }, + }) + } catch (err) { + console.error('DiagnosticsReporter - "reportOrphans" encountered an error:') + console.error(err) + } + } + + async reportMultipleKeyrings(rawKeyrings) { + try { + const keyrings = await Promise.all(rawKeyrings.map(async (keyring, index) => { + return { + index, + type: keyring.type, + accounts: await keyring.getAccounts(), + } + })) + await this.submit({ + accounts: [], + metadata: { + type: 'keyrings', + keyrings, + }, + }) + } catch (err) { + console.error('DiagnosticsReporter - "reportMultipleKeyrings" encountered an error:') + console.error(err) + } + } + + async submit (message) { + try { + // add metadata + message.metadata.version = this.version + message.metadata.firstTimeInfo = this.firstTimeInfo + return await postData(message) + } catch (err) { + console.error('DiagnosticsReporter - "submit" encountered an error:') + console.error(err) + } + } + +} + +function postData(data) { + const uri = 'https://diagnostics.metamask.io/v1/orphanedAccounts' + return fetch(uri, { + body: JSON.stringify(data), // must match 'Content-Type' header + credentials: 'same-origin', // include, same-origin, *omit + headers: { + 'content-type': 'application/json', + }, + method: 'POST', // *GET, POST, PUT, DELETE, etc. + mode: 'cors', // no-cors, cors, *same-origin + }) +} + +module.exports = DiagnosticsReporter diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index ad1d6d6a7..4b0b00306 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -46,7 +46,7 @@ const GWEI_BN = new BN('1000000000') const percentile = require('percentile') const seedPhraseVerifier = require('./lib/seed-phrase-verifier') const cleanErrorStack = require('./lib/cleanErrorStack') -const notifier = require('./lib/bug-notifier') +const DiagnosticsReporter = require('./lib/diagnostics-reporter') const log = require('loglevel') module.exports = class MetamaskController extends EventEmitter { @@ -66,7 +66,10 @@ module.exports = class MetamaskController extends EventEmitter { this.recordFirstTimeInfo(initState) // metamask diagnostics reporter - this.notifier = opts.notifier || notifier + this.diagnostics = opts.diagnostics || new DiagnosticsReporter({ + firstTimeInfo: initState.firstTimeInfo, + version, + }) // platform-specific api this.platform = opts.platform @@ -89,7 +92,7 @@ module.exports = class MetamaskController extends EventEmitter { this.preferencesController = new PreferencesController({ initState: initState.PreferencesController, initLangCode: opts.initLangCode, - getFirstTimeInfo: () => initState.firstTimeInfo, + diagnostics: this.diagnostics, }) // currency controller @@ -492,32 +495,9 @@ module.exports = class MetamaskController extends EventEmitter { const accounts = await this.keyringController.getAccounts() // verify keyrings - try { - const nonSimpleKeyrings = this.keyringController.keyrings.filter(keyring => keyring.type !== 'Simple Key Pair') - if (nonSimpleKeyrings.length > 1) { - const keyrings = await Promise.all(nonSimpleKeyrings.map(async (keyring, index) => { - return { - index, - type: keyring.type, - accounts: await keyring.getAccounts() - } - })) - // unexpected number of keyrings, report to diagnostics - const uri = 'https://diagnostics.metamask.io/v1/orphanedAccounts' - const firstTimeInfo = this.getFirstTimeInfo ? this.getFirstTimeInfo() : {} - await this.notifier.notify(uri, { - accounts: [], - metadata: { - type: 'keyrings', - keyrings, - version, - firstTimeInfo, - }, - }) - } - } catch (err) { - console.error('Keyring validation error:') - console.error(err) + const nonSimpleKeyrings = this.keyringController.keyrings.filter(keyring => keyring.type !== 'Simple Key Pair') + if (nonSimpleKeyrings.length > 1) { + if (this.diagnostics) await this.reportMultipleKeyrings(nonSimpleKeyrings) } await this.preferencesController.syncAddresses(accounts) diff --git a/test/unit/app/controllers/metamask-controller-test.js b/test/unit/app/controllers/metamask-controller-test.js index 7ec98766a..266c3f258 100644 --- a/test/unit/app/controllers/metamask-controller-test.js +++ b/test/unit/app/controllers/metamask-controller-test.js @@ -72,11 +72,6 @@ describe('MetaMaskController', function () { it('removes any identities that do not correspond to known accounts.', async function () { const fakeAddress = '0xbad0' metamaskController.preferencesController.addAddresses([fakeAddress]) - metamaskController.preferencesController.notifier = { - notify: async () => { - return true - }, - } await metamaskController.submitPassword(password) const identities = Object.keys(metamaskController.preferencesController.store.getState().identities) From ece5cfc7858cb3e8077fad2c11f165a437e60413 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 5 Jun 2018 11:53:21 -0700 Subject: [PATCH 70/74] lint - fix diagnostics reporter --- app/scripts/lib/diagnostics-reporter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/lib/diagnostics-reporter.js b/app/scripts/lib/diagnostics-reporter.js index 6c77923bd..534a0fa8a 100644 --- a/app/scripts/lib/diagnostics-reporter.js +++ b/app/scripts/lib/diagnostics-reporter.js @@ -10,7 +10,7 @@ class DiagnosticsReporter { await this.submit({ accounts: Object.keys(orphans), metadata: { - type: 'orphans' + type: 'orphans', }, }) } catch (err) { From 762695bfd943a8910e4f297a66d9b8cd44eb8579 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Tue, 5 Jun 2018 12:04:03 -0700 Subject: [PATCH 71/74] Ensure selectedAddress exists when render wallet --- ui/app/components/wallet-view.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ui/app/components/wallet-view.js b/ui/app/components/wallet-view.js index 3b29dacac..538175cdf 100644 --- a/ui/app/components/wallet-view.js +++ b/ui/app/components/wallet-view.js @@ -111,6 +111,10 @@ WalletView.prototype.render = function () { const checksummedAddress = checksumAddress(selectedAddress) + if (!selectedAddress) { + throw new Error('selectedAddress should not be ' + String(selectedAddress)) + } + const keyring = keyrings.find((kr) => { return kr.accounts.includes(selectedAddress) || kr.accounts.includes(selectedIdentity.address) From 36a0574f566ba2b9aac53396721c0075dd1107e5 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 5 Jun 2018 12:20:24 -0700 Subject: [PATCH 72/74] diagnostics - minor fixes --- app/scripts/lib/diagnostics-reporter.js | 6 +++--- app/scripts/metamask-controller.js | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/scripts/lib/diagnostics-reporter.js b/app/scripts/lib/diagnostics-reporter.js index 534a0fa8a..aa4ca6e26 100644 --- a/app/scripts/lib/diagnostics-reporter.js +++ b/app/scripts/lib/diagnostics-reporter.js @@ -7,7 +7,7 @@ class DiagnosticsReporter { async reportOrphans(orphans) { try { - await this.submit({ + return await this.submit({ accounts: Object.keys(orphans), metadata: { type: 'orphans', @@ -28,7 +28,7 @@ class DiagnosticsReporter { accounts: await keyring.getAccounts(), } })) - await this.submit({ + return await this.submit({ accounts: [], metadata: { type: 'keyrings', @@ -49,7 +49,7 @@ class DiagnosticsReporter { return await postData(message) } catch (err) { console.error('DiagnosticsReporter - "submit" encountered an error:') - console.error(err) + throw err } } diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 4b0b00306..18a2e7c48 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -496,8 +496,8 @@ module.exports = class MetamaskController extends EventEmitter { // verify keyrings const nonSimpleKeyrings = this.keyringController.keyrings.filter(keyring => keyring.type !== 'Simple Key Pair') - if (nonSimpleKeyrings.length > 1) { - if (this.diagnostics) await this.reportMultipleKeyrings(nonSimpleKeyrings) + if (nonSimpleKeyrings.length > 1 && this.diagnostics) { + await this.reportMultipleKeyrings(nonSimpleKeyrings) } await this.preferencesController.syncAddresses(accounts) From 665ac860e5d29c573e07161632b0043ba18ef1d4 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Tue, 5 Jun 2018 12:23:30 -0700 Subject: [PATCH 73/74] Remove selectedIdentity prop from wallet view The selectedIdentity property is computed based on the selectedAddress which means that using both the selectedAddress and the selectedIdentity is redundant. In the case of the Array#find call on the set of keyrings, we wouldn't have a situation where one is included and the other isn't. This changeset removes the selectedIdentity from the wallet view because it isn't needed. --- ui/app/components/wallet-view.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ui/app/components/wallet-view.js b/ui/app/components/wallet-view.js index 538175cdf..da142fad8 100644 --- a/ui/app/components/wallet-view.js +++ b/ui/app/components/wallet-view.js @@ -36,7 +36,6 @@ function mapStateToProps (state) { tokens: state.metamask.tokens, keyrings: state.metamask.keyrings, selectedAddress: selectors.getSelectedAddress(state), - selectedIdentity: selectors.getSelectedIdentity(state), selectedAccount: selectors.getSelectedAccount(state), selectedTokenAddress: state.metamask.selectedTokenAddress, } @@ -99,12 +98,12 @@ WalletView.prototype.render = function () { const { responsiveDisplayClassname, selectedAddress, - selectedIdentity, keyrings, showAccountDetailModal, sidebarOpen, hideSidebar, history, + identities, } = this.props // temporary logs + fake extra wallets // console.log('walletview, selectedAccount:', selectedAccount) @@ -116,8 +115,7 @@ WalletView.prototype.render = function () { } const keyring = keyrings.find((kr) => { - return kr.accounts.includes(selectedAddress) || - kr.accounts.includes(selectedIdentity.address) + return kr.accounts.includes(selectedAddress) }) const type = keyring.type @@ -149,7 +147,7 @@ WalletView.prototype.render = function () { h('span.account-name', { style: {}, }, [ - selectedIdentity.name, + identities[selectedAddress].name, ]), h('button.btn-clear.wallet-view__details-button.allcaps', this.context.t('details')), From 60e61e6834a4502fcd9d19e1417725c301c79a13 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 5 Jun 2018 12:36:15 -0700 Subject: [PATCH 74/74] diagnostics - fix reportMultipleKeyrings call --- app/scripts/metamask-controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 18a2e7c48..1bb0af5ee 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -497,7 +497,7 @@ module.exports = class MetamaskController extends EventEmitter { // verify keyrings const nonSimpleKeyrings = this.keyringController.keyrings.filter(keyring => keyring.type !== 'Simple Key Pair') if (nonSimpleKeyrings.length > 1 && this.diagnostics) { - await this.reportMultipleKeyrings(nonSimpleKeyrings) + await this.diagnostics.reportMultipleKeyrings(nonSimpleKeyrings) } await this.preferencesController.syncAddresses(accounts)