mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Add web3 usage metrics, prepare for web3 removal (#9144)
* add web3 usage metrics * move web3 metrics method to new middleware * rename some methods, files, and exports
This commit is contained in:
parent
d59fc79e0f
commit
e5cb63eea2
@ -7,7 +7,7 @@ import { CapabilitiesController as RpcCap } from 'rpc-cap'
|
|||||||
import { ethErrors } from 'eth-json-rpc-errors'
|
import { ethErrors } from 'eth-json-rpc-errors'
|
||||||
import { cloneDeep } from 'lodash'
|
import { cloneDeep } from 'lodash'
|
||||||
|
|
||||||
import createMethodMiddleware from './methodMiddleware'
|
import createPermissionsMethodMiddleware from './permissionsMethodMiddleware'
|
||||||
import PermissionsLogController from './permissionsLog'
|
import PermissionsLogController from './permissionsLog'
|
||||||
|
|
||||||
// Methods that do not require any permissions to use:
|
// Methods that do not require any permissions to use:
|
||||||
@ -90,7 +90,7 @@ export class PermissionsController {
|
|||||||
|
|
||||||
engine.push(this.permissionsLog.createMiddleware())
|
engine.push(this.permissionsLog.createMiddleware())
|
||||||
|
|
||||||
engine.push(createMethodMiddleware({
|
engine.push(createPermissionsMethodMiddleware({
|
||||||
addDomainMetadata: this.addDomainMetadata.bind(this),
|
addDomainMetadata: this.addDomainMetadata.bind(this),
|
||||||
getAccounts: this.getAccounts.bind(this, origin),
|
getAccounts: this.getAccounts.bind(this, origin),
|
||||||
getUnlockPromise: () => this._getUnlockPromise(true),
|
getUnlockPromise: () => this._getUnlockPromise(true),
|
||||||
|
@ -4,7 +4,7 @@ import { ethErrors } from 'eth-json-rpc-errors'
|
|||||||
/**
|
/**
|
||||||
* Create middleware for handling certain methods and preprocessing permissions requests.
|
* Create middleware for handling certain methods and preprocessing permissions requests.
|
||||||
*/
|
*/
|
||||||
export default function createMethodMiddleware ({
|
export default function createPermissionsMethodMiddleware ({
|
||||||
addDomainMetadata,
|
addDomainMetadata,
|
||||||
getAccounts,
|
getAccounts,
|
||||||
getUnlockPromise,
|
getUnlockPromise,
|
@ -1,5 +1,3 @@
|
|||||||
/*global Web3*/
|
|
||||||
|
|
||||||
// need to make sure we aren't affected by overlapping namespaces
|
// need to make sure we aren't affected by overlapping namespaces
|
||||||
// and that we dont affect the app with our namespace
|
// and that we dont affect the app with our namespace
|
||||||
// mostly a fix for web3's BigNumber if AMD's "define" is defined...
|
// mostly a fix for web3's BigNumber if AMD's "define" is defined...
|
||||||
@ -37,9 +35,7 @@ import LocalMessageDuplexStream from 'post-message-stream'
|
|||||||
import { initProvider } from '@metamask/inpage-provider'
|
import { initProvider } from '@metamask/inpage-provider'
|
||||||
|
|
||||||
// TODO:deprecate:2020
|
// TODO:deprecate:2020
|
||||||
import 'web3/dist/web3.min.js'
|
import setupWeb3 from './lib/setupWeb3.js'
|
||||||
|
|
||||||
import setupDappAutoReload from './lib/auto-reload.js'
|
|
||||||
|
|
||||||
restoreContextAfterImports()
|
restoreContextAfterImports()
|
||||||
|
|
||||||
@ -59,11 +55,9 @@ initProvider({
|
|||||||
connectionStream: metamaskStream,
|
connectionStream: metamaskStream,
|
||||||
})
|
})
|
||||||
|
|
||||||
//
|
|
||||||
// TODO:deprecate:2020
|
// TODO:deprecate:2020
|
||||||
//
|
// Setup web3
|
||||||
|
|
||||||
// setup web3
|
|
||||||
|
|
||||||
if (typeof window.web3 !== 'undefined') {
|
if (typeof window.web3 !== 'undefined') {
|
||||||
throw new Error(`MetaMask detected another web3.
|
throw new Error(`MetaMask detected another web3.
|
||||||
@ -73,18 +67,5 @@ if (typeof window.web3 !== 'undefined') {
|
|||||||
and try again.`)
|
and try again.`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const web3 = new Web3(window.ethereum)
|
// proxy web3, assign to window, and set up site auto reload
|
||||||
web3.setProvider = function () {
|
setupWeb3(log)
|
||||||
log.debug('MetaMask - overrode web3.setProvider')
|
|
||||||
}
|
|
||||||
log.debug('MetaMask - injected web3')
|
|
||||||
|
|
||||||
Object.defineProperty(window.ethereum, '_web3Ref', {
|
|
||||||
enumerable: false,
|
|
||||||
writable: true,
|
|
||||||
configurable: true,
|
|
||||||
value: web3.eth,
|
|
||||||
})
|
|
||||||
|
|
||||||
// setup dapp auto reload AND proxy web3
|
|
||||||
setupDappAutoReload(web3, window.ethereum._publicConfigStore)
|
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import { getBackgroundMetaMetricState } from '../../../ui/app/selectors'
|
import { getBackgroundMetaMetricState } from '../../../ui/app/selectors'
|
||||||
import { sendMetaMetricsEvent } from '../../../ui/app/helpers/utils/metametrics.util'
|
import { sendMetaMetricsEvent } from '../../../ui/app/helpers/utils/metametrics.util'
|
||||||
|
|
||||||
export default function backEndMetaMetricsEvent (metaMaskState, eventData) {
|
export default function backgroundMetaMetricsEvent (metaMaskState, eventData) {
|
||||||
const stateEventData = getBackgroundMetaMetricState({ metamask: metaMaskState })
|
const stateEventData = getBackgroundMetaMetricState({ metamask: metaMaskState })
|
||||||
|
|
||||||
if (stateEventData.participateInMetaMetrics) {
|
if (stateEventData.participateInMetaMetrics) {
|
||||||
sendMetaMetricsEvent({
|
sendMetaMetricsEvent({
|
||||||
...stateEventData,
|
...stateEventData,
|
||||||
...eventData,
|
...eventData,
|
||||||
|
category: 'Background',
|
||||||
currentPath: '/background',
|
currentPath: '/background',
|
||||||
})
|
})
|
||||||
}
|
}
|
32
app/scripts/lib/createMethodMiddleware.js
Normal file
32
app/scripts/lib/createMethodMiddleware.js
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/**
|
||||||
|
* Returns a middleware that implements the following RPC methods:
|
||||||
|
* - metamask_logInjectedWeb3Usage
|
||||||
|
*
|
||||||
|
* @param {Object} opts - The middleware options
|
||||||
|
* @param {string} opts.origin - The origin for the middleware stack
|
||||||
|
* @param {Function} opts.sendMetrics - A function for sending a metrics event
|
||||||
|
* @returns {(req: any, res: any, next: Function, end: Function) => void}
|
||||||
|
*/
|
||||||
|
export default function createMethodMiddleware ({ origin, sendMetrics }) {
|
||||||
|
return function methodMiddleware (req, res, next, end) {
|
||||||
|
switch (req.method) {
|
||||||
|
|
||||||
|
case 'metamask_logInjectedWeb3Usage':
|
||||||
|
|
||||||
|
const { action, name } = req.params[0]
|
||||||
|
|
||||||
|
sendMetrics({
|
||||||
|
action,
|
||||||
|
name,
|
||||||
|
customVariables: { origin },
|
||||||
|
})
|
||||||
|
|
||||||
|
res.result = true
|
||||||
|
break
|
||||||
|
|
||||||
|
default:
|
||||||
|
return next()
|
||||||
|
}
|
||||||
|
return end()
|
||||||
|
}
|
||||||
|
}
|
@ -1,26 +1,67 @@
|
|||||||
|
/*global Web3*/
|
||||||
|
|
||||||
// TODO:deprecate:2020
|
// TODO:deprecate:2020
|
||||||
|
// Delete this file
|
||||||
|
|
||||||
export default function setupDappAutoReload (web3, observable) {
|
import 'web3/dist/web3.min.js'
|
||||||
|
|
||||||
|
const shouldLogUsage = !([
|
||||||
|
'docs.metamask.io',
|
||||||
|
'metamask.github.io',
|
||||||
|
'metamask.io',
|
||||||
|
].includes(window.location.hostname))
|
||||||
|
|
||||||
|
export default function setupWeb3 (log) {
|
||||||
// export web3 as a global, checking for usage
|
// export web3 as a global, checking for usage
|
||||||
let reloadInProgress = false
|
let reloadInProgress = false
|
||||||
let lastTimeUsed
|
let lastTimeUsed
|
||||||
let lastSeenNetwork
|
let lastSeenNetwork
|
||||||
let hasBeenWarned = false
|
let hasBeenWarned = false
|
||||||
|
|
||||||
|
const web3 = new Web3(window.ethereum)
|
||||||
|
web3.setProvider = function () {
|
||||||
|
log.debug('MetaMask - overrode web3.setProvider')
|
||||||
|
}
|
||||||
|
log.debug('MetaMask - injected web3')
|
||||||
|
|
||||||
|
Object.defineProperty(window.ethereum, '_web3Ref', {
|
||||||
|
enumerable: false,
|
||||||
|
writable: true,
|
||||||
|
configurable: true,
|
||||||
|
value: web3.eth,
|
||||||
|
})
|
||||||
|
|
||||||
const web3Proxy = new Proxy(web3, {
|
const web3Proxy = new Proxy(web3, {
|
||||||
get: (_web3, key) => {
|
get: (_web3, key) => {
|
||||||
|
|
||||||
// get the time of use
|
// get the time of use
|
||||||
lastTimeUsed = Date.now()
|
lastTimeUsed = Date.now()
|
||||||
|
|
||||||
// show warning once on web3 access
|
// show warning once on web3 access
|
||||||
if (!hasBeenWarned && key !== 'currentProvider') {
|
if (!hasBeenWarned) {
|
||||||
console.warn(`MetaMask: We will stop injecting web3 in Q4 2020.\nPlease see this article for more information: https://medium.com/metamask/no-longer-injecting-web3-js-4a899ad6e59e`)
|
console.warn(`MetaMask: We will stop injecting web3 in Q4 2020.\nPlease see this article for more information: https://medium.com/metamask/no-longer-injecting-web3-js-4a899ad6e59e`)
|
||||||
hasBeenWarned = true
|
hasBeenWarned = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (shouldLogUsage) {
|
||||||
|
window.ethereum.request({
|
||||||
|
method: 'metamask_logInjectedWeb3Usage',
|
||||||
|
params: [{ action: 'window.web3 get', name: key }],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// return value normally
|
// return value normally
|
||||||
return _web3[key]
|
return _web3[key]
|
||||||
},
|
},
|
||||||
set: (_web3, key, value) => {
|
set: (_web3, key, value) => {
|
||||||
|
|
||||||
|
if (shouldLogUsage) {
|
||||||
|
window.ethereum.request({
|
||||||
|
method: 'metamask_logInjectedWeb3Usage',
|
||||||
|
params: [{ action: 'window.web3 set', name: key }],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// set value normally
|
// set value normally
|
||||||
_web3[key] = value
|
_web3[key] = value
|
||||||
},
|
},
|
||||||
@ -33,7 +74,7 @@ export default function setupDappAutoReload (web3, observable) {
|
|||||||
value: web3Proxy,
|
value: web3Proxy,
|
||||||
})
|
})
|
||||||
|
|
||||||
observable.subscribe(function (state) {
|
window.ethereum._publicConfigStore.subscribe((state) => {
|
||||||
// if the auto refresh on network change is false do not
|
// if the auto refresh on network change is false do not
|
||||||
// do anything
|
// do anything
|
||||||
if (!window.ethereum.autoRefreshOnNetworkChange) {
|
if (!window.ethereum.autoRefreshOnNetworkChange) {
|
@ -19,6 +19,7 @@ import createEngineStream from 'json-rpc-middleware-stream/engineStream'
|
|||||||
import createFilterMiddleware from 'eth-json-rpc-filters'
|
import createFilterMiddleware from 'eth-json-rpc-filters'
|
||||||
import createSubscriptionManager from 'eth-json-rpc-filters/subscriptionManager'
|
import createSubscriptionManager from 'eth-json-rpc-filters/subscriptionManager'
|
||||||
import createLoggerMiddleware from './lib/createLoggerMiddleware'
|
import createLoggerMiddleware from './lib/createLoggerMiddleware'
|
||||||
|
import createMethodMiddleware from './lib/createMethodMiddleware'
|
||||||
import createOriginMiddleware from './lib/createOriginMiddleware'
|
import createOriginMiddleware from './lib/createOriginMiddleware'
|
||||||
import createTabIdMiddleware from './lib/createTabIdMiddleware'
|
import createTabIdMiddleware from './lib/createTabIdMiddleware'
|
||||||
import createOnboardingMiddleware from './lib/createOnboardingMiddleware'
|
import createOnboardingMiddleware from './lib/createOnboardingMiddleware'
|
||||||
@ -66,7 +67,7 @@ import {
|
|||||||
PhishingController,
|
PhishingController,
|
||||||
} from '@metamask/controllers'
|
} from '@metamask/controllers'
|
||||||
|
|
||||||
import backEndMetaMetricsEvent from './lib/backend-metametrics'
|
import backgroundMetaMetricsEvent from './lib/background-metametrics'
|
||||||
|
|
||||||
export default class MetamaskController extends EventEmitter {
|
export default class MetamaskController extends EventEmitter {
|
||||||
|
|
||||||
@ -249,18 +250,11 @@ export default class MetamaskController extends EventEmitter {
|
|||||||
this.platform.showTransactionNotification(txMeta)
|
this.platform.showTransactionNotification(txMeta)
|
||||||
|
|
||||||
const { txReceipt } = txMeta
|
const { txReceipt } = txMeta
|
||||||
const participateInMetaMetrics = this.preferencesController.getParticipateInMetaMetrics()
|
if (txReceipt && txReceipt.status === '0x0') {
|
||||||
if (txReceipt && txReceipt.status === '0x0' && participateInMetaMetrics) {
|
this.sendBackgroundMetaMetrics({
|
||||||
const metamaskState = await this.getState()
|
|
||||||
backEndMetaMetricsEvent(metamaskState, {
|
|
||||||
customVariables: {
|
|
||||||
errorMessage: txMeta.simulationFails?.reason,
|
|
||||||
},
|
|
||||||
eventOpts: {
|
|
||||||
category: 'Background',
|
|
||||||
action: 'Transactions',
|
action: 'Transactions',
|
||||||
name: 'On Chain Failure',
|
name: 'On Chain Failure',
|
||||||
},
|
customVariables: { errorMessage: txMeta.simulationFails?.reason },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1637,6 +1631,10 @@ export default class MetamaskController extends EventEmitter {
|
|||||||
location,
|
location,
|
||||||
registerOnboarding: this.onboardingController.registerOnboarding,
|
registerOnboarding: this.onboardingController.registerOnboarding,
|
||||||
}))
|
}))
|
||||||
|
engine.push(createMethodMiddleware({
|
||||||
|
origin,
|
||||||
|
sendMetrics: this.sendBackgroundMetaMetrics.bind(this),
|
||||||
|
}))
|
||||||
// filter and subscription polyfills
|
// filter and subscription polyfills
|
||||||
engine.push(filterMiddleware)
|
engine.push(filterMiddleware)
|
||||||
engine.push(subscriptionManager.middleware)
|
engine.push(subscriptionManager.middleware)
|
||||||
@ -1837,6 +1835,22 @@ export default class MetamaskController extends EventEmitter {
|
|||||||
return nonceLock.nextNonce
|
return nonceLock.nextNonce
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async sendBackgroundMetaMetrics ({ action, name, customVariables } = {}) {
|
||||||
|
|
||||||
|
if (!action || !name) {
|
||||||
|
throw new Error('Must provide action and name.')
|
||||||
|
}
|
||||||
|
|
||||||
|
const metamaskState = await this.getState()
|
||||||
|
backgroundMetaMetricsEvent(metamaskState, {
|
||||||
|
customVariables,
|
||||||
|
eventOpts: {
|
||||||
|
action,
|
||||||
|
name,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
// CONFIG
|
// CONFIG
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
@ -23,7 +23,7 @@ const METAMETRICS_CUSTOM_GAS_LIMIT_CHANGE = 'gasLimitChange'
|
|||||||
const METAMETRICS_CUSTOM_GAS_PRICE_CHANGE = 'gasPriceChange'
|
const METAMETRICS_CUSTOM_GAS_PRICE_CHANGE = 'gasPriceChange'
|
||||||
const METAMETRICS_CUSTOM_FUNCTION_TYPE = 'functionType'
|
const METAMETRICS_CUSTOM_FUNCTION_TYPE = 'functionType'
|
||||||
const METAMETRICS_CUSTOM_RECIPIENT_KNOWN = 'recipientKnown'
|
const METAMETRICS_CUSTOM_RECIPIENT_KNOWN = 'recipientKnown'
|
||||||
const METAMETRICS_CUSTOM_CONFIRM_SCREEN_ORIGIN = 'origin'
|
const METAMETRICS_REQUEST_ORIGIN = 'origin'
|
||||||
const METAMETRICS_CUSTOM_FROM_NETWORK = 'fromNetwork'
|
const METAMETRICS_CUSTOM_FROM_NETWORK = 'fromNetwork'
|
||||||
const METAMETRICS_CUSTOM_TO_NETWORK = 'toNetwork'
|
const METAMETRICS_CUSTOM_TO_NETWORK = 'toNetwork'
|
||||||
const METAMETRICS_CUSTOM_ERROR_FIELD = 'errorField'
|
const METAMETRICS_CUSTOM_ERROR_FIELD = 'errorField'
|
||||||
@ -36,7 +36,7 @@ const METAMETRICS_CUSTOM_ASSET_SELECTED = 'assetSelected'
|
|||||||
const customVariableNameIdMap = {
|
const customVariableNameIdMap = {
|
||||||
[METAMETRICS_CUSTOM_FUNCTION_TYPE]: 1,
|
[METAMETRICS_CUSTOM_FUNCTION_TYPE]: 1,
|
||||||
[METAMETRICS_CUSTOM_RECIPIENT_KNOWN]: 2,
|
[METAMETRICS_CUSTOM_RECIPIENT_KNOWN]: 2,
|
||||||
[METAMETRICS_CUSTOM_CONFIRM_SCREEN_ORIGIN]: 3,
|
[METAMETRICS_REQUEST_ORIGIN]: 3,
|
||||||
[METAMETRICS_CUSTOM_GAS_LIMIT_CHANGE]: 4,
|
[METAMETRICS_CUSTOM_GAS_LIMIT_CHANGE]: 4,
|
||||||
[METAMETRICS_CUSTOM_GAS_PRICE_CHANGE]: 5,
|
[METAMETRICS_CUSTOM_GAS_PRICE_CHANGE]: 5,
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user