From 4fea9d0cc2ec9c6914931d5e310665aca8e273b6 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Mon, 29 Apr 2019 03:48:40 -0230 Subject: Send metrics event from backend for on chain transaction failures (#6500) * Send metrics event from backend for on chain transaction failures * Passes state object to backEndMetaMetricsEvent, and adds getMetaMetricState selector --- app/scripts/metamask-controller.js | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'app/scripts/metamask-controller.js') diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 0506e3116..be2090f63 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -54,6 +54,7 @@ const EthQuery = require('eth-query') const ethUtil = require('ethereumjs-util') const sigUtil = require('eth-sig-util') const { AddressBookController } = require('gaba') +const backEndMetaMetricsEvent = require('./lib/backend-metametrics') module.exports = class MetamaskController extends EventEmitter { @@ -190,10 +191,26 @@ module.exports = class MetamaskController extends EventEmitter { }) this.txController.on('newUnapprovedTx', () => opts.showUnapprovedTx()) - this.txController.on(`tx:status-update`, (txId, status) => { + this.txController.on(`tx:status-update`, async (txId, status) => { if (status === 'confirmed' || status === 'failed') { const txMeta = this.txController.txStateManager.getTx(txId) this.platform.showTransactionNotification(txMeta) + + const { txReceipt } = txMeta + const participateInMetaMetrics = this.preferencesController.getParticipateInMetaMetrics() + if (txReceipt && txReceipt.status === '0x0' && participateInMetaMetrics) { + const metamaskState = await this.getState() + backEndMetaMetricsEvent(metamaskState, { + customVariables: { + errorMessage: txMeta.simulationFails.reason, + }, + eventOpts: { + category: 'backend', + action: 'Transactions', + name: 'On Chain Failure', + }, + }) + } } }) -- cgit v1.2.3 From 2845398c3d824e5da1830ba7905ffdbf8149cf9e Mon Sep 17 00:00:00 2001 From: kumavis Date: Sat, 4 May 2019 01:32:05 +0800 Subject: Refactor ProviderApprovalController to use rpc and publicConfigStore (#6410) * Ensure home screen does not render if there are unapproved txs (#6501) * Ensure that the confirm screen renders before the home screen if there are unapproved txs. * Only render confirm screen before home screen on mount. * inpage - revert _metamask api to isEnabled isApproved isUnlocked --- app/scripts/metamask-controller.js | 102 +++++++++++++++++++++++++++++-------- 1 file changed, 80 insertions(+), 22 deletions(-) (limited to 'app/scripts/metamask-controller.js') diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index be2090f63..7d666ae88 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -7,8 +7,10 @@ const EventEmitter = require('events') const pump = require('pump') const Dnode = require('dnode') +const pify = require('pify') const ObservableStore = require('obs-store') const ComposableObservableStore = require('./lib/ComposableObservableStore') +const createDnodeRemoteGetter = require('./lib/createDnodeRemoteGetter') const asStream = require('obs-store/lib/asStream') const AccountTracker = require('./lib/account-tracker') const RpcEngine = require('json-rpc-engine') @@ -87,7 +89,7 @@ module.exports = class MetamaskController extends EventEmitter { this.createVaultMutex = new Mutex() // network store - this.networkController = new NetworkController(initState.NetworkController, this.platform) + this.networkController = new NetworkController(initState.NetworkController) // preferences controller this.preferencesController = new PreferencesController({ @@ -235,15 +237,17 @@ module.exports = class MetamaskController extends EventEmitter { this.messageManager = new MessageManager() this.personalMessageManager = new PersonalMessageManager() this.typedMessageManager = new TypedMessageManager({ networkController: this.networkController }) - this.publicConfigStore = this.initPublicConfigStore() + + // ensure isClientOpenAndUnlocked is updated when memState updates + this.on('update', (memState) => { + this.isClientOpenAndUnlocked = memState.isUnlocked && this._isClientOpen + }) this.providerApprovalController = new ProviderApprovalController({ closePopup: opts.closePopup, keyringController: this.keyringController, openPopup: opts.openPopup, - platform: opts.platform, preferencesController: this.preferencesController, - publicConfigStore: this.publicConfigStore, }) this.store.updateStructure({ @@ -322,22 +326,32 @@ module.exports = class MetamaskController extends EventEmitter { * Constructor helper: initialize a public config store. * This store is used to make some config info available to Dapps synchronously. */ - initPublicConfigStore () { - // get init state + createPublicConfigStore ({ checkIsEnabled }) { + // subset of state for metamask inpage provider const publicConfigStore = new ObservableStore() - // memStore -> transform -> publicConfigStore - this.on('update', (memState) => { - this.isClientOpenAndUnlocked = memState.isUnlocked && this._isClientOpen + // setup memStore subscription hooks + this.on('update', updatePublicConfigStore) + updatePublicConfigStore(this.getState()) + + publicConfigStore.destroy = () => { + this.removeEventListener('update', updatePublicConfigStore) + } + + function updatePublicConfigStore (memState) { const publicState = selectPublicState(memState) publicConfigStore.putState(publicState) - }) + } - function selectPublicState (memState) { + function selectPublicState ({ isUnlocked, selectedAddress, network, completedOnboarding }) { + const isEnabled = checkIsEnabled() + const isReady = isUnlocked && isEnabled const result = { - selectedAddress: memState.isUnlocked ? memState.selectedAddress : undefined, - networkVersion: memState.network, - onboardingcomplete: memState.completedOnboarding, + isUnlocked, + isEnabled, + selectedAddress: isReady ? selectedAddress : undefined, + networkVersion: network, + onboardingcomplete: completedOnboarding, } return result } @@ -477,9 +491,10 @@ module.exports = class MetamaskController extends EventEmitter { signTypedMessage: nodeify(this.signTypedMessage, this), cancelTypedMessage: this.cancelTypedMessage.bind(this), - approveProviderRequest: providerApprovalController.approveProviderRequest.bind(providerApprovalController), + // provider approval + approveProviderRequestByOrigin: providerApprovalController.approveProviderRequestByOrigin.bind(providerApprovalController), + rejectProviderRequestByOrigin: providerApprovalController.rejectProviderRequestByOrigin.bind(providerApprovalController), clearApprovedOrigins: providerApprovalController.clearApprovedOrigins.bind(providerApprovalController), - rejectProviderRequest: providerApprovalController.rejectProviderRequest.bind(providerApprovalController), } } @@ -1296,8 +1311,9 @@ module.exports = class MetamaskController extends EventEmitter { // setup multiplexing const mux = setupMultiplex(connectionStream) // connect features - this.setupProviderConnection(mux.createStream('provider'), originDomain) - this.setupPublicConfig(mux.createStream('publicConfig')) + const publicApi = this.setupPublicApi(mux.createStream('publicApi'), originDomain) + this.setupProviderConnection(mux.createStream('provider'), originDomain, publicApi) + this.setupPublicConfig(mux.createStream('publicConfig'), originDomain) } /** @@ -1370,7 +1386,7 @@ module.exports = class MetamaskController extends EventEmitter { * @param {*} outStream - The stream to provide over. * @param {string} origin - The URI of the requesting resource. */ - setupProviderConnection (outStream, origin) { + setupProviderConnection (outStream, origin, publicApi) { // setup json rpc engine stack const engine = new RpcEngine() const provider = this.provider @@ -1390,6 +1406,11 @@ module.exports = class MetamaskController extends EventEmitter { engine.push(subscriptionManager.middleware) // watch asset engine.push(this.preferencesController.requestWatchAsset.bind(this.preferencesController)) + // requestAccounts + engine.push(this.providerApprovalController.createMiddleware({ + origin, + getSiteMetadata: publicApi && publicApi.getSiteMetadata, + })) // forward to metamask primary provider engine.push(providerAsMiddleware(provider)) @@ -1418,18 +1439,56 @@ module.exports = class MetamaskController extends EventEmitter { * * @param {*} outStream - The stream to provide public config over. */ - setupPublicConfig (outStream) { - const configStream = asStream(this.publicConfigStore) + setupPublicConfig (outStream, originDomain) { + const configStore = this.createPublicConfigStore({ + // check the providerApprovalController's approvedOrigins + checkIsEnabled: () => this.providerApprovalController.shouldExposeAccounts(originDomain), + }) + const configStream = asStream(configStore) + pump( configStream, outStream, (err) => { + configStore.destroy() configStream.destroy() if (err) log.error(err) } ) } + /** + * A method for providing our public api over a stream. + * This includes a method for setting site metadata like title and image + * + * @param {*} outStream - The stream to provide the api over. + */ + setupPublicApi (outStream, originDomain) { + const dnode = Dnode() + // connect dnode api to remote connection + pump( + outStream, + dnode, + outStream, + (err) => { + // report any error + if (err) log.error(err) + } + ) + + const getRemote = createDnodeRemoteGetter(dnode) + + const publicApi = { + // wrap with an await remote + getSiteMetadata: async () => { + const remote = await getRemote() + return await pify(remote.getSiteMetadata)() + }, + } + + return publicApi + } + /** * Handle a KeyringController update * @param {object} state the KC state @@ -1734,7 +1793,6 @@ module.exports = class MetamaskController extends EventEmitter { * Locks MetaMask */ setLocked () { - this.providerApprovalController.setLocked() return this.keyringController.setLocked() } } -- cgit v1.2.3 From 094e4cf555c698bfef50ca6679cd1e98f4ea9aa1 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Wed, 8 May 2019 17:21:33 -0230 Subject: Check for unused function arguments (#6583) * eslint: Check for unused function arguments * eslint: Ignore unused '_' in argument list Also allow any number of '_' e.g., '__' or '___' which is to be used sparingly * Remove and rename unused arguments --- app/scripts/metamask-controller.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'app/scripts/metamask-controller.js') diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 7d666ae88..b190dd452 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -1222,9 +1222,8 @@ module.exports = class MetamaskController extends EventEmitter { * with higher gas. * * @param {string} txId - The ID of the transaction to speed up. - * @param {Function} cb - The callback function called with a full state update. */ - async retryTransaction (txId, gasPrice, cb) { + async retryTransaction (txId, gasPrice) { await this.txController.retryTransaction(txId, gasPrice) const state = await this.getState() return state @@ -1237,7 +1236,7 @@ module.exports = class MetamaskController extends EventEmitter { * @param {string=} customGasPrice - the hex value to use for the cancel transaction * @returns {object} MetaMask state */ - async createCancelTransaction (originalTxId, customGasPrice, cb) { + async createCancelTransaction (originalTxId, customGasPrice) { try { await this.txController.createCancelTransaction(originalTxId, customGasPrice) const state = await this.getState() @@ -1247,7 +1246,7 @@ module.exports = class MetamaskController extends EventEmitter { } } - async createSpeedUpTransaction (originalTxId, customGasPrice, cb) { + async createSpeedUpTransaction (originalTxId, customGasPrice) { await this.txController.createSpeedUpTransaction(originalTxId, customGasPrice) const state = await this.getState() return state @@ -1463,7 +1462,7 @@ module.exports = class MetamaskController extends EventEmitter { * * @param {*} outStream - The stream to provide the api over. */ - setupPublicApi (outStream, originDomain) { + setupPublicApi (outStream) { const dnode = Dnode() // connect dnode api to remote connection pump( -- cgit v1.2.3 From 77d3bc252d5c4d223e9de3c6700750d1895bb257 Mon Sep 17 00:00:00 2001 From: bitpshr Date: Mon, 6 May 2019 12:12:52 -0400 Subject: feature: integrate gaba/PhishingController --- app/scripts/metamask-controller.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'app/scripts/metamask-controller.js') diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index b190dd452..447d8b626 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -28,7 +28,6 @@ const PreferencesController = require('./controllers/preferences') const CurrencyController = require('./controllers/currency') const ShapeShiftController = require('./controllers/shapeshift') const InfuraController = require('./controllers/infura') -const BlacklistController = require('./controllers/blacklist') const CachedBalancesController = require('./controllers/cached-balances') const RecentBlocksController = require('./controllers/recent-blocks') const MessageManager = require('./lib/message-manager') @@ -55,7 +54,10 @@ const HW_WALLETS_KEYRINGS = [TrezorKeyring.type, LedgerBridgeKeyring.type] const EthQuery = require('eth-query') const ethUtil = require('ethereumjs-util') const sigUtil = require('eth-sig-util') -const { AddressBookController } = require('gaba') +const { + AddressBookController, + PhishingController, +} = require('gaba') const backEndMetaMetricsEvent = require('./lib/backend-metametrics') @@ -112,8 +114,7 @@ module.exports = class MetamaskController extends EventEmitter { }) this.infuraController.scheduleInfuraNetworkCheck() - this.blacklistController = new BlacklistController() - this.blacklistController.scheduleUpdates() + this.phishingController = new PhishingController() // rpc provider this.initializeProvider() @@ -1301,7 +1302,7 @@ module.exports = class MetamaskController extends EventEmitter { */ setupUntrustedCommunication (connectionStream, originDomain) { // Check if new connection is blacklisted - if (this.blacklistController.checkForPhishing(originDomain)) { + if (this.phishingController.test(originDomain)) { log.debug('MetaMask - sending phishing warning for', originDomain) this.sendPhishingWarning(connectionStream, originDomain) return @@ -1781,11 +1782,11 @@ module.exports = class MetamaskController extends EventEmitter { */ /** - * Adds a domain to the {@link BlacklistController} whitelist + * Adds a domain to the PhishingController whitelist * @param {string} hostname the domain to whitelist */ whitelistPhishingDomain (hostname) { - return this.blacklistController.whitelistDomain(hostname) + return this.phishingController.bypass(hostname) } /** -- cgit v1.2.3 From 13be683701bc46d8f1bcbaa301e2b7f01a34e29c Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Thu, 9 May 2019 14:57:14 -0230 Subject: New settings custom rpc form (#6490) * Add networks tab to settings, with header. * Adds network list to settings network tab. * Adds form to settings networks tab and connects it to network list. * Network tab: form adding and editing working * Settings network form properly handles input errors * Add translations for settings network form * Clean up styles of settings network tab. * Add popup-view styles and behaviour to settings network tab. * Fix save button on settings network form * Adds 'Add Network' button and addMode to settings networks tab * Lint fix for settings networks tab addition * Fix navigation in settings networks tab. * Editing an rpcurl in networks tab does not create new network, just changes rpc of old * Fix layout of settings tabs other than network * Networks dropdown 'Custom Rpc' item links to networks tab in settings. * Update settings sidebar networks subheader. * Make networks tab buttons width consistent with input widths in extension view. * Fix settings screen subheader height in popup view * Fix height of add networks button in popup view * Add optional label to chainId and symbol form labels in networks setting tab * Style fixes for networks tab headers * Add ability to customize block explorer used by custom rpc * Stylistic improvements+fixes to custom rpc form. * Hide cancel button. * Highlight and show network form of provider by default. * Standardize network subheader name to 'Networks' * Update e2e tests for new settings network form * Update unit tests for new rpcPrefs prop * Extract blockexplorer url construction into method. * Fix broken styles on non-network tabs in popup mode * Fix block explorer url links for cases when provider in state has not been updated. * Fix vertical spacing of network form * Don't allow click of save button on network form if nothing has changed * Ensure add network button is shown in popup view * Lint fix for networks tab * Fix block explorer url preference setting. * Fix e2e tests for custom blockexplorer in account details modal changes. * Update integration test states to include frequentRpcList property * Fix some capitalizations in en/messages.json * Remove some console.logs added during custom rpc form work * Fix external account link text and url for modal and dropdown. * Documentation, url validation, proptype required additions and lint fixes on network tab and form. --- app/scripts/metamask-controller.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'app/scripts/metamask-controller.js') diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index b190dd452..cc9d51d3c 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -1633,9 +1633,9 @@ module.exports = class MetamaskController extends EventEmitter { * @returns {Promise} - The RPC Target URL confirmed. */ - async updateAndSetCustomRpc (rpcUrl, chainId, ticker = 'ETH', nickname) { - await this.preferencesController.updateRpc({ rpcUrl, chainId, ticker, nickname }) - this.networkController.setRpcTarget(rpcUrl, chainId, ticker, nickname) + async updateAndSetCustomRpc (rpcUrl, chainId, ticker = 'ETH', nickname, rpcPrefs) { + await this.preferencesController.updateRpc({ rpcUrl, chainId, ticker, nickname, rpcPrefs }) + this.networkController.setRpcTarget(rpcUrl, chainId, ticker, nickname, rpcPrefs) return rpcUrl } @@ -1648,15 +1648,15 @@ module.exports = class MetamaskController extends EventEmitter { * @param {string} nickname - Optional nickname of the selected network. * @returns {Promise} - The RPC Target URL confirmed. */ - async setCustomRpc (rpcTarget, chainId, ticker = 'ETH', nickname = '') { + async setCustomRpc (rpcTarget, chainId, ticker = 'ETH', nickname = '', rpcPrefs = {}) { const frequentRpcListDetail = this.preferencesController.getFrequentRpcListDetail() const rpcSettings = frequentRpcListDetail.find((rpc) => rpcTarget === rpc.rpcUrl) if (rpcSettings) { - this.networkController.setRpcTarget(rpcSettings.rpcUrl, rpcSettings.chainId, rpcSettings.ticker, rpcSettings.nickname) + this.networkController.setRpcTarget(rpcSettings.rpcUrl, rpcSettings.chainId, rpcSettings.ticker, rpcSettings.nickname, rpcPrefs) } else { - this.networkController.setRpcTarget(rpcTarget, chainId, ticker, nickname) - await this.preferencesController.addToFrequentRpcList(rpcTarget, chainId, ticker, nickname) + this.networkController.setRpcTarget(rpcTarget, chainId, ticker, nickname, rpcPrefs) + await this.preferencesController.addToFrequentRpcList(rpcTarget, chainId, ticker, nickname, rpcPrefs) } return rpcTarget } -- cgit v1.2.3 From 28c4001f5269eb170f14bd2829698ee402b2cfbf Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Mon, 13 May 2019 13:46:09 -0230 Subject: Update auto-logout to recognize idle time in background (#6593) * Fix wording of autoLogoutTimeLimitDescription * AppStateController and update auto-logout functionality --- app/scripts/metamask-controller.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'app/scripts/metamask-controller.js') diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index bdfff9827..07054f84b 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -25,6 +25,7 @@ const {setupMultiplex} = require('./lib/stream-utils.js') const KeyringController = require('eth-keyring-controller') const NetworkController = require('./controllers/network') const PreferencesController = require('./controllers/preferences') +const AppStateController = require('./controllers/app-state') const CurrencyController = require('./controllers/currency') const ShapeShiftController = require('./controllers/shapeshift') const InfuraController = require('./controllers/infura') @@ -101,6 +102,12 @@ module.exports = class MetamaskController extends EventEmitter { network: this.networkController, }) + // app-state controller + this.appStateController = new AppStateController({ + preferencesStore: this.preferencesController.store, + onInactiveTimeout: () => this.setLocked(), + }) + // currency controller this.currencyController = new CurrencyController({ initState: initState.CurrencyController, @@ -252,6 +259,7 @@ module.exports = class MetamaskController extends EventEmitter { }) this.store.updateStructure({ + AppStateController: this.appStateController.store, TransactionController: this.txController.store, KeyringController: this.keyringController.store, PreferencesController: this.preferencesController.store, @@ -264,6 +272,7 @@ module.exports = class MetamaskController extends EventEmitter { }) this.memStore = new ComposableObservableStore(null, { + AppStateController: this.appStateController.store, NetworkController: this.networkController.store, AccountTracker: this.accountTracker.store, TxController: this.txController.memStore, @@ -462,6 +471,9 @@ module.exports = class MetamaskController extends EventEmitter { // AddressController setAddressBook: this.addressBookController.set.bind(this.addressBookController), + // AppStateController + setLastActiveTime: nodeify(this.appStateController.setLastActiveTime, this.appStateController), + // KeyringController setLocked: nodeify(this.setLocked, this), createNewVaultAndKeychain: nodeify(this.createNewVaultAndKeychain, this), -- cgit v1.2.3 From e57ffbed593599cbf84d91144c7f208ee1298226 Mon Sep 17 00:00:00 2001 From: Paul Bouchon Date: Tue, 14 May 2019 14:38:55 -0400 Subject: feature: integrate gaba/ShapeShiftController (#6569) --- app/scripts/metamask-controller.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'app/scripts/metamask-controller.js') diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 07054f84b..55ca96ad4 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -27,7 +27,6 @@ const NetworkController = require('./controllers/network') const PreferencesController = require('./controllers/preferences') const AppStateController = require('./controllers/app-state') const CurrencyController = require('./controllers/currency') -const ShapeShiftController = require('./controllers/shapeshift') const InfuraController = require('./controllers/infura') const CachedBalancesController = require('./controllers/cached-balances') const RecentBlocksController = require('./controllers/recent-blocks') @@ -57,6 +56,7 @@ const ethUtil = require('ethereumjs-util') const sigUtil = require('eth-sig-util') const { AddressBookController, + ShapeShiftController, PhishingController, } = require('gaba') const backEndMetaMetricsEvent = require('./lib/backend-metametrics') @@ -237,9 +237,7 @@ module.exports = class MetamaskController extends EventEmitter { }) this.balancesController.updateAllBalances() - this.shapeshiftController = new ShapeShiftController({ - initState: initState.ShapeShiftController, - }) + this.shapeshiftController = new ShapeShiftController(undefined, initState.ShapeShiftController) this.networkController.lookupNetwork() this.messageManager = new MessageManager() @@ -265,7 +263,7 @@ module.exports = class MetamaskController extends EventEmitter { PreferencesController: this.preferencesController.store, AddressBookController: this.addressBookController, CurrencyController: this.currencyController.store, - ShapeShiftController: this.shapeshiftController.store, + ShapeShiftController: this.shapeshiftController, NetworkController: this.networkController.store, InfuraController: this.infuraController.store, CachedBalancesController: this.cachedBalancesController.store, @@ -287,7 +285,7 @@ module.exports = class MetamaskController extends EventEmitter { RecentBlocksController: this.recentBlocksController.store, AddressBookController: this.addressBookController, CurrencyController: this.currencyController.store, - ShapeshiftController: this.shapeshiftController.store, + ShapeshiftController: this.shapeshiftController, InfuraController: this.infuraController.store, ProviderApprovalController: this.providerApprovalController.store, }) @@ -1633,7 +1631,7 @@ module.exports = class MetamaskController extends EventEmitter { * @property {string} depositType - An abbreviation of the type of crypto currency to be deposited. */ createShapeShiftTx (depositAddress, depositType) { - this.shapeshiftController.createShapeShiftTx(depositAddress, depositType) + this.shapeshiftController.createTransaction(depositAddress, depositType) } // network -- cgit v1.2.3