Skip to content

Commit

Permalink
Add web3 usage metrics, prepare for web3 removal (#9144)
Browse files Browse the repository at this point in the history
* add web3 usage metrics

* move web3 metrics method to new middleware

* rename some methods, files, and exports
  • Loading branch information
rekmarks authored Aug 7, 2020
1 parent d59fc79 commit e5cb63e
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 46 deletions.
4 changes: 2 additions & 2 deletions app/scripts/controllers/permissions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
27 changes: 4 additions & 23 deletions app/scripts/inpage.js
Original file line number Diff line number Diff line change
@@ -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...
Expand Down Expand Up @@ -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()

Expand All @@ -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.
Expand All @@ -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)
Original file line number Diff line number Diff line change
@@ -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',
})
}
Expand Down
32 changes: 32 additions & 0 deletions app/scripts/lib/createMethodMiddleware.js
Original file line number Diff line number Diff line change
@@ -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()
}
}
47 changes: 44 additions & 3 deletions app/scripts/lib/auto-reload.js → app/scripts/lib/setupWeb3.js
Original file line number Diff line number Diff line change
@@ -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
},
Expand All @@ -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) {
Expand Down
40 changes: 27 additions & 13 deletions app/scripts/metamask-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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 {

Expand Down Expand Up @@ -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',
action: 'Transactions',
name: 'On Chain Failure',
},
if (txReceipt && txReceipt.status === '0x0') {
this.sendBackgroundMetaMetrics({
action: 'Transactions',
name: 'On Chain Failure',
customVariables: { errorMessage: txMeta.simulationFails?.reason },
})
}
}
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
//=============================================================================
Expand Down
4 changes: 2 additions & 2 deletions ui/app/helpers/utils/metametrics.util.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -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,

Expand Down

0 comments on commit e5cb63e

Please sign in to comment.