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
feature/default_network_editable
Erik Marks 4 years ago committed by Mark Stacey
parent f39498703e
commit 500dbf76cf
  1. 4
      app/scripts/controllers/permissions/index.js
  2. 2
      app/scripts/controllers/permissions/permissionsMethodMiddleware.js
  3. 27
      app/scripts/inpage.js
  4. 4
      app/scripts/lib/background-metametrics.js
  5. 32
      app/scripts/lib/createMethodMiddleware.js
  6. 47
      app/scripts/lib/setupWeb3.js
  7. 36
      app/scripts/metamask-controller.js
  8. 4
      ui/app/helpers/utils/metametrics.util.js

@ -7,7 +7,7 @@ import { CapabilitiesController as RpcCap } from 'rpc-cap'
import { ethErrors } from 'eth-json-rpc-errors'
import { cloneDeep } from 'lodash'
import createMethodMiddleware from './methodMiddleware'
import createPermissionsMethodMiddleware from './permissionsMethodMiddleware'
import PermissionsLogController from './permissionsLog'
// Methods that do not require any permissions to use:
@ -90,7 +90,7 @@ export class PermissionsController {
engine.push(this.permissionsLog.createMiddleware())
engine.push(createMethodMiddleware({
engine.push(createPermissionsMethodMiddleware({
addDomainMetadata: this.addDomainMetadata.bind(this),
getAccounts: this.getAccounts.bind(this, origin),
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.
*/
export default function createMethodMiddleware ({
export default function createPermissionsMethodMiddleware ({
addDomainMetadata,
getAccounts,
getUnlockPromise,

@ -1,5 +1,3 @@
/*global Web3*/
// need to make sure we aren't affected by overlapping namespaces
// and that we dont affect the app with our namespace
// 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'
// TODO:deprecate:2020
import 'web3/dist/web3.min.js'
import setupDappAutoReload from './lib/auto-reload.js'
import setupWeb3 from './lib/setupWeb3.js'
restoreContextAfterImports()
@ -59,11 +55,9 @@ initProvider({
connectionStream: metamaskStream,
})
//
// TODO:deprecate:2020
//
// Setup web3
// setup web3
if (typeof window.web3 !== 'undefined') {
throw new Error(`MetaMask detected another web3.
@ -73,18 +67,5 @@ if (typeof window.web3 !== 'undefined') {
and try again.`)
}
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,
})
// setup dapp auto reload AND proxy web3
setupDappAutoReload(web3, window.ethereum._publicConfigStore)
// proxy web3, assign to window, and set up site auto reload
setupWeb3(log)

@ -1,13 +1,13 @@
import { getBackgroundMetaMetricState } from '../../../ui/app/selectors'
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 })
if (stateEventData.participateInMetaMetrics) {
sendMetaMetricsEvent({
...stateEventData,
...eventData,
category: 'Background',
currentPath: '/background',
})
}

@ -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
// 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
let reloadInProgress = false
let lastTimeUsed
let lastSeenNetwork
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, {
get: (_web3, key) => {
// get the time of use
lastTimeUsed = Date.now()
// 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`)
hasBeenWarned = true
}
if (shouldLogUsage) {
window.ethereum.request({
method: 'metamask_logInjectedWeb3Usage',
params: [{ action: 'window.web3 get', name: key }],
})
}
// return value normally
return _web3[key]
},
set: (_web3, key, value) => {
if (shouldLogUsage) {
window.ethereum.request({
method: 'metamask_logInjectedWeb3Usage',
params: [{ action: 'window.web3 set', name: key }],
})
}
// set value normally
_web3[key] = value
},
@ -33,7 +74,7 @@ export default function setupDappAutoReload (web3, observable) {
value: web3Proxy,
})
observable.subscribe(function (state) {
window.ethereum._publicConfigStore.subscribe((state) => {
// if the auto refresh on network change is false do not
// do anything
if (!window.ethereum.autoRefreshOnNetworkChange) {

@ -19,6 +19,7 @@ import createEngineStream from 'json-rpc-middleware-stream/engineStream'
import createFilterMiddleware from 'eth-json-rpc-filters'
import createSubscriptionManager from 'eth-json-rpc-filters/subscriptionManager'
import createLoggerMiddleware from './lib/createLoggerMiddleware'
import createMethodMiddleware from './lib/createMethodMiddleware'
import createOriginMiddleware from './lib/createOriginMiddleware'
import createTabIdMiddleware from './lib/createTabIdMiddleware'
import createOnboardingMiddleware from './lib/createOnboardingMiddleware'
@ -66,7 +67,7 @@ import {
PhishingController,
} from '@metamask/controllers'
import backEndMetaMetricsEvent from './lib/backend-metametrics'
import backgroundMetaMetricsEvent from './lib/background-metametrics'
export default class MetamaskController extends EventEmitter {
@ -249,18 +250,11 @@ export default class MetamaskController extends EventEmitter {
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: 'Background',
if (txReceipt && txReceipt.status === '0x0') {
this.sendBackgroundMetaMetrics({
action: 'Transactions',
name: 'On Chain Failure',
},
customVariables: { errorMessage: txMeta.simulationFails?.reason },
})
}
}
@ -1637,6 +1631,10 @@ export default class MetamaskController extends EventEmitter {
location,
registerOnboarding: this.onboardingController.registerOnboarding,
}))
engine.push(createMethodMiddleware({
origin,
sendMetrics: this.sendBackgroundMetaMetrics.bind(this),
}))
// filter and subscription polyfills
engine.push(filterMiddleware)
engine.push(subscriptionManager.middleware)
@ -1837,6 +1835,22 @@ export default class MetamaskController extends EventEmitter {
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
//=============================================================================

@ -23,7 +23,7 @@ const METAMETRICS_CUSTOM_GAS_LIMIT_CHANGE = 'gasLimitChange'
const METAMETRICS_CUSTOM_GAS_PRICE_CHANGE = 'gasPriceChange'
const METAMETRICS_CUSTOM_FUNCTION_TYPE = 'functionType'
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_TO_NETWORK = 'toNetwork'
const METAMETRICS_CUSTOM_ERROR_FIELD = 'errorField'
@ -36,7 +36,7 @@ const METAMETRICS_CUSTOM_ASSET_SELECTED = 'assetSelected'
const customVariableNameIdMap = {
[METAMETRICS_CUSTOM_FUNCTION_TYPE]: 1,
[METAMETRICS_CUSTOM_RECIPIENT_KNOWN]: 2,
[METAMETRICS_CUSTOM_CONFIRM_SCREEN_ORIGIN]: 3,
[METAMETRICS_REQUEST_ORIGIN]: 3,
[METAMETRICS_CUSTOM_GAS_LIMIT_CHANGE]: 4,
[METAMETRICS_CUSTOM_GAS_PRICE_CHANGE]: 5,

Loading…
Cancel
Save