mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Refactor background Segment usage (#9509)
* Create wrapper function for segment events * Extract transaction controller metrics calls into own function Co-authored-by: Mark Stacey <markjstacey@gmail.com>
This commit is contained in:
parent
4411f0eb9c
commit
30d6ad83f7
@ -22,7 +22,6 @@ import cleanErrorStack from '../../lib/cleanErrorStack'
|
||||
import { hexToBn, bnToHex, BnMultiplyByFraction } from '../../lib/util'
|
||||
import { TRANSACTION_NO_CONTRACT_ERROR_KEY } from '../../../../ui/app/helpers/constants/error-keys'
|
||||
import { getSwapsTokensReceivedFromTxMeta } from '../../../../ui/app/pages/swaps/swaps.util'
|
||||
import { segment, METAMETRICS_ANONYMOUS_ID } from '../../lib/segment'
|
||||
import TransactionStateManager from './tx-state-manager'
|
||||
import TxGasUtil from './tx-gas-utils'
|
||||
import PendingTransactionTracker from './pending-tx-tracker'
|
||||
@ -77,7 +76,8 @@ export default class TransactionController extends EventEmitter {
|
||||
this.blockTracker = opts.blockTracker
|
||||
this.signEthTx = opts.signTransaction
|
||||
this.inProcessOfSigning = new Set()
|
||||
this.version = opts.version
|
||||
this._trackSegmentEvent = opts.trackSegmentEvent
|
||||
this._getParticipateInMetrics = opts.getParticipateInMetrics
|
||||
|
||||
this.memStore = new ObservableStore({})
|
||||
this.query = new EthQuery(this.provider)
|
||||
@ -569,7 +569,6 @@ export default class TransactionController extends EventEmitter {
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
// It seems that sometimes the numerical values being returned from
|
||||
// this.query.getTransactionReceipt are BN instances and not strings.
|
||||
const gasUsed = typeof txReceipt.gasUsed === 'string'
|
||||
@ -586,64 +585,8 @@ export default class TransactionController extends EventEmitter {
|
||||
txMeta.postTxBalance = postTxBalance.toString(16)
|
||||
}
|
||||
|
||||
if (txMeta.swapMetaData) {
|
||||
let { version } = this
|
||||
if (process.env.METAMASK_ENVIRONMENT !== 'production') {
|
||||
version = `${version}-${process.env.METAMASK_ENVIRONMENT}`
|
||||
}
|
||||
const segmentContext = {
|
||||
app: {
|
||||
version,
|
||||
name: 'MetaMask Extension',
|
||||
},
|
||||
locale: this.preferencesStore.getState().currentLocale.replace('_', '-'),
|
||||
page: {
|
||||
path: '/background-process',
|
||||
title: 'Background Process',
|
||||
url: '/background-process',
|
||||
},
|
||||
userAgent: window.navigator.userAgent,
|
||||
}
|
||||
|
||||
const metametricsId = this.preferencesStore.getState().metaMetricsId
|
||||
if (metametricsId && txMeta.swapMetaData && txReceipt.status !== '0x0') {
|
||||
const tokensReceived = getSwapsTokensReceivedFromTxMeta(
|
||||
txMeta.destinationTokenSymbol,
|
||||
txMeta,
|
||||
txMeta.destinationTokenAddress,
|
||||
txMeta.txParams.from,
|
||||
txMeta.destinationTokenDecimals,
|
||||
)
|
||||
const quoteVsExecutionRatio = `${(new BigNumber(tokensReceived, 10))
|
||||
.div(txMeta.swapMetaData?.['token_to_amount'], 10).times(100).round(2)}%`
|
||||
|
||||
segment.track({ event: 'Swap Completed', userId: metametricsId, context: segmentContext, category: 'swaps' })
|
||||
segment.track({
|
||||
event: 'Swap Completed',
|
||||
properties: {
|
||||
...txMeta.swapMetaData,
|
||||
token_to_amount_received: tokensReceived,
|
||||
quote_vs_executionRatio: quoteVsExecutionRatio,
|
||||
},
|
||||
context: segmentContext,
|
||||
anonymousId: METAMETRICS_ANONYMOUS_ID,
|
||||
excludeMetaMetricsId: true,
|
||||
category: 'swaps',
|
||||
})
|
||||
} else if (metametricsId && txMeta.swapMetaData) {
|
||||
segment.track({ event: 'Swap Failed', userId: metametricsId, context: segmentContext, category: 'swaps' })
|
||||
segment.track({
|
||||
event: 'Swap Failed',
|
||||
properties: { ...txMeta.swapMetaData },
|
||||
anonymousId: METAMETRICS_ANONYMOUS_ID,
|
||||
excludeMetaMetricsId: true,
|
||||
context: segmentContext,
|
||||
category: 'swaps',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
this.txStateManager.updateTx(txMeta, 'transactions#confirmTransaction - add txReceipt')
|
||||
this._trackSwapsMetrics(txMeta)
|
||||
} catch (err) {
|
||||
log.error(err)
|
||||
}
|
||||
@ -879,4 +822,53 @@ export default class TransactionController extends EventEmitter {
|
||||
this.memStore.updateState({ unapprovedTxs, currentNetworkTxList })
|
||||
}
|
||||
|
||||
_trackSwapsMetrics (txMeta) {
|
||||
if (this._getParticipateInMetrics() && txMeta.swapMetaData) {
|
||||
if (txMeta.txReceipt.status === '0x0') {
|
||||
this._trackSegmentEvent({
|
||||
event: 'Swap Failed',
|
||||
category: 'swaps',
|
||||
excludeMetaMetricsId: false,
|
||||
})
|
||||
|
||||
this._trackSegmentEvent({
|
||||
event: 'Swap Failed',
|
||||
properties: { ...txMeta.swapMetaData },
|
||||
category: 'swaps',
|
||||
excludeMetaMetricsId: true,
|
||||
})
|
||||
} else {
|
||||
const tokensReceived = getSwapsTokensReceivedFromTxMeta(
|
||||
txMeta.destinationTokenSymbol,
|
||||
txMeta,
|
||||
txMeta.destinationTokenAddress,
|
||||
txMeta.txParams.from,
|
||||
txMeta.destinationTokenDecimals,
|
||||
)
|
||||
|
||||
const quoteVsExecutionRatio = `${
|
||||
(new BigNumber(tokensReceived, 10))
|
||||
.div(txMeta.swapMetaData.token_to_amount, 10)
|
||||
.times(100)
|
||||
.round(2)
|
||||
}%`
|
||||
|
||||
this._trackSegmentEvent({
|
||||
event: 'Swap Completed',
|
||||
category: 'swaps',
|
||||
excludeMetaMetricsId: false,
|
||||
})
|
||||
|
||||
this._trackSegmentEvent({
|
||||
event: 'Swap Completed',
|
||||
properties: {
|
||||
...txMeta.swapMetaData,
|
||||
token_to_amount_received: tokensReceived,
|
||||
quote_vs_executionRatio: quoteVsExecutionRatio,
|
||||
},
|
||||
excludeMetaMetricsId: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,8 @@ const inDevelopment = process.env.METAMASK_DEBUG || process.env.IN_TEST
|
||||
|
||||
const flushAt = inDevelopment ? 1 : undefined
|
||||
|
||||
const METAMETRICS_ANONYMOUS_ID = '0x0000000000000000'
|
||||
|
||||
const segmentNoop = {
|
||||
track () {
|
||||
// noop
|
||||
@ -20,8 +22,83 @@ const segmentNoop = {
|
||||
// provided a SEGMENT_WRITE_KEY. This also holds true for test environments and
|
||||
// E2E, which is handled in the build process by never providing the SEGMENT_WRITE_KEY
|
||||
// which process.env.IN_TEST is true
|
||||
export const segment = process.env.SEGMENT_WRITE_KEY
|
||||
const segment = process.env.SEGMENT_WRITE_KEY
|
||||
? new Analytics(process.env.SEGMENT_WRITE_KEY, { flushAt })
|
||||
: segmentNoop
|
||||
|
||||
export const METAMETRICS_ANONYMOUS_ID = '0x0000000000000000'
|
||||
/**
|
||||
* Returns a function for tracking Segment events.
|
||||
*
|
||||
* @param {string} metamaskVersion - The current version of the MetaMask
|
||||
* extension.
|
||||
* @param {Function} getParticipateInMetrics - A function that returns
|
||||
* whether the user participates in MetaMetrics.
|
||||
* @param {Function} getMetricsState - A function for getting state relevant
|
||||
* to MetaMetrics/Segment.
|
||||
*/
|
||||
export function getTrackSegmentEvent (
|
||||
metamaskVersion,
|
||||
getParticipateInMetrics,
|
||||
getMetricsState,
|
||||
) {
|
||||
const version = process.env.METAMASK_ENVIRONMENT === 'production'
|
||||
? metamaskVersion
|
||||
: `${metamaskVersion}-${process.env.METAMASK_ENVIRONMENT}`
|
||||
|
||||
const segmentContext = {
|
||||
app: {
|
||||
name: 'MetaMask Extension',
|
||||
version,
|
||||
},
|
||||
page: {
|
||||
path: '/background-process',
|
||||
title: 'Background Process',
|
||||
url: '/background-process',
|
||||
},
|
||||
userAgent: window.navigator.userAgent,
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks a Segment event per the given arguments.
|
||||
*
|
||||
* @param {string} event - The event name.
|
||||
* @param {string} category - The event category.
|
||||
* @param {Object} [properties] - The event properties.
|
||||
* @param {boolean} [excludeMetaMetricsId] - `true` if the user's MetaMetrics id should
|
||||
* not be included, and `false` otherwise. Default: `true`
|
||||
*/
|
||||
return function trackSegmentEvent ({
|
||||
event,
|
||||
category,
|
||||
properties = {},
|
||||
excludeMetaMetricsId = true,
|
||||
}) {
|
||||
if (!event || !category) {
|
||||
throw new Error('Must specify event and category.')
|
||||
}
|
||||
|
||||
if (!getParticipateInMetrics()) {
|
||||
return
|
||||
}
|
||||
|
||||
const { currentLocale, metaMetricsId } = getMetricsState()
|
||||
|
||||
const trackOptions = {
|
||||
event,
|
||||
category,
|
||||
context: {
|
||||
...segmentContext,
|
||||
locale: currentLocale.replace('_', '-'),
|
||||
},
|
||||
properties,
|
||||
}
|
||||
|
||||
if (excludeMetaMetricsId) {
|
||||
trackOptions.anonymousId = METAMETRICS_ANONYMOUS_ID
|
||||
} else {
|
||||
trackOptions.userId = metaMetricsId
|
||||
}
|
||||
|
||||
segment.track(trackOptions)
|
||||
}
|
||||
}
|
||||
|
@ -55,6 +55,7 @@ import getRestrictedMethods from './controllers/permissions/restrictedMethods'
|
||||
import nodeify from './lib/nodeify'
|
||||
import accountImporter from './account-import-strategies'
|
||||
import seedPhraseVerifier from './lib/seed-phrase-verifier'
|
||||
import { getTrackSegmentEvent } from './lib/segment'
|
||||
|
||||
import backgroundMetaMetricsEvent from './lib/background-metametrics'
|
||||
|
||||
@ -114,6 +115,19 @@ export default class MetamaskController extends EventEmitter {
|
||||
migrateAddressBookState: this.migrateAddressBookState.bind(this),
|
||||
})
|
||||
|
||||
// This depends on preferences controller state
|
||||
this.trackSegmentEvent = getTrackSegmentEvent(
|
||||
this.platform.getVersion(),
|
||||
() => this.preferencesController.getParticipateInMetaMetrics(),
|
||||
() => {
|
||||
const {
|
||||
currentLocale,
|
||||
metaMetricsId,
|
||||
} = this.preferencesController.getState()
|
||||
return { currentLocale, metaMetricsId }
|
||||
},
|
||||
)
|
||||
|
||||
this.appStateController = new AppStateController({
|
||||
addUnlockListener: this.on.bind(this, 'unlock'),
|
||||
isUnlocked: this.isUnlocked.bind(this),
|
||||
@ -239,7 +253,8 @@ export default class MetamaskController extends EventEmitter {
|
||||
signTransaction: this.keyringController.signTransaction.bind(this.keyringController),
|
||||
provider: this.provider,
|
||||
blockTracker: this.blockTracker,
|
||||
version: this.platform.getVersion(),
|
||||
trackSegmentEvent: this.trackSegmentEvent,
|
||||
getParticipateInMetrics: () => this.preferencesController.getParticipateInMetaMetrics(),
|
||||
})
|
||||
this.txController.on('newUnapprovedTx', () => opts.showUnapprovedTx())
|
||||
|
||||
|
@ -50,6 +50,7 @@ describe('Transaction Controller', function () {
|
||||
}),
|
||||
getPermittedAccounts: () => undefined,
|
||||
getCurrentChainId: () => currentChainId,
|
||||
getParticipateInMetrics: () => false,
|
||||
})
|
||||
txController.nonceTracker.getNonceLock = () => Promise.resolve({ nextNonce: 0, releaseLock: noop })
|
||||
})
|
||||
@ -558,6 +559,7 @@ describe('Transaction Controller', function () {
|
||||
ethTx.sign(_fromAccount.key)
|
||||
resolve()
|
||||
}),
|
||||
getParticipateInMetrics: () => false,
|
||||
})
|
||||
const result = await _txController._determineTransactionCategory({
|
||||
to: '0x9e673399f795D01116e9A8B2dD2F156705131ee9',
|
||||
@ -590,6 +592,7 @@ describe('Transaction Controller', function () {
|
||||
ethTx.sign(_fromAccount.key)
|
||||
resolve()
|
||||
}),
|
||||
getParticipateInMetrics: () => false,
|
||||
})
|
||||
const result = await _txController._determineTransactionCategory({
|
||||
to: '0x9e673399f795D01116e9A8B2dD2F156705131ee9',
|
||||
|
Loading…
Reference in New Issue
Block a user