diff --git a/app/scripts/controllers/permissions/index.js b/app/scripts/controllers/permissions/index.js index 311a0d1ca..a5aeb7b14 100644 --- a/app/scripts/controllers/permissions/index.js +++ b/app/scripts/controllers/permissions/index.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), diff --git a/app/scripts/controllers/permissions/methodMiddleware.js b/app/scripts/controllers/permissions/permissionsMethodMiddleware.js similarity index 98% rename from app/scripts/controllers/permissions/methodMiddleware.js rename to app/scripts/controllers/permissions/permissionsMethodMiddleware.js index 613ea3876..075f67cf8 100644 --- a/app/scripts/controllers/permissions/methodMiddleware.js +++ b/app/scripts/controllers/permissions/permissionsMethodMiddleware.js @@ -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, diff --git a/app/scripts/inpage.js b/app/scripts/inpage.js index 672502286..c7c92face 100644 --- a/app/scripts/inpage.js +++ b/app/scripts/inpage.js @@ -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) diff --git a/app/scripts/lib/backend-metametrics.js b/app/scripts/lib/background-metametrics.js similarity index 78% rename from app/scripts/lib/backend-metametrics.js rename to app/scripts/lib/background-metametrics.js index e62f09d0d..f381ea3a1 100644 --- a/app/scripts/lib/backend-metametrics.js +++ b/app/scripts/lib/background-metametrics.js @@ -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', }) } diff --git a/app/scripts/lib/createMethodMiddleware.js b/app/scripts/lib/createMethodMiddleware.js new file mode 100644 index 000000000..308cf0a99 --- /dev/null +++ b/app/scripts/lib/createMethodMiddleware.js @@ -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() + } +} diff --git a/app/scripts/lib/auto-reload.js b/app/scripts/lib/setupWeb3.js similarity index 64% rename from app/scripts/lib/auto-reload.js rename to app/scripts/lib/setupWeb3.js index 2f50e3e88..da5d8d422 100644 --- a/app/scripts/lib/auto-reload.js +++ b/app/scripts/lib/setupWeb3.js @@ -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) { diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 8008cb779..f9821e822 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -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', - action: 'Transactions', - name: 'On Chain Failure', - }, + 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 //============================================================================= diff --git a/ui/app/helpers/utils/metametrics.util.js b/ui/app/helpers/utils/metametrics.util.js index d2563c7fc..cf9f15720 100644 --- a/ui/app/helpers/utils/metametrics.util.js +++ b/ui/app/helpers/utils/metametrics.util.js @@ -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,