From 93a9ef284e527a4a7d26305be8abf455d938cca4 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 30 Apr 2018 16:05:01 -0700 Subject: [PATCH 01/18] sentry - add helper to fully rewrite all error messages --- app/scripts/lib/setupRaven.js | 42 +++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/app/scripts/lib/setupRaven.js b/app/scripts/lib/setupRaven.js index b1b67f771..d164827ab 100644 --- a/app/scripts/lib/setupRaven.js +++ b/app/scripts/lib/setupRaven.js @@ -25,7 +25,7 @@ function setupRaven(opts) { const report = opts.data try { // handle error-like non-error exceptions - nonErrorException(report) + rewriteErrorLikeExceptions(report) // simplify certain complex error messages (e.g. Ethjs) simplifyErrorMessages(report) // modify report urls @@ -42,27 +42,35 @@ function setupRaven(opts) { return Raven } -function nonErrorException(report) { - // handle errors that lost their error-ness in serialization - if (report.message.includes('Non-Error exception captured with keys: message')) { - if (!(report.extra && report.extra.__serialized__)) return - report.message = `Non-Error Exception: ${report.extra.__serialized__.message}` - } +function rewriteErrorLikeExceptions(report) { + // handle errors that lost their error-ness in serialization (e.g. dnode) + rewriteErrorMessages(report, (errorMessage) => { + if (!errorMessage.includes('Non-Error exception captured with keys:')) return errorMessage + if (!(report.extra && report.extra.__serialized__ && report.extra.__serialized__.message)) return errorMessage + return `Non-Error Exception: ${report.extra.__serialized__.message}` + }) } function simplifyErrorMessages(report) { + rewriteErrorMessages(report, (errorMessage) => { + // simplify ethjs error messages + errorMessage = extractEthjsErrorMessage(errorMessage) + // simplify 'Transaction Failed: known transaction' + if (errorMessage.indexOf('Transaction Failed: known transaction') === 0) { + // cut the hash from the error message + errorMessage = 'Transaction Failed: known transaction' + } + return errorMessage + }) +} + +function rewriteErrorMessages(report, rewriteFn) { + // rewrite top level message + report.message = rewriteFn(report.message) + // rewrite each exception message if (report.exception && report.exception.values) { report.exception.values.forEach(item => { - let errorMessage = item.value - // simplify ethjs error messages - errorMessage = extractEthjsErrorMessage(errorMessage) - // simplify 'Transaction Failed: known transaction' - if (errorMessage.indexOf('Transaction Failed: known transaction') === 0) { - // cut the hash from the error message - errorMessage = 'Transaction Failed: known transaction' - } - // finalize - item.value = errorMessage + item.value = rewriteFn(item.value) }) } } From bfedd2776d1fa668259488a5216c533b4e959fb0 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 30 Apr 2018 16:23:16 -0700 Subject: [PATCH 02/18] controllers - network - more semantic assert --- app/scripts/controllers/network/network.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/controllers/network/network.js b/app/scripts/controllers/network/network.js index 2f5b81cd2..3e4bfa020 100644 --- a/app/scripts/controllers/network/network.js +++ b/app/scripts/controllers/network/network.js @@ -111,7 +111,7 @@ module.exports = class NetworkController extends EventEmitter { } async setProviderType (type, forceUpdate = false) { - assert(type !== 'rpc', `NetworkController.setProviderType - cannot connect by type "rpc"`) + assert.notEqual(type, 'rpc', `NetworkController.setProviderType - cannot connect by type "rpc"`) // skip if type already matches if (type === this.getProviderConfig().type && !forceUpdate) { return From 6f316ca450967c161e7f231127a76494bace40a8 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 30 Apr 2018 16:36:17 -0700 Subject: [PATCH 03/18] network - remove setNetworkEndpoints --- app/scripts/controllers/network/network.js | 13 ------------- app/scripts/metamask-controller.js | 1 - old-ui/app/app.js | 2 -- ui/app/actions.js | 18 ------------------ ui/app/components/pages/settings/settings.js | 1 - ui/app/components/pages/unlock.js | 4 ---- ui/app/first-time/init-menu.js | 1 - ui/app/select-app.js | 4 +--- ui/app/unlock.js | 1 - ui/index.js | 1 - 10 files changed, 1 insertion(+), 45 deletions(-) diff --git a/app/scripts/controllers/network/network.js b/app/scripts/controllers/network/network.js index 3e4bfa020..37a5e69a0 100644 --- a/app/scripts/controllers/network/network.js +++ b/app/scripts/controllers/network/network.js @@ -38,19 +38,6 @@ module.exports = class NetworkController extends EventEmitter { this.on('networkDidChange', this.lookupNetwork) } - async setNetworkEndpoints (version) { - if (version === this._networkEndpointVersion) { - return - } - - this._networkEndpointVersion = version - this._networkEndpoints = getNetworkEndpoints(version) - this._defaultRpc = this._networkEndpoints[DEFAULT_NETWORK] - const { type } = this.getProviderConfig() - - return this.setProviderType(type, true) - } - initializeProvider (_providerParams) { this._baseProviderParams = _providerParams const { type, rpcTarget } = this.providerStore.getState() diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index c4a73d8ea..67d257fea 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -355,7 +355,6 @@ module.exports = class MetamaskController extends EventEmitter { submitPassword: nodeify(keyringController.submitPassword, keyringController), // network management - setNetworkEndpoints: nodeify(networkController.setNetworkEndpoints, networkController), setProviderType: nodeify(networkController.setProviderType, networkController), setCustomRpc: nodeify(this.setCustomRpc, this), diff --git a/old-ui/app/app.js b/old-ui/app/app.js index 3aa845b3a..fe5e57d93 100644 --- a/old-ui/app/app.js +++ b/old-ui/app/app.js @@ -409,7 +409,6 @@ App.prototype.renderDropdown = function () { closeMenu: () => this.setState({ isMainMenuOpen: !isOpen }), onClick: () => { this.props.dispatch(actions.setFeatureFlag('betaUI', true, 'BETA_UI_NOTIFICATION_MODAL')) - .then(() => this.props.dispatch(actions.setNetworkEndpoints(BETA_UI_NETWORK_TYPE))) }, }, 'Try Beta!'), ]) @@ -472,7 +471,6 @@ App.prototype.renderPrimary = function () { onClick: () => { global.platform.openExtensionInBrowser() props.dispatch(actions.setFeatureFlag('betaUI', true, 'BETA_UI_NOTIFICATION_MODAL')) - .then(() => props.dispatch(actions.setNetworkEndpoints(BETA_UI_NETWORK_TYPE))) }, style: { fontSize: '0.8em', diff --git a/ui/app/actions.js b/ui/app/actions.js index e817fa907..021ffcdfd 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -271,7 +271,6 @@ var actions = { SET_MOUSE_USER_STATE: 'SET_MOUSE_USER_STATE', // Network - setNetworkEndpoints, updateNetworkEndpointType, UPDATE_NETWORK_ENDPOINT_TYPE: 'UPDATE_NETWORK_ENDPOINT_TYPE', @@ -1922,23 +1921,6 @@ function setLocaleMessages (localeMessages) { } } -function setNetworkEndpoints (networkEndpointType) { - return dispatch => { - log.debug('background.setNetworkEndpoints') - return new Promise((resolve, reject) => { - background.setNetworkEndpoints(networkEndpointType, err => { - if (err) { - dispatch(actions.displayWarning(err.message)) - return reject(err) - } - - dispatch(actions.updateNetworkEndpointType(networkEndpointType)) - resolve(networkEndpointType) - }) - }) - } -} - function updateNetworkEndpointType (networkEndpointType) { return { type: actions.UPDATE_NETWORK_ENDPOINT_TYPE, diff --git a/ui/app/components/pages/settings/settings.js b/ui/app/components/pages/settings/settings.js index bdefe56f8..e5725c0ca 100644 --- a/ui/app/components/pages/settings/settings.js +++ b/ui/app/components/pages/settings/settings.js @@ -349,7 +349,6 @@ const mapDispatchToProps = dispatch => { updateCurrentLocale: key => dispatch(actions.updateCurrentLocale(key)), setFeatureFlagToBeta: () => { return dispatch(actions.setFeatureFlag('betaUI', false, 'OLD_UI_NOTIFICATION_MODAL')) - .then(() => dispatch(actions.setNetworkEndpoints(OLD_UI_NETWORK_TYPE))) }, showResetAccountConfirmationModal: () => { return dispatch(actions.showModal({ name: 'CONFIRM_RESET_ACCOUNT' })) diff --git a/ui/app/components/pages/unlock.js b/ui/app/components/pages/unlock.js index 30144b978..bbdb17306 100644 --- a/ui/app/components/pages/unlock.js +++ b/ui/app/components/pages/unlock.js @@ -8,7 +8,6 @@ const { tryUnlockMetamask, forgotPassword, markPasswordForgotten, - setNetworkEndpoints, setFeatureFlag, } = require('../../actions') const { ENVIRONMENT_TYPE_POPUP } = require('../../../../app/scripts/lib/enums') @@ -146,7 +145,6 @@ class UnlockScreen extends Component { h('p.pointer', { onClick: () => { this.props.useOldInterface() - .then(() => this.props.setNetworkEndpoints(OLD_UI_NETWORK_TYPE)) }, style: { fontSize: '0.8em', @@ -168,7 +166,6 @@ UnlockScreen.propTypes = { isUnlocked: PropTypes.bool, t: PropTypes.func, useOldInterface: PropTypes.func, - setNetworkEndpoints: PropTypes.func, } const mapStateToProps = state => { @@ -184,7 +181,6 @@ const mapDispatchToProps = dispatch => { tryUnlockMetamask: password => dispatch(tryUnlockMetamask(password)), markPasswordForgotten: () => dispatch(markPasswordForgotten()), useOldInterface: () => dispatch(setFeatureFlag('betaUI', false, 'OLD_UI_NOTIFICATION_MODAL')), - setNetworkEndpoints: type => dispatch(setNetworkEndpoints(type)), } } diff --git a/ui/app/first-time/init-menu.js b/ui/app/first-time/init-menu.js index 6cb548bb9..7b02d7fd6 100644 --- a/ui/app/first-time/init-menu.js +++ b/ui/app/first-time/init-menu.js @@ -190,7 +190,6 @@ class InitializeMenuScreen extends Component { showOldUI () { this.props.dispatch(actions.setFeatureFlag('betaUI', false, 'OLD_UI_NOTIFICATION_MODAL')) - .then(() => this.props.dispatch(actions.setNetworkEndpoints(OLD_UI_NETWORK_TYPE))) } } diff --git a/ui/app/select-app.js b/ui/app/select-app.js index 808f9ba56..6611fea09 100644 --- a/ui/app/select-app.js +++ b/ui/app/select-app.js @@ -6,7 +6,7 @@ const { HashRouter } = require('react-router-dom') const App = require('./app') const OldApp = require('../../old-ui/app/app') const { autoAddToBetaUI } = require('./selectors') -const { setFeatureFlag, setNetworkEndpoints } = require('./actions') +const { setFeatureFlag } = require('./actions') const { BETA_UI_NETWORK_TYPE } = require('../../app/scripts/controllers/network/enums') const I18nProvider = require('./i18n-provider') @@ -24,11 +24,9 @@ function mapDispatchToProps (dispatch) { return { setFeatureFlagWithModal: () => { return dispatch(setFeatureFlag('betaUI', true, 'BETA_UI_NOTIFICATION_MODAL')) - .then(() => dispatch(setNetworkEndpoints(BETA_UI_NETWORK_TYPE))) }, setFeatureFlagWithoutModal: () => { return dispatch(setFeatureFlag('betaUI', true)) - .then(() => dispatch(setNetworkEndpoints(BETA_UI_NETWORK_TYPE))) }, } } diff --git a/ui/app/unlock.js b/ui/app/unlock.js index 099e5f9c6..bcc24c3b0 100644 --- a/ui/app/unlock.js +++ b/ui/app/unlock.js @@ -92,7 +92,6 @@ UnlockScreen.prototype.render = function () { h('p.pointer', { onClick: () => { this.props.dispatch(actions.setFeatureFlag('betaUI', false, 'OLD_UI_NOTIFICATION_MODAL')) - .then(() => this.props.dispatch(actions.setNetworkEndpoints(OLD_UI_NETWORK_TYPE))) }, style: { fontSize: '0.8em', diff --git a/ui/index.js b/ui/index.js index 075faf66d..d7cedd12d 100644 --- a/ui/index.js +++ b/ui/index.js @@ -57,7 +57,6 @@ async function startApp (metamaskState, accountManager, opts) { const useBetaUi = metamaskState.featureFlags.betaUI const networkEndpointType = useBetaUi ? BETA_UI_NETWORK_TYPE : OLD_UI_NETWORK_TYPE - store.dispatch(actions.setNetworkEndpoints(networkEndpointType)) // if unconfirmed txs, start on txConf page const unapprovedTxsAll = txHelper(metamaskState.unapprovedTxs, metamaskState.unapprovedMsgs, metamaskState.unapprovedPersonalMsgs, metamaskState.unapprovedTypedMessages, metamaskState.network) From 53caa49666e00ecb21a5a999da01355a6c7485e3 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 30 Apr 2018 17:59:53 -0700 Subject: [PATCH 04/18] network - refactor to remove unnecesary code --- app/scripts/controllers/network/enums.js | 26 ------ app/scripts/controllers/network/network.js | 92 +++++++--------------- app/scripts/controllers/network/util.js | 35 -------- 3 files changed, 29 insertions(+), 124 deletions(-) diff --git a/app/scripts/controllers/network/enums.js b/app/scripts/controllers/network/enums.js index 4f29e301b..9da7f309c 100644 --- a/app/scripts/controllers/network/enums.js +++ b/app/scripts/controllers/network/enums.js @@ -13,20 +13,6 @@ const RINKEBY_DISPLAY_NAME = 'Rinkeby' const KOVAN_DISPLAY_NAME = 'Kovan' const MAINNET_DISPLAY_NAME = 'Main Ethereum Network' -const MAINNET_RPC_URL = 'https://mainnet.infura.io/metamask' -const ROPSTEN_RPC_URL = 'https://ropsten.infura.io/metamask' -const KOVAN_RPC_URL = 'https://kovan.infura.io/metamask' -const RINKEBY_RPC_URL = 'https://rinkeby.infura.io/metamask' -const LOCALHOST_RPC_URL = 'http://localhost:8545' - -const MAINNET_RPC_URL_BETA = 'https://mainnet.infura.io/metamask2' -const ROPSTEN_RPC_URL_BETA = 'https://ropsten.infura.io/metamask2' -const KOVAN_RPC_URL_BETA = 'https://kovan.infura.io/metamask2' -const RINKEBY_RPC_URL_BETA = 'https://rinkeby.infura.io/metamask2' - -const DEFAULT_NETWORK = 'rinkeby' -const OLD_UI_NETWORK_TYPE = 'network' -const BETA_UI_NETWORK_TYPE = 'networkBeta' module.exports = { ROPSTEN, @@ -41,16 +27,4 @@ module.exports = { RINKEBY_DISPLAY_NAME, KOVAN_DISPLAY_NAME, MAINNET_DISPLAY_NAME, - MAINNET_RPC_URL, - ROPSTEN_RPC_URL, - KOVAN_RPC_URL, - RINKEBY_RPC_URL, - LOCALHOST_RPC_URL, - MAINNET_RPC_URL_BETA, - ROPSTEN_RPC_URL_BETA, - KOVAN_RPC_URL_BETA, - RINKEBY_RPC_URL_BETA, - DEFAULT_NETWORK, - OLD_UI_NETWORK_TYPE, - BETA_UI_NETWORK_TYPE, } diff --git a/app/scripts/controllers/network/network.js b/app/scripts/controllers/network/network.js index 37a5e69a0..826ce89c3 100644 --- a/app/scripts/controllers/network/network.js +++ b/app/scripts/controllers/network/network.js @@ -14,10 +14,9 @@ const { RINKEBY, KOVAN, MAINNET, - OLD_UI_NETWORK_TYPE, - DEFAULT_NETWORK, + LOCALHOST, } = require('./enums') -const { getNetworkEndpoints } = require('./util') +const LOCALHOST_RPC_URL = 'http://localhost:8545' const INFURA_PROVIDER_TYPES = [ROPSTEN, RINKEBY, KOVAN, MAINNET] module.exports = class NetworkController extends EventEmitter { @@ -25,11 +24,6 @@ module.exports = class NetworkController extends EventEmitter { constructor (config) { super() - this._networkEndpointVersion = OLD_UI_NETWORK_TYPE - this._networkEndpoints = getNetworkEndpoints(OLD_UI_NETWORK_TYPE) - this._defaultRpc = this._networkEndpoints[DEFAULT_NETWORK] - - config.provider.rpcTarget = this.getRpcAddressForType(config.provider.type, config.provider) this.networkStore = new ObservableStore('loading') this.providerStore = new ObservableStore(config.provider) this.store = new ComposedStore({ provider: this.providerStore, network: this.networkStore }) @@ -41,12 +35,7 @@ module.exports = class NetworkController extends EventEmitter { initializeProvider (_providerParams) { this._baseProviderParams = _providerParams const { type, rpcTarget } = this.providerStore.getState() - // map rpcTarget to rpcUrl - const opts = { - type, - rpcUrl: rpcTarget, - } - this._configureProvider(opts) + this._configureProvider({ type, rpcTarget }) this._proxy.on('block', this._logBlock.bind(this)) this._proxy.on('error', this.verifyNetwork.bind(this)) this.ethQuery = new EthQuery(this._proxy) @@ -83,45 +72,27 @@ module.exports = class NetworkController extends EventEmitter { }) } - setRpcTarget (rpcUrl) { - this.providerStore.updateState({ + setRpcTarget (rpcTarget) { + const providerConfig = { type: 'rpc', - rpcTarget: rpcUrl, - }) - this._switchNetwork({ rpcUrl }) - } - - getCurrentRpcAddress () { - const provider = this.getProviderConfig() - if (!provider) return null - return this.getRpcAddressForType(provider.type) - } - - async setProviderType (type, forceUpdate = false) { - assert.notEqual(type, 'rpc', `NetworkController.setProviderType - cannot connect by type "rpc"`) - // skip if type already matches - if (type === this.getProviderConfig().type && !forceUpdate) { - return + rpcTarget, } + this.providerStore.updateState(providerConfig) + this._switchNetwork(providerConfig) + } - const rpcTarget = this.getRpcAddressForType(type) - assert(rpcTarget, `NetworkController - unknown rpc address for type "${type}"`) - this.providerStore.updateState({ type, rpcTarget }) - this._switchNetwork({ type }) + async setProviderType (type) { + assert.notEqual(type, 'rpc', `NetworkController - cannot call "setProviderType" with type 'rpc'. use "setRpcTarget"`) + assert(INFURA_PROVIDER_TYPES.includes(type) || type === LOCALHOST, `NetworkController - Unknown rpc type "${type}"`) + const providerConfig = { type } + this.providerStore.updateState(providerConfig) + this._switchNetwork(providerConfig) } getProviderConfig () { return this.providerStore.getState() } - getRpcAddressForType (type, provider = this.getProviderConfig()) { - if (this._networkEndpoints[type]) { - return this._networkEndpoints[type] - } - - return provider && provider.rpcTarget ? provider.rpcTarget : this._defaultRpc - } - // // Private // @@ -133,32 +104,27 @@ module.exports = class NetworkController extends EventEmitter { } _configureProvider (opts) { - // type-based rpc endpoints - const { type } = opts - if (type) { - // type-based infura rpc endpoints - const isInfura = INFURA_PROVIDER_TYPES.includes(type) - opts.rpcUrl = this.getRpcAddressForType(type) - if (isInfura) { - this._configureInfuraProvider(opts) - // other type-based rpc endpoints - } else { - this._configureStandardProvider(opts) - } + const { type, rpcTarget } = opts + // infura type-based endpoints + const isInfura = INFURA_PROVIDER_TYPES.includes(type) + if (isInfura) { + this._configureInfuraProvider(opts) + // other type-based rpc endpoints + } else if (type === LOCALHOST) { + this._configureStandardProvider({ rpcUrl: LOCALHOST_RPC_URL }) // url-based rpc endpoints + } else if (type === 'rpc'){ + this._configureStandardProvider({ rpcUrl: rpcTarget }) } else { - this._configureStandardProvider(opts) + throw new Error(`NetworkController - _configureProvider - unknown type "${type}"`) } } - _configureInfuraProvider (opts) { - log.info('_configureInfuraProvider', opts) - const infuraProvider = createInfuraProvider({ - network: opts.type, - }) + _configureInfuraProvider ({ type }) { + log.info('_configureInfuraProvider', type) + const infuraProvider = createInfuraProvider({ network: type }) const infuraSubprovider = new SubproviderFromProvider(infuraProvider) const providerParams = extend(this._baseProviderParams, { - rpcUrl: opts.rpcUrl, engineParams: { pollingInterval: 8000, blockTrackerProvider: infuraProvider, diff --git a/app/scripts/controllers/network/util.js b/app/scripts/controllers/network/util.js index 4f38ccda4..a14fddea7 100644 --- a/app/scripts/controllers/network/util.js +++ b/app/scripts/controllers/network/util.js @@ -11,17 +11,6 @@ const { RINKEBY_DISPLAY_NAME, KOVAN_DISPLAY_NAME, MAINNET_DISPLAY_NAME, - MAINNET_RPC_URL, - ROPSTEN_RPC_URL, - KOVAN_RPC_URL, - RINKEBY_RPC_URL, - LOCALHOST_RPC_URL, - MAINNET_RPC_URL_BETA, - ROPSTEN_RPC_URL_BETA, - KOVAN_RPC_URL_BETA, - RINKEBY_RPC_URL_BETA, - OLD_UI_NETWORK_TYPE, - BETA_UI_NETWORK_TYPE, } = require('./enums') const networkToNameMap = { @@ -34,32 +23,8 @@ const networkToNameMap = { [KOVAN_CODE]: KOVAN_DISPLAY_NAME, } -const networkEndpointsMap = { - [OLD_UI_NETWORK_TYPE]: { - [LOCALHOST]: LOCALHOST_RPC_URL, - [MAINNET]: MAINNET_RPC_URL, - [ROPSTEN]: ROPSTEN_RPC_URL, - [KOVAN]: KOVAN_RPC_URL, - [RINKEBY]: RINKEBY_RPC_URL, - }, - [BETA_UI_NETWORK_TYPE]: { - [LOCALHOST]: LOCALHOST_RPC_URL, - [MAINNET]: MAINNET_RPC_URL_BETA, - [ROPSTEN]: ROPSTEN_RPC_URL_BETA, - [KOVAN]: KOVAN_RPC_URL_BETA, - [RINKEBY]: RINKEBY_RPC_URL_BETA, - }, -} - const getNetworkDisplayName = key => networkToNameMap[key] -const getNetworkEndpoints = (networkType = OLD_UI_NETWORK_TYPE) => { - return { - ...networkEndpointsMap[networkType], - } -} - module.exports = { getNetworkDisplayName, - getNetworkEndpoints, } From fec4c50657c0be5bdae9dd211ef4b1a6ebb1be43 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 2 May 2018 18:03:59 -0700 Subject: [PATCH 05/18] controllers - network - move default config out of first-time-state --- app/scripts/controllers/network/network.js | 17 +++++++++++++++-- app/scripts/first-time-state.js | 9 --------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/app/scripts/controllers/network/network.js b/app/scripts/controllers/network/network.js index 826ce89c3..5496f8a68 100644 --- a/app/scripts/controllers/network/network.js +++ b/app/scripts/controllers/network/network.js @@ -19,14 +19,27 @@ const { const LOCALHOST_RPC_URL = 'http://localhost:8545' const INFURA_PROVIDER_TYPES = [ROPSTEN, RINKEBY, KOVAN, MAINNET] +const env = process.env.METAMASK_ENV +const METAMASK_DEBUG = process.env.METAMASK_DEBUG +const testMode = (METAMASK_DEBUG || env === 'test') + +const defaultProviderConfig = { + type: testMode ? RINKEBY : MAINNET, +} + module.exports = class NetworkController extends EventEmitter { - constructor (config) { + constructor (opts = {}) { super() + // parse options + const providerConfig = opts.provider || defaultProviderConfig + console.log('providerStore:', providerConfig) + // create stores + this.providerStore = new ObservableStore(providerConfig) this.networkStore = new ObservableStore('loading') - this.providerStore = new ObservableStore(config.provider) this.store = new ComposedStore({ provider: this.providerStore, network: this.networkStore }) + // create event emitter proxy this._proxy = createEventEmitterProxy() this.on('networkDidChange', this.lookupNetwork) diff --git a/app/scripts/first-time-state.js b/app/scripts/first-time-state.js index c49d89288..13119bc04 100644 --- a/app/scripts/first-time-state.js +++ b/app/scripts/first-time-state.js @@ -1,7 +1,3 @@ -// test and development environment variables -const env = process.env.METAMASK_ENV -const METAMASK_DEBUG = process.env.METAMASK_DEBUG -const { DEFAULT_NETWORK, MAINNET } = require('./controllers/network/enums') /** * @typedef {Object} FirstTimeState @@ -14,11 +10,6 @@ const { DEFAULT_NETWORK, MAINNET } = require('./controllers/network/enums') */ const initialState = { config: {}, - NetworkController: { - provider: { - type: (METAMASK_DEBUG || env === 'test') ? DEFAULT_NETWORK : MAINNET, - }, - }, } module.exports = initialState From d2aa36f866ae25b2facb90583d552097a80d42b3 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 2 May 2018 18:07:29 -0700 Subject: [PATCH 06/18] test - network controller - remove tests for deprecated APIs + update tests --- test/unit/network-contoller-test.js | 30 +++++------------------------ 1 file changed, 5 insertions(+), 25 deletions(-) diff --git a/test/unit/network-contoller-test.js b/test/unit/network-contoller-test.js index 2b905718b..2d590a3f6 100644 --- a/test/unit/network-contoller-test.js +++ b/test/unit/network-contoller-test.js @@ -3,17 +3,15 @@ const nock = require('nock') const NetworkController = require('../../app/scripts/controllers/network') const { getNetworkDisplayName, - getNetworkEndpoints, } = require('../../app/scripts/controllers/network/util') const { createTestProviderTools } = require('../stub/provider') const providerResultStub = {} -const provider = createTestProviderTools({ scaffold: providerResultStub }).provider describe('# Network Controller', function () { let networkController const noop = () => {} - const networkControllerProviderInit = { + const networkControllerProviderConfig = { getAccounts: noop, } @@ -24,11 +22,9 @@ describe('# Network Controller', function () { .post('/metamask') .reply(200) - networkController = new NetworkController({ - provider, - }) + networkController = new NetworkController() - networkController.initializeProvider(networkControllerProviderInit, provider) + networkController.initializeProvider(networkControllerProviderConfig) }) afterEach(function () { @@ -38,7 +34,7 @@ describe('# Network Controller', function () { describe('network', function () { describe('#provider', function () { it('provider should be updatable without reassignment', function () { - networkController.initializeProvider(networkControllerProviderInit, provider) + networkController.initializeProvider(networkControllerProviderConfig) const proxy = networkController._proxy proxy.setTarget({ test: true, on: () => {} }) assert.ok(proxy.test) @@ -59,12 +55,6 @@ describe('# Network Controller', function () { }) }) - describe('#getRpcAddressForType', function () { - it('should return the right rpc address', function () { - const rpcTarget = networkController.getRpcAddressForType('mainnet') - assert.equal(rpcTarget, 'https://mainnet.infura.io/metamask', 'returns the right rpcAddress') - }) - }) describe('#setProviderType', function () { it('should update provider.type', function () { networkController.setProviderType('mainnet') @@ -76,16 +66,11 @@ describe('# Network Controller', function () { const loading = networkController.isNetworkLoading() assert.ok(loading, 'network is loading') }) - it('should set the right rpcTarget', function () { - networkController.setProviderType('mainnet') - const rpcTarget = networkController.getProviderConfig().rpcTarget - assert.equal(rpcTarget, 'https://mainnet.infura.io/metamask', 'returns the right rpcAddress') - }) }) }) }) -describe('# Network utils', () => { +describe('Network utils', () => { it('getNetworkDisplayName should return the correct network name', () => { const tests = [ { @@ -114,9 +99,4 @@ describe('# Network utils', () => { tests.forEach(({ input, expected }) => assert.equal(getNetworkDisplayName(input), expected)) }) - - it('getNetworkEndpoints should return the correct endpoints', () => { - assert.equal(getNetworkEndpoints('networkBeta').ropsten, 'https://ropsten.infura.io/metamask2') - assert.equal(getNetworkEndpoints('network').rinkeby, 'https://rinkeby.infura.io/metamask') - }) }) From a1d13d45cf7451162b071e5507f1e31b12574e6e Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 2 May 2018 18:23:55 -0700 Subject: [PATCH 07/18] lint - cleanup some unused variables --- app/scripts/controllers/network/util.js | 1 - old-ui/app/app.js | 1 - ui/app/components/pages/settings/settings.js | 1 - ui/app/components/pages/unlock.js | 1 - ui/app/first-time/init-menu.js | 1 - ui/app/select-app.js | 1 - ui/app/unlock.js | 1 - ui/index.js | 8 -------- 8 files changed, 15 deletions(-) diff --git a/app/scripts/controllers/network/util.js b/app/scripts/controllers/network/util.js index a14fddea7..261dae721 100644 --- a/app/scripts/controllers/network/util.js +++ b/app/scripts/controllers/network/util.js @@ -3,7 +3,6 @@ const { RINKEBY, KOVAN, MAINNET, - LOCALHOST, ROPSTEN_CODE, RINKEYBY_CODE, KOVAN_CODE, diff --git a/old-ui/app/app.js b/old-ui/app/app.js index fe5e57d93..2378a1a0a 100644 --- a/old-ui/app/app.js +++ b/old-ui/app/app.js @@ -35,7 +35,6 @@ const HDCreateVaultComplete = require('./keychains/hd/create-vault-complete') const HDRestoreVaultScreen = require('./keychains/hd/restore-vault') const RevealSeedConfirmation = require('./keychains/hd/recover-seed/confirmation') const AccountDropdowns = require('./components/account-dropdowns').AccountDropdowns -const { BETA_UI_NETWORK_TYPE } = require('../../app/scripts/controllers/network/enums') module.exports = connect(mapStateToProps)(App) diff --git a/ui/app/components/pages/settings/settings.js b/ui/app/components/pages/settings/settings.js index e5725c0ca..f58ac7ddf 100644 --- a/ui/app/components/pages/settings/settings.js +++ b/ui/app/components/pages/settings/settings.js @@ -12,7 +12,6 @@ const SimpleDropdown = require('../../dropdowns/simple-dropdown') const ToggleButton = require('react-toggle-button') const { REVEAL_SEED_ROUTE } = require('../../../routes') const locales = require('../../../../../app/_locales/index.json') -const { OLD_UI_NETWORK_TYPE } = require('../../../../../app/scripts/controllers/network/enums') const getInfuraCurrencyOptions = () => { const sortedCurrencies = infuraCurrencies.objects.sort((a, b) => { diff --git a/ui/app/components/pages/unlock.js b/ui/app/components/pages/unlock.js index bbdb17306..ac541dad7 100644 --- a/ui/app/components/pages/unlock.js +++ b/ui/app/components/pages/unlock.js @@ -15,7 +15,6 @@ const { getEnvironmentType } = require('../../../../app/scripts/lib/util') const getCaretCoordinates = require('textarea-caret') const EventEmitter = require('events').EventEmitter const Mascot = require('../mascot') -const { OLD_UI_NETWORK_TYPE } = require('../../../../app/scripts/controllers/network/enums') const { DEFAULT_ROUTE, RESTORE_VAULT_ROUTE } = require('../../routes') class UnlockScreen extends Component { diff --git a/ui/app/first-time/init-menu.js b/ui/app/first-time/init-menu.js index 7b02d7fd6..c20ba2d77 100644 --- a/ui/app/first-time/init-menu.js +++ b/ui/app/first-time/init-menu.js @@ -10,7 +10,6 @@ const getCaretCoordinates = require('textarea-caret') const { RESTORE_VAULT_ROUTE, DEFAULT_ROUTE } = require('../routes') const { getEnvironmentType } = require('../../../app/scripts/lib/util') const { ENVIRONMENT_TYPE_POPUP } = require('../../../app/scripts/lib/enums') -const { OLD_UI_NETWORK_TYPE } = require('../../../app/scripts/controllers/network/enums') class InitializeMenuScreen extends Component { constructor (props) { diff --git a/ui/app/select-app.js b/ui/app/select-app.js index 6611fea09..f2e8e8d10 100644 --- a/ui/app/select-app.js +++ b/ui/app/select-app.js @@ -7,7 +7,6 @@ const App = require('./app') const OldApp = require('../../old-ui/app/app') const { autoAddToBetaUI } = require('./selectors') const { setFeatureFlag } = require('./actions') -const { BETA_UI_NETWORK_TYPE } = require('../../app/scripts/controllers/network/enums') const I18nProvider = require('./i18n-provider') function mapStateToProps (state) { diff --git a/ui/app/unlock.js b/ui/app/unlock.js index bcc24c3b0..d7983654e 100644 --- a/ui/app/unlock.js +++ b/ui/app/unlock.js @@ -6,7 +6,6 @@ const connect = require('react-redux').connect const actions = require('./actions') const getCaretCoordinates = require('textarea-caret') const EventEmitter = require('events').EventEmitter -const { OLD_UI_NETWORK_TYPE } = require('../../app/scripts/controllers/network/enums') const { getEnvironmentType } = require('../../app/scripts/lib/util') const { ENVIRONMENT_TYPE_POPUP } = require('../../app/scripts/lib/enums') diff --git a/ui/index.js b/ui/index.js index d7cedd12d..bd9ecc28b 100644 --- a/ui/index.js +++ b/ui/index.js @@ -5,11 +5,6 @@ const actions = require('./app/actions') const configureStore = require('./app/store') const txHelper = require('./lib/tx-helper') const { fetchLocale } = require('./i18n-helper') -const { - OLD_UI_NETWORK_TYPE, - BETA_UI_NETWORK_TYPE, -} = require('../app/scripts/controllers/network/enums') - const log = require('loglevel') module.exports = launchMetamaskUi @@ -55,9 +50,6 @@ async function startApp (metamaskState, accountManager, opts) { networkVersion: opts.networkVersion, }) - const useBetaUi = metamaskState.featureFlags.betaUI - const networkEndpointType = useBetaUi ? BETA_UI_NETWORK_TYPE : OLD_UI_NETWORK_TYPE - // if unconfirmed txs, start on txConf page const unapprovedTxsAll = txHelper(metamaskState.unapprovedTxs, metamaskState.unapprovedMsgs, metamaskState.unapprovedPersonalMsgs, metamaskState.unapprovedTypedMessages, metamaskState.network) const numberOfUnapprivedTx = unapprovedTxsAll.length From 9026651224f03069d3ab80cef5fe1386f9d7a532 Mon Sep 17 00:00:00 2001 From: Csaba Solya Date: Thu, 10 May 2018 13:26:02 +0200 Subject: [PATCH 08/18] add time stamps to transaction history log entries --- .../lib/tx-state-history-helper.js | 21 ++- .../transactions/tx-state-manager.js | 23 ++- test/unit/tx-state-history-helper-test.js | 139 +++++++++++++++--- test/unit/tx-state-history-helper.js | 46 ------ test/unit/tx-state-manager-test.js | 9 +- 5 files changed, 157 insertions(+), 81 deletions(-) delete mode 100644 test/unit/tx-state-history-helper.js diff --git a/app/scripts/controllers/transactions/lib/tx-state-history-helper.js b/app/scripts/controllers/transactions/lib/tx-state-history-helper.js index 59a4b562c..bb51c9871 100644 --- a/app/scripts/controllers/transactions/lib/tx-state-history-helper.js +++ b/app/scripts/controllers/transactions/lib/tx-state-history-helper.js @@ -25,26 +25,31 @@ function migrateFromSnapshotsToDiffs (longHistory) { } /** - generates an array of history objects sense the previous state. - The object has the keys opp(the operation preformed), - path(the key and if a nested object then each key will be seperated with a `/`) - value - with the first entry having the note + Generates an array of history objects sense the previous state. + The object has the keys + op (the operation performed), + path (the key and if a nested object then each key will be seperated with a `/`) + value + with the first entry having the note and a timestamp when the change took place @param previousState {object} - the previous state of the object @param newState {object} - the update object @param note {string} - a optional note for the state change - @reurns {array} + @returns {array} */ function generateHistoryEntry (previousState, newState, note) { const entry = jsonDiffer.compare(previousState, newState) // Add a note to the first op, since it breaks if we append it to the entry - if (note && entry[0]) entry[0].note = note + if (entry[0]) { + if (note) entry[0].note = note + + entry[0].timestamp = (new Date()).getTime() + } return entry } /** Recovers previous txMeta state obj - @return {object} + @returns {object} */ function replayHistory (_shortHistory) { const shortHistory = clone(_shortHistory) diff --git a/app/scripts/controllers/transactions/tx-state-manager.js b/app/scripts/controllers/transactions/tx-state-manager.js index 380214c1d..0aae4774b 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') @@ -158,7 +159,7 @@ class TransactionStateManager extends EventEmitter { /** updates the txMeta in the list and adds a history entry @param txMeta {Object} - the txMeta to update - @param [note] {string} - a not about the update for history + @param [note] {string} - a note about the update for history */ updateTx (txMeta, note) { // validate txParams @@ -398,13 +399,19 @@ 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(() => { + 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) + } + }) } /** diff --git a/test/unit/tx-state-history-helper-test.js b/test/unit/tx-state-history-helper-test.js index 35e9ef188..5ad014dbb 100644 --- a/test/unit/tx-state-history-helper-test.js +++ b/test/unit/tx-state-history-helper-test.js @@ -1,26 +1,129 @@ const assert = require('assert') -const clone = require('clone') const txStateHistoryHelper = require('../../app/scripts/controllers/transactions/lib/tx-state-history-helper') +const testVault = require('../data/v17-long-history.json') -describe('deepCloneFromTxMeta', function () { - it('should clone deep', function () { - const input = { - foo: { - bar: { - bam: 'baz' +describe ('Transaction state history helper', function () { + + describe('#snapshotFromTxMeta', function () { + it('should clone deep', function () { + const input = { + foo: { + bar: { + bam: 'baz' + } } } - } - const output = txStateHistoryHelper.snapshotFromTxMeta(input) - assert('foo' in output, 'has a foo key') - assert('bar' in output.foo, 'has a bar key') - assert('bam' in output.foo.bar, 'has a bar key') - assert.equal(output.foo.bar.bam, 'baz', 'has a baz value') + const output = txStateHistoryHelper.snapshotFromTxMeta(input) + assert('foo' in output, 'has a foo key') + assert('bar' in output.foo, 'has a bar key') + assert('bam' in output.foo.bar, 'has a bar key') + assert.equal(output.foo.bar.bam, 'baz', 'has a baz value') + }) + + it('should remove the history key', function () { + const input = { foo: 'bar', history: 'remembered' } + const output = txStateHistoryHelper.snapshotFromTxMeta(input) + assert(typeof output.history, 'undefined', 'should remove history') + }) }) - it('should remove the history key', function () { - const input = { foo: 'bar', history: 'remembered' } - const output = txStateHistoryHelper.snapshotFromTxMeta(input) - assert(typeof output.history, 'undefined', 'should remove history') + describe('#migrateFromSnapshotsToDiffs', function () { + it('migrates history to diffs and can recover original values', function () { + testVault.data.TransactionController.transactions.forEach((tx, index) => { + const newHistory = txStateHistoryHelper.migrateFromSnapshotsToDiffs(tx.history) + newHistory.forEach((newEntry, index) => { + if (index === 0) { + assert.equal(Array.isArray(newEntry), false, 'initial history item IS NOT a json patch obj') + } else { + assert.equal(Array.isArray(newEntry), true, 'non-initial history entry IS a json patch obj') + } + const oldEntry = tx.history[index] + const historySubset = newHistory.slice(0, index + 1) + const reconstructedValue = txStateHistoryHelper.replayHistory(historySubset) + assert.deepEqual(oldEntry, reconstructedValue, 'was able to reconstruct old entry from diffs') + }) + }) + }) + }) + + describe('#replayHistory', function () { + it('replaying history does not mutate the original obj', function () { + const initialState = { test: true, message: 'hello', value: 1 } + const diff1 = [{ + "op": "replace", + "path": "/message", + "value": "haay", + }] + const diff2 = [{ + "op": "replace", + "path": "/value", + "value": 2, + }] + const history = [initialState, diff1, diff2] + + const beforeStateSnapshot = JSON.stringify(initialState) + const latestState = txStateHistoryHelper.replayHistory(history) + const afterStateSnapshot = JSON.stringify(initialState) + + assert.notEqual(initialState, latestState, 'initial state is not the same obj as the latest state') + assert.equal(beforeStateSnapshot, afterStateSnapshot, 'initial state is not modified during run') + }) + }) + + describe('#generateHistoryEntry', function () { + + function generateHistoryEntryTest(note) { + + const prevState = { + someValue: 'value 1', + foo: { + bar: { + bam: 'baz' + } + } + } + + const nextState = { + newPropRoot: 'new property - root', + someValue: 'value 2', + foo: { + newPropFirstLevel: 'new property - first level', + bar: { + bam: 'baz' + } + } + } + + const before = new Date().getTime() + const result = txStateHistoryHelper.generateHistoryEntry(prevState, nextState, note) + const after = new Date().getTime() + + assert.ok(Array.isArray(result)) + assert.equal(result.length, 3) + + const expectedEntry1 = { op: 'add', path: '/foo/newPropFirstLevel', value: 'new property - first level' } + assert.equal(result[0].op, expectedEntry1.op) + assert.equal(result[0].path, expectedEntry1.path) + assert.equal(result[0].value, expectedEntry1.value) + assert.equal(result[0].value, expectedEntry1.value) + if (note) + assert.equal(result[0].note, note) + + assert.ok(result[0].timestamp >= before && result[0].timestamp <= after) + + const expectedEntry2 = { op: 'replace', path: '/someValue', value: 'value 2' } + assert.deepEqual(result[1], expectedEntry2) + + const expectedEntry3 = { op: 'add', path: '/newPropRoot', value: 'new property - root' } + assert.deepEqual(result[2], expectedEntry3) + } + + it('should generate history entries', function () { + generateHistoryEntryTest() + }) + + it('should add note to first entry', function () { + generateHistoryEntryTest('custom note') + }) }) -}) +}) \ No newline at end of file diff --git a/test/unit/tx-state-history-helper.js b/test/unit/tx-state-history-helper.js deleted file mode 100644 index 35f7dac57..000000000 --- a/test/unit/tx-state-history-helper.js +++ /dev/null @@ -1,46 +0,0 @@ -const assert = require('assert') -const txStateHistoryHelper = require('../../app/scripts/controllers/transactions/lib/tx-state-history-helper') -const testVault = require('../data/v17-long-history.json') - - -describe('tx-state-history-helper', function () { - it('migrates history to diffs and can recover original values', function () { - testVault.data.TransactionController.transactions.forEach((tx, index) => { - const newHistory = txStateHistoryHelper.migrateFromSnapshotsToDiffs(tx.history) - newHistory.forEach((newEntry, index) => { - if (index === 0) { - assert.equal(Array.isArray(newEntry), false, 'initial history item IS NOT a json patch obj') - } else { - assert.equal(Array.isArray(newEntry), true, 'non-initial history entry IS a json patch obj') - } - const oldEntry = tx.history[index] - const historySubset = newHistory.slice(0, index + 1) - const reconstructedValue = txStateHistoryHelper.replayHistory(historySubset) - assert.deepEqual(oldEntry, reconstructedValue, 'was able to reconstruct old entry from diffs') - }) - }) - }) - - it('replaying history does not mutate the original obj', function () { - const initialState = { test: true, message: 'hello', value: 1 } - const diff1 = [{ - "op": "replace", - "path": "/message", - "value": "haay", - }] - const diff2 = [{ - "op": "replace", - "path": "/value", - "value": 2, - }] - const history = [initialState, diff1, diff2] - - const beforeStateSnapshot = JSON.stringify(initialState) - const latestState = txStateHistoryHelper.replayHistory(history) - const afterStateSnapshot = JSON.stringify(initialState) - - assert.notEqual(initialState, latestState, 'initial state is not the same obj as the latest state') - assert.equal(beforeStateSnapshot, afterStateSnapshot, 'initial state is not modified during run') - }) - -}) diff --git a/test/unit/tx-state-manager-test.js b/test/unit/tx-state-manager-test.js index e5fe68d0b..179542f90 100644 --- a/test/unit/tx-state-manager-test.js +++ b/test/unit/tx-state-manager-test.js @@ -176,14 +176,21 @@ describe('TransactionStateManager', function () { assert.deepEqual(updatedTx.history[0], txStateHistoryHelper.snapshotFromTxMeta(updatedTx), 'first history item is initial state') // modify value and updateTx updatedTx.txParams.gasPrice = desiredGasPrice + const before = new Date().getTime() txStateManager.updateTx(updatedTx) + const after = new Date().getTime() // check updated value const result = txStateManager.getTx('1') assert.equal(result.txParams.gasPrice, desiredGasPrice, 'gas price updated') // validate history was updated assert.equal(result.history.length, 2, 'two history items (initial + diff)') + assert.equal(result.history[1].length, 1, 'two history state items (initial + diff)') + const expectedEntry = { op: 'replace', path: '/txParams/gasPrice', value: desiredGasPrice } - assert.deepEqual(result.history[1], [expectedEntry], 'two history items (initial + diff)') + assert.deepEqual(result.history[1][0].op, expectedEntry.op, 'two history items (initial + diff) operation') + assert.deepEqual(result.history[1][0].path, expectedEntry.path, 'two history items (initial + diff) path') + assert.deepEqual(result.history[1][0].value, expectedEntry.value, 'two history items (initial + diff) value') + assert.ok(result.history[1][0].timestamp >= before && result.history[1][0].timestamp <= after) }) }) From 349fb9e0bcf873de4f63db2bc7a3452043223fde Mon Sep 17 00:00:00 2001 From: Csaba Solya Date: Thu, 10 May 2018 13:33:40 +0200 Subject: [PATCH 09/18] revert unnecessary change in state manager --- .../transactions/tx-state-manager.js | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/app/scripts/controllers/transactions/tx-state-manager.js b/app/scripts/controllers/transactions/tx-state-manager.js index 0aae4774b..33bb855c5 100644 --- a/app/scripts/controllers/transactions/tx-state-manager.js +++ b/app/scripts/controllers/transactions/tx-state-manager.js @@ -399,19 +399,13 @@ class TransactionStateManager extends EventEmitter { _setTxStatus (txId, status) { const txMeta = this.getTx(txId) txMeta.status = status - setTimeout(() => { - 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(`${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') } /** From 3642810584b262cf98f2576248392a389292831f Mon Sep 17 00:00:00 2001 From: Csaba Solya Date: Thu, 10 May 2018 13:34:56 +0200 Subject: [PATCH 10/18] remove unnecessary lib --- app/scripts/controllers/transactions/tx-state-manager.js | 1 - 1 file changed, 1 deletion(-) diff --git a/app/scripts/controllers/transactions/tx-state-manager.js b/app/scripts/controllers/transactions/tx-state-manager.js index 33bb855c5..7b6b52432 100644 --- a/app/scripts/controllers/transactions/tx-state-manager.js +++ b/app/scripts/controllers/transactions/tx-state-manager.js @@ -2,7 +2,6 @@ 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 2081768fc5881151c1035236fdb4cb65b1a5f6be Mon Sep 17 00:00:00 2001 From: Csaba Solya Date: Thu, 10 May 2018 13:43:31 +0200 Subject: [PATCH 11/18] fix lint issues --- .../controllers/transactions/lib/tx-state-history-helper.js | 2 +- app/scripts/controllers/transactions/tx-state-manager.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/scripts/controllers/transactions/lib/tx-state-history-helper.js b/app/scripts/controllers/transactions/lib/tx-state-history-helper.js index bb51c9871..4d8f4baa4 100644 --- a/app/scripts/controllers/transactions/lib/tx-state-history-helper.js +++ b/app/scripts/controllers/transactions/lib/tx-state-history-helper.js @@ -26,7 +26,7 @@ function migrateFromSnapshotsToDiffs (longHistory) { /** Generates an array of history objects sense the previous state. - The object has the keys + The object has the keys op (the operation performed), path (the key and if a nested object then each key will be seperated with a `/`) value diff --git a/app/scripts/controllers/transactions/tx-state-manager.js b/app/scripts/controllers/transactions/tx-state-manager.js index 7b6b52432..00e837571 100644 --- a/app/scripts/controllers/transactions/tx-state-manager.js +++ b/app/scripts/controllers/transactions/tx-state-manager.js @@ -401,7 +401,7 @@ class TransactionStateManager extends EventEmitter { 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(`${txMeta.id}:finished`, txMeta) } this.updateTx(txMeta, `txStateManager: setting status to ${status}`) this.emit('update:badge') From 5561937773b4e59e3df9df385693680e17e6b8c0 Mon Sep 17 00:00:00 2001 From: Alexander Tseung Date: Mon, 14 May 2018 14:34:10 -0700 Subject: [PATCH 12/18] Fix account and network dropdowns in confirm screen --- ui/app/app.js | 13 +----- .../app-header/app-header.component.js | 44 ++++++++++++++++--- .../pending-tx/confirm-send-ether.js | 14 +++++- ui/app/css/itcss/components/account-menu.scss | 4 ++ ui/app/css/itcss/components/header.scss | 4 -- 5 files changed, 58 insertions(+), 21 deletions(-) diff --git a/ui/app/app.js b/ui/app/app.js index 5bc571c64..f840cc34e 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -1,7 +1,7 @@ const { Component } = require('react') const PropTypes = require('prop-types') const connect = require('react-redux').connect -const { Route, Switch, withRouter, matchPath } = require('react-router-dom') +const { Route, Switch, withRouter } = require('react-router-dom') const { compose } = require('recompose') const h = require('react-hyperscript') const actions = require('./actions') @@ -83,15 +83,6 @@ class App extends Component { ) } - renderAppHeader () { - const { location } = this.props - const isInitializing = matchPath(location.pathname, { - path: INITIALIZE_ROUTE, exact: false, - }) - - return isInitializing ? null : h(AppHeader) - } - render () { const { isLoading, @@ -128,7 +119,7 @@ class App extends Component { // global modal h(Modal, {}, []), - this.renderAppHeader(), + h(AppHeader), // sidebar this.renderSidebar(), diff --git a/ui/app/components/app-header/app-header.component.js b/ui/app/components/app-header/app-header.component.js index cf36e0d79..62b04562a 100644 --- a/ui/app/components/app-header/app-header.component.js +++ b/ui/app/components/app-header/app-header.component.js @@ -1,9 +1,13 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' import classnames from 'classnames' +import { matchPath } from 'react-router-dom' -const { ENVIRONMENT_TYPE_NOTIFICATION } = require('../../../../app/scripts/lib/enums') -const { DEFAULT_ROUTE, CONFIRM_TRANSACTION_ROUTE } = require('../../routes') +const { + ENVIRONMENT_TYPE_NOTIFICATION, + ENVIRONMENT_TYPE_POPUP, +} = require('../../../../app/scripts/lib/enums') +const { DEFAULT_ROUTE, INITIALIZE_ROUTE, CONFIRM_TRANSACTION_ROUTE } = require('../../routes') const Identicon = require('../identicon') const NetworkIndicator = require('../network') @@ -36,13 +40,23 @@ class AppHeader extends Component { : hideNetworkDropdown() } + isConfirming () { + const { location } = this.props + + return Boolean(matchPath(location.pathname, { + path: CONFIRM_TRANSACTION_ROUTE, exact: false, + })) + } + renderAccountMenu () { const { isUnlocked, toggleAccountMenu, selectedAddress } = this.props return isUnlocked && (
this.isConfirming() || toggleAccountMenu()} > Date: Wed, 16 May 2018 12:33:26 -0230 Subject: [PATCH 13/18] Adds detailed QA checklist for the New UI send screen. --- docs/send-screen-QA-checklist.md | 90 ++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 docs/send-screen-QA-checklist.md diff --git a/docs/send-screen-QA-checklist.md b/docs/send-screen-QA-checklist.md new file mode 100644 index 000000000..8c60c3c6c --- /dev/null +++ b/docs/send-screen-QA-checklist.md @@ -0,0 +1,90 @@ +Send screen QA checklist: + +## Send Eth mode + - [ ] **Header** _It should:_ + - [ ] have title "Send ETH" + - [ ] have sub title "Only send ETH to an Ethereum address." + - [ ] return user to main screen when top right X is clicked + - [ ] **From row** _It should:_ + - [ ] show the currently selected account by default + - [ ] show a dropdown with all of the users accounts + - [ ] contain the following info for each account: identicon, account name, balance in ETH, balance in current currency + - [ ] change the account selected in the dropdown (but not the app-wide selected account) when one in the dropdown is clicked + - [ ] close the dropdown, without changing the dropdown selected account, when the dropdown is open and then a click happens outside it + - [ ] **To row** _It should:_ + - [ ] Show a placeholder with the text 'Recipient Address' by default + - [ ] Show, when clicked, a dropdown list of all 'to accounts': the users accounts, plus any other accounts they have previously sent to + - [ ] Show account address, and account name if it exists, of each item in the dropdown list + - [ ] Show a dropdown list of all to accounts (see above) whose address matches an address currently being typed in + - [ ] Set the input text to the address of an account clicked in the dropdown list, and also hide the dropdown + - [ ] Hide the dropdown without changing what is in the input if the user clicks outside the dropdown list while it is open + - [ ] Select the text in the input (i.e. the address) if an address is displayed and then clicked + - [ ] Show a 'required' error if the dropdown is opened but no account is selected + - [ ] Show an 'invalid address' error if text is entered in the input that cannot be a valid hex address or ens address + - [ ] Support ens names. (enter dinodan.eth on mainnet) After entering the plain text address, the hex address should appear in the input with a green checkmark beside + - [ ] Should show a 'no such address' error if a non-existent ens address is entered + - [ ] **Amount row** _It should:_ + - [ ] allow user to enter any rational number >= 0 + - [ ] allow user to copy and paste into the field + - [ ] show an insufficient funds error if an amount > balance - gas fee + - [ ] display 'ETH' after the number amount. The position of 'ETH' should change as the length of the input amount text changes + - [ ] display the value of the amount of ETH in the current currency, formatted in that currency + - [ ] show a 'max' but if amount < balance - gas fee + - [ ] show no max button or error if amount === balance - gas fee + - [ ] set the amount to balance - gas fee if the 'max' button is clicked + - [ ] **Gas Fee Display row** _It should:_ + - [ ] Default to the fee given by the estimated gas price + - [ ] display the fee in ETH and the current currency + - [ ] update when changes are made using the customize gas modal + - [ ] **Cancel button** _It should:_ + - [ ] Take the user back to the main screen + - [ ] **submit button** _It should:_ + - [ ] be disabled if no recipient address is provided or if any field is in error + - [ ] sign a transaction with the info in the above form, and display the details of that transaction on the confirm screen + +## Send token mode +- [ ] **Header** _It should:_ + - [ ] have title "Send Tokens" + - [ ] have sub title "Only send [token symbol] to an Ethereum address." + - [ ] return user to main screen when top right X is clicked +- [ ] **From row** _It should:_ + - [ ] Behave the same as 'Send ETH mode' (see above) +- [ ] **To row** _It should:_ + - [ ] Behave the same as 'Send ETH mode' (see above) +- [ ] **Amount row** _It should:_ + - [ ] allow user to enter any rational number >= 0 + - [ ] allow user to copy and paste into the field + - [ ] show an 'insufficient tokens' error if an amount > token balance + - [ ] show an 'insufficient funds' error if an gas fee > eth balance + - [ ] display [token symbol] after the number amount. The position of [token symbol] should change as the length of the input amount text changes + - [ ] display the value of the amount of tokens in the current currency, formatted in that currency + - [ ] show a 'max' but if amount < token balance + - [ ] show no max button or error if amount === token balance + - [ ] set the amount to token balance if the 'max' button is clicked +- [ ] **Gas Fee Display row** _It should:_ + - [ ] Behave the same as 'Send ETH mode' (see above) +- [ ] **Cancel button** _It should:_ + - [ ] Take the user back to the main screen +- [ ] **submit button** _It should:_ + - [ ] be disabled if no recipient address is provided or if any field is in error + - [ ] sign a token transaction with the info in the above form, and display the details of that transaction on the confirm screen + +## Edit send Eth mode + - [ ] Say 'Editing transaction' in the header + - [ ] display a button to go back to the confirmation screen without applying update + - [ ] say 'update transaction' on the submit button + - [ ] update the existing transaction, instead of signing a new one, when clicking the submit button + - [ ] Otherwise, behave the same as 'Send ETH mode' (see above) + +## Edit send token mode + - [ ] Behave the same as 'Edit send Eth mode' (see above) + +## Specific cases to test + - [ ] Send eth to a hex address + - [ ] Send eth to an ENS address + - [ ] Donate to the faucet at https://faucet.metamask.io/ and edit the transaction before confirming + - [ ] Send a token that is available on the 'Add Token' screen search to a hex address + - [ ] Create a custom token at https://tokenfactory.surge.sh/ and send it to a hex address + - [ ] Send a token to an ENS address + - [ ] Create a token transaction using https://tokenfactory.surge.sh/#/, and edit the transaction before confirming + - [ ] Send each of MKR, EOS and ICON using myetherwallet, and edit the transaction before confirming From 5a7e98b3a9a56fe355a26ef0433912dcf98d0461 Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 16 May 2018 12:45:06 -0230 Subject: [PATCH 14/18] Adds description to send-screen-QA-checklist.md --- docs/send-screen-QA-checklist.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/send-screen-QA-checklist.md b/docs/send-screen-QA-checklist.md index 8c60c3c6c..52167b50b 100644 --- a/docs/send-screen-QA-checklist.md +++ b/docs/send-screen-QA-checklist.md @@ -1,4 +1,10 @@ -Send screen QA checklist: +# Send screen QA checklist: + +This checklist can be to guide QA of the send screen. It can also be used to guide e2e tests for the send screen. + +Once all of these are QA verified on master, resolutions to any bugs related to the send screen should include and update to this list. + +Additional features or functionality on the send screen should include an update to this list. ## Send Eth mode - [ ] **Header** _It should:_ From d62fc22611d7e7f83b1f983667b7bb16fa4c7c98 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 16 May 2018 11:59:50 -0700 Subject: [PATCH 15/18] network - remove debugging console.log --- app/scripts/controllers/network/network.js | 1 - 1 file changed, 1 deletion(-) diff --git a/app/scripts/controllers/network/network.js b/app/scripts/controllers/network/network.js index 5496f8a68..93fde7c57 100644 --- a/app/scripts/controllers/network/network.js +++ b/app/scripts/controllers/network/network.js @@ -34,7 +34,6 @@ module.exports = class NetworkController extends EventEmitter { // parse options const providerConfig = opts.provider || defaultProviderConfig - console.log('providerStore:', providerConfig) // create stores this.providerStore = new ObservableStore(providerConfig) this.networkStore = new ObservableStore('loading') From c6f822ad45e91e4610bfea32dcfd40ca01576e5a Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 16 May 2018 12:29:57 -0700 Subject: [PATCH 16/18] ui - remove files accidently added by bad merge --- ui/app/components/pages/unlock.js | 189 ------------------------------ ui/app/unlock.js | 139 ---------------------- 2 files changed, 328 deletions(-) delete mode 100644 ui/app/components/pages/unlock.js delete mode 100644 ui/app/unlock.js diff --git a/ui/app/components/pages/unlock.js b/ui/app/components/pages/unlock.js deleted file mode 100644 index ac541dad7..000000000 --- a/ui/app/components/pages/unlock.js +++ /dev/null @@ -1,189 +0,0 @@ -const { Component } = require('react') -const PropTypes = require('prop-types') -const connect = require('../../metamask-connect') -const h = require('react-hyperscript') -const { withRouter } = require('react-router-dom') -const { compose } = require('recompose') -const { - tryUnlockMetamask, - forgotPassword, - markPasswordForgotten, - setFeatureFlag, -} = require('../../actions') -const { ENVIRONMENT_TYPE_POPUP } = require('../../../../app/scripts/lib/enums') -const { getEnvironmentType } = require('../../../../app/scripts/lib/util') -const getCaretCoordinates = require('textarea-caret') -const EventEmitter = require('events').EventEmitter -const Mascot = require('../mascot') -const { DEFAULT_ROUTE, RESTORE_VAULT_ROUTE } = require('../../routes') - -class UnlockScreen extends Component { - constructor (props) { - super(props) - - this.state = { - error: null, - } - - this.animationEventEmitter = new EventEmitter() - } - - componentWillMount () { - const { isUnlocked, history } = this.props - - if (isUnlocked) { - history.push(DEFAULT_ROUTE) - } - } - - componentDidMount () { - const passwordBox = document.getElementById('password-box') - - if (passwordBox) { - passwordBox.focus() - } - } - - tryUnlockMetamask (password) { - const { tryUnlockMetamask, history } = this.props - tryUnlockMetamask(password) - .then(() => history.push(DEFAULT_ROUTE)) - .catch(({ message }) => this.setState({ error: message })) - } - - onSubmit (event) { - const input = document.getElementById('password-box') - const password = input.value - this.tryUnlockMetamask(password) - } - - onKeyPress (event) { - if (event.key === 'Enter') { - this.submitPassword(event) - } - } - - submitPassword (event) { - var element = event.target - var password = element.value - // reset input - element.value = '' - this.tryUnlockMetamask(password) - } - - inputChanged (event) { - // tell mascot to look at page action - var element = event.target - var boundingRect = element.getBoundingClientRect() - var coordinates = getCaretCoordinates(element, element.selectionEnd) - this.animationEventEmitter.emit('point', { - x: boundingRect.left + coordinates.left - element.scrollLeft, - y: boundingRect.top + coordinates.top - element.scrollTop, - }) - } - - render () { - const { error } = this.state - return ( - h('.unlock-screen', [ - - h(Mascot, { - animationEventEmitter: this.animationEventEmitter, - }), - - h('h1', { - style: { - fontSize: '1.4em', - textTransform: 'uppercase', - color: '#7F8082', - }, - }, this.props.t('appName')), - - h('input.large-input', { - type: 'password', - id: 'password-box', - placeholder: 'enter password', - style: { - background: 'white', - }, - onKeyPress: this.onKeyPress.bind(this), - onInput: this.inputChanged.bind(this), - }), - - h('.error', { - style: { - display: error ? 'block' : 'none', - padding: '0 20px', - textAlign: 'center', - }, - }, error), - - h('button.primary.cursor-pointer', { - onClick: this.onSubmit.bind(this), - style: { - margin: 10, - }, - }, this.props.t('login')), - - h('p.pointer', { - onClick: () => { - this.props.markPasswordForgotten() - this.props.history.push(RESTORE_VAULT_ROUTE) - - if (getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_POPUP) { - global.platform.openExtensionInBrowser() - } - }, - style: { - fontSize: '0.8em', - color: 'rgb(247, 134, 28)', - textDecoration: 'underline', - }, - }, this.props.t('restoreFromSeed')), - - h('p.pointer', { - onClick: () => { - this.props.useOldInterface() - }, - style: { - fontSize: '0.8em', - color: '#aeaeae', - textDecoration: 'underline', - marginTop: '32px', - }, - }, this.props.t('classicInterface')), - ]) - ) - } -} - -UnlockScreen.propTypes = { - forgotPassword: PropTypes.func, - tryUnlockMetamask: PropTypes.func, - markPasswordForgotten: PropTypes.func, - history: PropTypes.object, - isUnlocked: PropTypes.bool, - t: PropTypes.func, - useOldInterface: PropTypes.func, -} - -const mapStateToProps = state => { - const { metamask: { isUnlocked } } = state - return { - isUnlocked, - } -} - -const mapDispatchToProps = dispatch => { - return { - forgotPassword: () => dispatch(forgotPassword()), - tryUnlockMetamask: password => dispatch(tryUnlockMetamask(password)), - markPasswordForgotten: () => dispatch(markPasswordForgotten()), - useOldInterface: () => dispatch(setFeatureFlag('betaUI', false, 'OLD_UI_NOTIFICATION_MODAL')), - } -} - -module.exports = compose( - withRouter, - connect(mapStateToProps, mapDispatchToProps) -)(UnlockScreen) diff --git a/ui/app/unlock.js b/ui/app/unlock.js deleted file mode 100644 index d7983654e..000000000 --- a/ui/app/unlock.js +++ /dev/null @@ -1,139 +0,0 @@ -const inherits = require('util').inherits -const Component = require('react').Component -const PropTypes = require('prop-types') -const h = require('react-hyperscript') -const connect = require('react-redux').connect -const actions = require('./actions') -const getCaretCoordinates = require('textarea-caret') -const EventEmitter = require('events').EventEmitter -const { getEnvironmentType } = require('../../app/scripts/lib/util') -const { ENVIRONMENT_TYPE_POPUP } = require('../../app/scripts/lib/enums') - -const Mascot = require('./components/mascot') - -UnlockScreen.contextTypes = { - t: PropTypes.func, -} - -module.exports = connect(mapStateToProps)(UnlockScreen) - - -inherits(UnlockScreen, Component) -function UnlockScreen () { - Component.call(this) - this.animationEventEmitter = new EventEmitter() -} - -function mapStateToProps (state) { - return { - warning: state.appState.warning, - } -} - -UnlockScreen.prototype.render = function () { - const state = this.props - const warning = state.warning - return ( - h('.unlock-screen', [ - - h(Mascot, { - animationEventEmitter: this.animationEventEmitter, - }), - - h('h1', { - style: { - fontSize: '1.4em', - textTransform: 'uppercase', - color: '#7F8082', - }, - }, this.context.t('appName')), - - h('input.large-input', { - type: 'password', - id: 'password-box', - placeholder: 'enter password', - style: { - background: 'white', - }, - onKeyPress: this.onKeyPress.bind(this), - onInput: this.inputChanged.bind(this), - }), - - h('.error', { - style: { - display: warning ? 'block' : 'none', - padding: '0 20px', - textAlign: 'center', - }, - }, warning), - - h('button.primary.cursor-pointer', { - onClick: this.onSubmit.bind(this), - style: { - margin: 10, - }, - }, this.context.t('login')), - - h('p.pointer', { - onClick: () => { - this.props.dispatch(actions.markPasswordForgotten()) - if (getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_POPUP) { - global.platform.openExtensionInBrowser() - } - }, - style: { - fontSize: '0.8em', - color: 'rgb(247, 134, 28)', - textDecoration: 'underline', - }, - }, this.context.t('restoreFromSeed')), - - h('p.pointer', { - onClick: () => { - this.props.dispatch(actions.setFeatureFlag('betaUI', false, 'OLD_UI_NOTIFICATION_MODAL')) - }, - style: { - fontSize: '0.8em', - color: '#aeaeae', - textDecoration: 'underline', - marginTop: '32px', - }, - }, this.context.t('classicInterface')), - ]) - ) -} - -UnlockScreen.prototype.componentDidMount = function () { - document.getElementById('password-box').focus() -} - -UnlockScreen.prototype.onSubmit = function (event) { - const input = document.getElementById('password-box') - const password = input.value - this.props.dispatch(actions.tryUnlockMetamask(password)) -} - -UnlockScreen.prototype.onKeyPress = function (event) { - if (event.key === 'Enter') { - this.submitPassword(event) - } -} - -UnlockScreen.prototype.submitPassword = function (event) { - var element = event.target - var password = element.value - // reset input - element.value = '' - this.props.dispatch(actions.tryUnlockMetamask(password)) -} - -UnlockScreen.prototype.inputChanged = function (event) { - // tell mascot to look at page action - var element = event.target - var boundingRect = element.getBoundingClientRect() - var coordinates = getCaretCoordinates(element, element.selectionEnd) - this.animationEventEmitter.emit('point', { - x: boundingRect.left + coordinates.left - element.scrollLeft, - y: boundingRect.top + coordinates.top - element.scrollTop, - }) -} From ff91ef96ef1f71c22dd66ea4140b1b211c033641 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 16 May 2018 12:35:43 -0700 Subject: [PATCH 17/18] ui - unlock - remove setNetworkEndpoints calls from new unlock screen --- ui/app/components/pages/unlock-page/unlock-page.component.js | 1 - ui/app/components/pages/unlock-page/unlock-page.container.js | 2 -- 2 files changed, 3 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 d5e2a3224..0976d9506 100644 --- a/ui/app/components/pages/unlock-page/unlock-page.component.js +++ b/ui/app/components/pages/unlock-page/unlock-page.component.js @@ -175,7 +175,6 @@ UnlockPage.propTypes = { isUnlocked: PropTypes.bool, t: PropTypes.func, useOldInterface: PropTypes.func, - setNetworkEndpoints: PropTypes.func, } export default UnlockPage diff --git a/ui/app/components/pages/unlock-page/unlock-page.container.js b/ui/app/components/pages/unlock-page/unlock-page.container.js index 9788a18ea..18fed9b2e 100644 --- a/ui/app/components/pages/unlock-page/unlock-page.container.js +++ b/ui/app/components/pages/unlock-page/unlock-page.container.js @@ -6,7 +6,6 @@ const { tryUnlockMetamask, forgotPassword, markPasswordForgotten, - setNetworkEndpoints, } = require('../../../actions') import UnlockPage from './unlock-page.component' @@ -23,7 +22,6 @@ const mapDispatchToProps = dispatch => { forgotPassword: () => dispatch(forgotPassword()), tryUnlockMetamask: password => dispatch(tryUnlockMetamask(password)), markPasswordForgotten: () => dispatch(markPasswordForgotten()), - setNetworkEndpoints: type => dispatch(setNetworkEndpoints(type)), } } From 8e1cad5ff60a67117bd6802dce15345d7b2542a4 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 16 May 2018 13:05:07 -0700 Subject: [PATCH 18/18] tx-state-history-helper - use more readable Date.now method --- .../controllers/transactions/lib/tx-state-history-helper.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/controllers/transactions/lib/tx-state-history-helper.js b/app/scripts/controllers/transactions/lib/tx-state-history-helper.js index 4d8f4baa4..4562568e9 100644 --- a/app/scripts/controllers/transactions/lib/tx-state-history-helper.js +++ b/app/scripts/controllers/transactions/lib/tx-state-history-helper.js @@ -42,7 +42,7 @@ function generateHistoryEntry (previousState, newState, note) { if (entry[0]) { if (note) entry[0].note = note - entry[0].timestamp = (new Date()).getTime() + entry[0].timestamp = Date.now() } return entry }