From 4fea9d0cc2ec9c6914931d5e310665aca8e273b6 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Mon, 29 Apr 2019 03:48:40 -0230 Subject: [PATCH] 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/controllers/preferences.js | 8 ++++++ app/scripts/lib/backend-metametrics.js | 26 +++++++++++++++++++ app/scripts/metamask-controller.js | 19 +++++++++++++- .../confirm-transaction.duck.js | 2 +- ui/app/helpers/utils/metametrics.util.js | 4 +-- ui/app/selectors/selectors.js | 15 ++++++++++- 6 files changed, 69 insertions(+), 5 deletions(-) create mode 100644 app/scripts/lib/backend-metametrics.js diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 737411890..9fe8bee4b 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -117,6 +117,14 @@ class PreferencesController { return metaMetricsId } + getMetaMetricsId () { + return this.store.getState().metaMetricsId + } + + getParticipateInMetaMetrics () { + return this.store.getState().participateInMetaMetrics + } + setMetaMetricsSendCount (val) { this.store.updateState({ metaMetricsSendCount: val }) } diff --git a/app/scripts/lib/backend-metametrics.js b/app/scripts/lib/backend-metametrics.js new file mode 100644 index 000000000..e3c163c1a --- /dev/null +++ b/app/scripts/lib/backend-metametrics.js @@ -0,0 +1,26 @@ +const { + getMetaMetricState, +} = require('../../../ui/app/selectors/selectors') +const { + sendMetaMetricsEvent, +} = require('../../../ui/app/helpers/utils/metametrics.util') + +const inDevelopment = process.env.NODE_ENV === 'development' + +const METAMETRICS_TRACKING_URL = inDevelopment + ? 'http://www.metamask.io/metametrics' + : 'http://www.metamask.io/metametrics-prod' + +function backEndMetaMetricsEvent (metaMaskState, eventData) { + const stateEventData = getMetaMetricState({ metamask: metaMaskState }) + + if (stateEventData.participateInMetaMetrics) { + sendMetaMetricsEvent({ + ...stateEventData, + ...eventData, + url: METAMETRICS_TRACKING_URL + '/backend', + }) + } +} + +module.exports = backEndMetaMetricsEvent 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', + }, + }) + } } }) diff --git a/ui/app/ducks/confirm-transaction/confirm-transaction.duck.js b/ui/app/ducks/confirm-transaction/confirm-transaction.duck.js index 169c9d543..58b0ec8e8 100644 --- a/ui/app/ducks/confirm-transaction/confirm-transaction.duck.js +++ b/ui/app/ducks/confirm-transaction/confirm-transaction.duck.js @@ -375,7 +375,7 @@ export function setTransactionToConfirm (transactionId) { dispatch(updateMethodData(methodData)) try { - const toSmartContract = await isSmartContractAddress(to) + const toSmartContract = await isSmartContractAddress(to || '') dispatch(updateToSmartContract(toSmartContract)) } catch (error) { log.error(error) diff --git a/ui/app/helpers/utils/metametrics.util.js b/ui/app/helpers/utils/metametrics.util.js index 5ae3e8937..62f5fd760 100644 --- a/ui/app/helpers/utils/metametrics.util.js +++ b/ui/app/helpers/utils/metametrics.util.js @@ -124,10 +124,10 @@ function composeUrl (config, permissionPreferences = {}) { numberOfTokens: customVariables && customVariables.numberOfTokens || numberOfTokens, numberOfAccounts: customVariables && customVariables.numberOfAccounts || numberOfAccounts, }) : '' - const url = configUrl || `&url=${encodeURIComponent(currentPath.replace(/chrome-extension:\/\/\w+/, METAMETRICS_TRACKING_URL))}` + const url = configUrl || currentPath ? `&url=${encodeURIComponent(currentPath.replace(/chrome-extension:\/\/\w+/, METAMETRICS_TRACKING_URL))}` : '' const _id = metaMetricsId && !excludeMetaMetricsId ? `&_id=${metaMetricsId.slice(2, 18)}` : '' const rand = `&rand=${String(Math.random()).slice(2)}` - const pv_id = `&pv_id=${ethUtil.bufferToHex(ethUtil.sha3(url || currentPath.match(/chrome-extension:\/\/\w+\/(.+)/)[0])).slice(2, 8)}` + const pv_id = (url || currentPath) && `&pv_id=${ethUtil.bufferToHex(ethUtil.sha3(url || currentPath.match(/chrome-extension:\/\/\w+\/(.+)/)[0])).slice(2, 8)}` || '' const uid = metaMetricsId && !excludeMetaMetricsId ? `&uid=${metaMetricsId.slice(2, 18)}` : excludeMetaMetricsId diff --git a/ui/app/selectors/selectors.js b/ui/app/selectors/selectors.js index 2d25aa156..ce02d067e 100644 --- a/ui/app/selectors/selectors.js +++ b/ui/app/selectors/selectors.js @@ -48,6 +48,7 @@ const selectors = { getNumberOfAccounts, getNumberOfTokens, isEthereumNetwork, + getMetaMetricState, } module.exports = selectors @@ -165,7 +166,7 @@ function getSelectedToken (state) { const tokens = state.metamask.tokens || [] const selectedTokenAddress = state.metamask.selectedTokenAddress const selectedToken = tokens.filter(({ address }) => address === selectedTokenAddress)[0] - const sendToken = state.metamask.send.token + const sendToken = state.metamask.send && state.metamask.send.token return selectedToken || sendToken || null } @@ -314,3 +315,15 @@ function preferencesSelector ({ metamask }) { function getAdvancedInlineGasShown (state) { return Boolean(state.metamask.featureFlags.advancedInlineGas) } + +function getMetaMetricState (state) { + return { + network: getCurrentNetworkId(state), + activeCurrency: getSelectedAsset(state), + accountType: getAccountType(state), + metaMetricsId: state.metamask.metaMetricsId, + numberOfTokens: getNumberOfTokens(state), + numberOfAccounts: getNumberOfAccounts(state), + participateInMetaMetrics: state.metamask.participateInMetaMetrics, + } +}