Event tracking for Token Detection V2 (#14441)

feature/default_network_editable
Niranjana Binoy 3 years ago committed by GitHub
parent 4b2cd0ef7a
commit 6c757ab5e0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 20
      app/scripts/controllers/detect-tokens.js
  2. 1
      app/scripts/controllers/metametrics.js
  3. 6
      app/scripts/controllers/metametrics.test.js
  4. 14
      app/scripts/controllers/transactions/index.test.js
  5. 2
      app/scripts/lib/rpc-method-middleware/handlers/add-ethereum-chain.js
  6. 3
      app/scripts/metamask-controller.js
  7. 32
      shared/constants/metametrics.js
  8. 25
      ui/components/app/asset-list/detetcted-tokens-link/detected-tokens-link.js
  9. 28
      ui/components/app/asset-list/detetcted-tokens-link/detected-tokens-link.stories.js
  10. 32
      ui/components/app/asset-list/detetcted-tokens-link/detected-tokens-link.test.js
  11. 19
      ui/components/app/detected-token/detected-token-selection-popover/detected-token-selection-popover.js
  12. 61
      ui/components/app/detected-token/detected-token.js
  13. 2
      ui/components/app/wallet-overview/eth-overview.js
  14. 2
      ui/components/app/wallet-overview/token-overview.js
  15. 5
      ui/pages/add-collectible/add-collectible.js
  16. 6
      ui/pages/confirm-add-suggested-token/confirm-add-suggested-token.js
  17. 11
      ui/pages/confirm-import-token/confirm-import-token.js

@ -6,6 +6,9 @@ import { MINUTE } from '../../../shared/constants/time';
import { MAINNET_CHAIN_ID } from '../../../shared/constants/network'; import { MAINNET_CHAIN_ID } from '../../../shared/constants/network';
import { isTokenDetectionEnabledForNetwork } from '../../../shared/modules/network.utils'; import { isTokenDetectionEnabledForNetwork } from '../../../shared/modules/network.utils';
import { isEqualCaseInsensitive } from '../../../shared/modules/string-utils'; import { isEqualCaseInsensitive } from '../../../shared/modules/string-utils';
import { TOKEN_STANDARDS } from '../../../ui/helpers/constants/common';
import { ASSET_TYPES } from '../../../shared/constants/transaction';
import { EVENT, EVENT_NAMES } from '../../../shared/constants/metametrics';
// By default, poll every 3 minutes // By default, poll every 3 minutes
const DEFAULT_INTERVAL = MINUTE * 3; const DEFAULT_INTERVAL = MINUTE * 3;
@ -26,6 +29,7 @@ export default class DetectTokensController {
* @param config.tokenList * @param config.tokenList
* @param config.tokensController * @param config.tokensController
* @param config.assetsContractController * @param config.assetsContractController
* @param config.trackMetaMetricsEvent
*/ */
constructor({ constructor({
interval = DEFAULT_INTERVAL, interval = DEFAULT_INTERVAL,
@ -35,6 +39,7 @@ export default class DetectTokensController {
tokenList, tokenList,
tokensController, tokensController,
assetsContractController = null, assetsContractController = null,
trackMetaMetricsEvent,
} = {}) { } = {}) {
this.assetsContractController = assetsContractController; this.assetsContractController = assetsContractController;
this.tokensController = tokensController; this.tokensController = tokensController;
@ -51,6 +56,7 @@ export default class DetectTokensController {
this.detectedTokens = process.env.TOKEN_DETECTION_V2 this.detectedTokens = process.env.TOKEN_DETECTION_V2
? this.tokensController?.state.detectedTokens ? this.tokensController?.state.detectedTokens
: []; : [];
this._trackMetaMetricsEvent = trackMetaMetricsEvent;
preferences?.store.subscribe(({ selectedAddress, useTokenDetection }) => { preferences?.store.subscribe(({ selectedAddress, useTokenDetection }) => {
if ( if (
@ -162,6 +168,7 @@ export default class DetectTokensController {
let tokensWithBalance = []; let tokensWithBalance = [];
if (process.env.TOKEN_DETECTION_V2) { if (process.env.TOKEN_DETECTION_V2) {
const eventTokensDetails = [];
if (result) { if (result) {
const nonZeroTokenAddresses = Object.keys(result); const nonZeroTokenAddresses = Object.keys(result);
for (const nonZeroTokenAddress of nonZeroTokenAddresses) { for (const nonZeroTokenAddress of nonZeroTokenAddresses) {
@ -172,6 +179,9 @@ export default class DetectTokensController {
iconUrl, iconUrl,
aggregators, aggregators,
} = tokenList[nonZeroTokenAddress]; } = tokenList[nonZeroTokenAddress];
eventTokensDetails.push(`${symbol} - ${address}`);
tokensWithBalance.push({ tokensWithBalance.push({
address, address,
symbol, symbol,
@ -180,7 +190,17 @@ export default class DetectTokensController {
aggregators, aggregators,
}); });
} }
if (tokensWithBalance.length > 0) { if (tokensWithBalance.length > 0) {
this._trackMetaMetricsEvent({
event: EVENT_NAMES.TOKEN_DETECTED,
category: EVENT.CATEGORIES.WALLET,
properties: {
tokens: eventTokensDetails,
token_standard: TOKEN_STANDARDS.ERC20,
asset_type: ASSET_TYPES.TOKEN,
},
});
await this.tokensController.addDetectedTokens(tokensWithBalance); await this.tokensController.addDetectedTokens(tokensWithBalance);
} }
} }

@ -571,6 +571,7 @@ export default class MetaMetricsController {
[TRAITS.OPENSEA_API_ENABLED]: metamaskState.openSeaEnabled, [TRAITS.OPENSEA_API_ENABLED]: metamaskState.openSeaEnabled,
[TRAITS.THREE_BOX_ENABLED]: metamaskState.threeBoxSyncingAllowed, [TRAITS.THREE_BOX_ENABLED]: metamaskState.threeBoxSyncingAllowed,
[TRAITS.THEME]: metamaskState.theme || 'default', [TRAITS.THEME]: metamaskState.theme || 'default',
[TRAITS.TOKEN_DETECTION_ENABLED]: metamaskState.useTokenDetection,
}; };
if (!this.previousTraits) { if (!this.previousTraits) {

@ -682,6 +682,7 @@ describe('MetaMetricsController', function () {
threeBoxSyncingAllowed: false, threeBoxSyncingAllowed: false,
useCollectibleDetection: false, useCollectibleDetection: false,
theme: 'default', theme: 'default',
useTokenDetection: true,
}); });
assert.deepEqual(traits, { assert.deepEqual(traits, {
@ -696,6 +697,7 @@ describe('MetaMetricsController', function () {
[TRAITS.OPENSEA_API_ENABLED]: true, [TRAITS.OPENSEA_API_ENABLED]: true,
[TRAITS.THREE_BOX_ENABLED]: false, [TRAITS.THREE_BOX_ENABLED]: false,
[TRAITS.THEME]: 'default', [TRAITS.THEME]: 'default',
[TRAITS.TOKEN_DETECTION_ENABLED]: true,
}); });
}); });
@ -717,6 +719,7 @@ describe('MetaMetricsController', function () {
threeBoxSyncingAllowed: false, threeBoxSyncingAllowed: false,
useCollectibleDetection: false, useCollectibleDetection: false,
theme: 'default', theme: 'default',
useTokenDetection: true,
}); });
const updatedTraits = metaMetricsController._buildUserTraitsObject({ const updatedTraits = metaMetricsController._buildUserTraitsObject({
@ -737,6 +740,7 @@ describe('MetaMetricsController', function () {
threeBoxSyncingAllowed: false, threeBoxSyncingAllowed: false,
useCollectibleDetection: false, useCollectibleDetection: false,
theme: 'default', theme: 'default',
useTokenDetection: true,
}); });
assert.deepEqual(updatedTraits, { assert.deepEqual(updatedTraits, {
@ -765,6 +769,7 @@ describe('MetaMetricsController', function () {
threeBoxSyncingAllowed: false, threeBoxSyncingAllowed: false,
useCollectibleDetection: true, useCollectibleDetection: true,
theme: 'default', theme: 'default',
useTokenDetection: true,
}); });
const updatedTraits = metaMetricsController._buildUserTraitsObject({ const updatedTraits = metaMetricsController._buildUserTraitsObject({
@ -783,6 +788,7 @@ describe('MetaMetricsController', function () {
threeBoxSyncingAllowed: false, threeBoxSyncingAllowed: false,
useCollectibleDetection: true, useCollectibleDetection: true,
theme: 'default', theme: 'default',
useTokenDetection: true,
}); });
assert.equal(updatedTraits, null); assert.equal(updatedTraits, null);

@ -1470,7 +1470,7 @@ describe('Transaction Controller', function () {
gas_edit_type: 'none', gas_edit_type: 'none',
network: '42', network: '42',
referrer: ORIGIN_METAMASK, referrer: ORIGIN_METAMASK,
source: 'user', source: EVENT.SOURCE.TRANSACTION.USER,
type: TRANSACTION_TYPES.SIMPLE_SEND, type: TRANSACTION_TYPES.SIMPLE_SEND,
account_type: 'MetaMask', account_type: 'MetaMask',
asset_type: ASSET_TYPES.NATIVE, asset_type: ASSET_TYPES.NATIVE,
@ -1549,7 +1549,7 @@ describe('Transaction Controller', function () {
gas_edit_type: 'none', gas_edit_type: 'none',
network: '42', network: '42',
referrer: ORIGIN_METAMASK, referrer: ORIGIN_METAMASK,
source: 'user', source: EVENT.SOURCE.TRANSACTION.USER,
type: TRANSACTION_TYPES.SIMPLE_SEND, type: TRANSACTION_TYPES.SIMPLE_SEND,
account_type: 'MetaMask', account_type: 'MetaMask',
asset_type: ASSET_TYPES.NATIVE, asset_type: ASSET_TYPES.NATIVE,
@ -1638,7 +1638,7 @@ describe('Transaction Controller', function () {
gas_edit_type: 'none', gas_edit_type: 'none',
network: '42', network: '42',
referrer: 'other', referrer: 'other',
source: 'dapp', source: EVENT.SOURCE.TRANSACTION.DAPP,
type: TRANSACTION_TYPES.SIMPLE_SEND, type: TRANSACTION_TYPES.SIMPLE_SEND,
account_type: 'MetaMask', account_type: 'MetaMask',
asset_type: ASSET_TYPES.NATIVE, asset_type: ASSET_TYPES.NATIVE,
@ -1719,7 +1719,7 @@ describe('Transaction Controller', function () {
gas_edit_type: 'none', gas_edit_type: 'none',
network: '42', network: '42',
referrer: 'other', referrer: 'other',
source: 'dapp', source: EVENT.SOURCE.TRANSACTION.DAPP,
type: TRANSACTION_TYPES.SIMPLE_SEND, type: TRANSACTION_TYPES.SIMPLE_SEND,
account_type: 'MetaMask', account_type: 'MetaMask',
asset_type: ASSET_TYPES.NATIVE, asset_type: ASSET_TYPES.NATIVE,
@ -1800,7 +1800,7 @@ describe('Transaction Controller', function () {
gas_edit_type: 'none', gas_edit_type: 'none',
network: '42', network: '42',
referrer: 'other', referrer: 'other',
source: 'dapp', source: EVENT.SOURCE.TRANSACTION.DAPP,
type: TRANSACTION_TYPES.SIMPLE_SEND, type: TRANSACTION_TYPES.SIMPLE_SEND,
account_type: 'MetaMask', account_type: 'MetaMask',
asset_type: ASSET_TYPES.NATIVE, asset_type: ASSET_TYPES.NATIVE,
@ -1859,7 +1859,7 @@ describe('Transaction Controller', function () {
properties: { properties: {
network: '42', network: '42',
referrer: 'other', referrer: 'other',
source: 'dapp', source: EVENT.SOURCE.TRANSACTION.DAPP,
type: TRANSACTION_TYPES.SIMPLE_SEND, type: TRANSACTION_TYPES.SIMPLE_SEND,
chain_id: '0x2a', chain_id: '0x2a',
eip_1559_version: '0', eip_1559_version: '0',
@ -1936,7 +1936,7 @@ describe('Transaction Controller', function () {
gas_edit_type: 'none', gas_edit_type: 'none',
network: '42', network: '42',
referrer: 'other', referrer: 'other',
source: 'dapp', source: EVENT.SOURCE.TRANSACTION.DAPP,
type: TRANSACTION_TYPES.SIMPLE_SEND, type: TRANSACTION_TYPES.SIMPLE_SEND,
account_type: 'MetaMask', account_type: 'MetaMask',
asset_type: ASSET_TYPES.NATIVE, asset_type: ASSET_TYPES.NATIVE,

@ -265,7 +265,7 @@ async function addEthereumChainHandler(
network: firstValidRPCUrl, network: firstValidRPCUrl,
symbol: ticker, symbol: ticker,
block_explorer_url: firstValidBlockExplorerUrl, block_explorer_url: firstValidBlockExplorerUrl,
source: 'dapp', source: EVENT.SOURCE.TRANSACTION.DAPP,
}, },
}); });

@ -713,6 +713,9 @@ export default class MetamaskController extends EventEmitter {
network: this.networkController, network: this.networkController,
keyringMemStore: this.keyringController.memStore, keyringMemStore: this.keyringController.memStore,
tokenList: this.tokenListController, tokenList: this.tokenListController,
trackMetaMetricsEvent: this.metaMetricsController.trackEvent.bind(
this.metaMetricsController,
),
})) }))
: (this.detectTokensController = new DetectTokensController({ : (this.detectTokensController = new DetectTokensController({
preferences: this.preferencesController, preferences: this.preferencesController,

@ -178,6 +178,8 @@
* @property {'three_box_enabled'} THREE_BOX_ENABLED - when 3box feature is * @property {'three_box_enabled'} THREE_BOX_ENABLED - when 3box feature is
* toggled we identify the 3box_enabled trait * toggled we identify the 3box_enabled trait
* @property {'theme'} THEME - when the user's theme changes we identify the theme trait * @property {'theme'} THEME - when the user's theme changes we identify the theme trait
* @property {'token_detection_enabled'} TOKEN_DETECTION_ENABLED - when token detection feature is toggled we
* identify the token_detection_enabled trait
*/ */
/** /**
@ -197,6 +199,7 @@ export const TRAITS = {
OPENSEA_API_ENABLED: 'opensea_api_enabled', OPENSEA_API_ENABLED: 'opensea_api_enabled',
THREE_BOX_ENABLED: 'three_box_enabled', THREE_BOX_ENABLED: 'three_box_enabled',
THEME: 'theme', THEME: 'theme',
TOKEN_DETECTION_ENABLED: 'token_detection_enabled',
}; };
/** /**
@ -222,6 +225,7 @@ export const TRAITS = {
* @property {boolean} [three_box_enabled] - does the user have 3box sync * @property {boolean} [three_box_enabled] - does the user have 3box sync
* enabled? * enabled?
* @property {string} [theme] - which theme the user has selected * @property {string} [theme] - which theme the user has selected
* @property {boolean} [token_detection_enabled] - does the user have token detection is enabled?
*/ */
// Mixpanel converts the zero address value to a truly anonymous event, which // Mixpanel converts the zero address value to a truly anonymous event, which
@ -265,10 +269,15 @@ export const REJECT_NOTFICIATION_CLOSE_SIG =
*/ */
export const EVENT_NAMES = { export const EVENT_NAMES = {
SIGNATURE_REQUESTED: 'Signature Requested',
ENCRYPTION_PUBLIC_KEY_REQUESTED: 'Encryption Public Key Requested', ENCRYPTION_PUBLIC_KEY_REQUESTED: 'Encryption Public Key Requested',
DECRYPTION_REQUESTED: 'Decryption Requested', DECRYPTION_REQUESTED: 'Decryption Requested',
PERMISSIONS_REQUESTED: 'Permissions Requested', PERMISSIONS_REQUESTED: 'Permissions Requested',
SIGNATURE_REQUESTED: 'Signature Requested',
TOKEN_ADDED: 'Token Added',
TOKEN_DETECTED: 'Token Detected',
TOKEN_HIDDEN: 'Token Hidden',
TOKEN_IMPORT_CANCELED: 'Token Import Canceled',
TOKEN_IMPORT_CLICKED: 'Token Import Clicked',
}; };
export const EVENT = { export const EVENT = {
@ -288,4 +297,25 @@ export const EVENT = {
TRANSACTIONS: 'Transactions', TRANSACTIONS: 'Transactions',
WALLET: 'Wallet', WALLET: 'Wallet',
}, },
SOURCE: {
SWAPS: {
MAIN_VIEW: 'Main View',
TOKEN_VIEW: 'Token View',
},
TRANSACTION: {
USER: 'user',
DAPP: 'dapp',
},
TOKEN: {
CUSTOM: 'custom',
DETECTED: 'detected',
DAPP: 'dapp',
LIST: 'list',
},
},
LOCATION: {
TOKEN_DETECTION: 'token_detection',
TOKEN_MENU: 'token_menu',
TOKEN_DETAILS: 'token_details',
},
}; };

@ -1,4 +1,4 @@
import React from 'react'; import React, { useContext } from 'react';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import classNames from 'classnames'; import classNames from 'classnames';
@ -7,11 +7,32 @@ import Box from '../../../ui/box/box';
import Button from '../../../ui/button'; import Button from '../../../ui/button';
import { useI18nContext } from '../../../../hooks/useI18nContext'; import { useI18nContext } from '../../../../hooks/useI18nContext';
import { getDetectedTokensInCurrentNetwork } from '../../../../selectors'; import { getDetectedTokensInCurrentNetwork } from '../../../../selectors';
import { MetaMetricsContext } from '../../../../contexts/metametrics';
import {
EVENT,
EVENT_NAMES,
} from '../../../../../shared/constants/metametrics';
const DetectedTokensLink = ({ className = '', setShowDetectedTokens }) => { const DetectedTokensLink = ({ className = '', setShowDetectedTokens }) => {
const t = useI18nContext(); const t = useI18nContext();
const trackEvent = useContext(MetaMetricsContext);
const detectedTokens = useSelector(getDetectedTokensInCurrentNetwork); const detectedTokens = useSelector(getDetectedTokensInCurrentNetwork);
const detectedTokensDetails = detectedTokens.map(
({ address, symbol }) => `${symbol} - ${address}`,
);
const onClick = () => {
setShowDetectedTokens(true);
trackEvent({
event: EVENT_NAMES.TOKEN_IMPORT_CLICKED,
category: EVENT.CATEGORIES.WALLET,
properties: {
source: EVENT.SOURCE.TOKEN.DETECTED,
tokens: detectedTokensDetails,
},
});
};
return ( return (
<Box <Box
className={classNames('detected-tokens-link', className)} className={classNames('detected-tokens-link', className)}
@ -20,7 +41,7 @@ const DetectedTokensLink = ({ className = '', setShowDetectedTokens }) => {
<Button <Button
type="link" type="link"
className="detected-tokens-link__link" className="detected-tokens-link__link"
onClick={() => setShowDetectedTokens(true)} onClick={onClick}
> >
{t('numberOfNewTokensDetected', [detectedTokens.length])} {t('numberOfNewTokensDetected', [detectedTokens.length])}
</Button> </Button>

@ -0,0 +1,28 @@
import React from 'react';
import { Provider } from 'react-redux';
import testData from '../../../../../.storybook/test-data';
import configureStore from '../../../../store/store';
import DetectedTokensLink from './detected-tokens-link';
const store = configureStore(testData);
export default {
title: 'Components/App/AssetList/DetectedTokensLink',
decorators: [(story) => <Provider store={store}>{story()}</Provider>],
id: __filename,
argTypes: {
setShowDetectedTokens: { control: 'func' },
},
args: {
setShowDetectedTokens: 'setShowDetectedTokensSpy',
},
};
const Template = (args) => {
return <DetectedTokensLink {...args} />;
};
export const DefaultStory = Template.bind({});
DefaultStory.storyName = 'Default';

@ -0,0 +1,32 @@
import * as React from 'react';
import {
renderWithProvider,
screen,
fireEvent,
} from '../../../../../test/jest';
import configureStore from '../../../../store/store';
import testData from '../../../../../.storybook/test-data';
import DetectedTokensLink from './detected-tokens-link';
describe('DetectedTokensLink', () => {
let setShowDetectedTokensSpy;
const args = {};
beforeEach(() => {
setShowDetectedTokensSpy = jest.fn();
args.setShowDetectedTokens = setShowDetectedTokensSpy;
});
it('should render number of tokens detected link', () => {
const store = configureStore(testData);
renderWithProvider(<DetectedTokensLink {...args} />, store);
expect(
screen.getByText('3 new tokens found in this account'),
).toBeInTheDocument();
fireEvent.click(screen.getByText('3 new tokens found in this account'));
expect(setShowDetectedTokensSpy).toHaveBeenCalled();
});
});

@ -1,8 +1,13 @@
import React from 'react'; import React, { useContext } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { useI18nContext } from '../../../../hooks/useI18nContext'; import { useI18nContext } from '../../../../hooks/useI18nContext';
import { MetaMetricsContext } from '../../../../contexts/metametrics';
import {
EVENT,
EVENT_NAMES,
} from '../../../../../shared/constants/metametrics';
import { getDetectedTokensInCurrentNetwork } from '../../../../selectors'; import { getDetectedTokensInCurrentNetwork } from '../../../../selectors';
import Popover from '../../../ui/popover'; import Popover from '../../../ui/popover';
@ -19,6 +24,7 @@ const DetectedTokenSelectionPopover = ({
sortingBasedOnTokenSelection, sortingBasedOnTokenSelection,
}) => { }) => {
const t = useI18nContext(); const t = useI18nContext();
const trackEvent = useContext(MetaMetricsContext);
const detectedTokens = useSelector(getDetectedTokensInCurrentNetwork); const detectedTokens = useSelector(getDetectedTokensInCurrentNetwork);
const { selected: selectedTokens = [] } = sortingBasedOnTokenSelection( const { selected: selectedTokens = [] } = sortingBasedOnTokenSelection(
@ -31,6 +37,17 @@ const DetectedTokenSelectionPopover = ({
const onClose = () => { const onClose = () => {
setShowDetectedTokens(false); setShowDetectedTokens(false);
const eventTokensDetails = detectedTokens.map(
({ address, symbol }) => `${symbol} - ${address}`,
);
trackEvent({
event: EVENT_NAMES.TOKEN_IMPORT_CANCELED,
category: EVENT.CATEGORIES.WALLET,
properties: {
source: EVENT.SOURCE.TOKEN.DETECTED,
tokens: eventTokensDetails,
},
});
}; };
const footer = ( const footer = (

@ -1,4 +1,4 @@
import React, { useState } from 'react'; import React, { useState, useContext } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { useSelector, useDispatch } from 'react-redux'; import { useSelector, useDispatch } from 'react-redux';
import { chain } from 'lodash'; import { chain } from 'lodash';
@ -9,7 +9,11 @@ import {
setNewTokensImported, setNewTokensImported,
} from '../../../store/actions'; } from '../../../store/actions';
import { getDetectedTokensInCurrentNetwork } from '../../../selectors'; import { getDetectedTokensInCurrentNetwork } from '../../../selectors';
import { MetaMetricsContext } from '../../../contexts/metametrics';
import { TOKEN_STANDARDS } from '../../../helpers/constants/common';
import { ASSET_TYPES } from '../../../../shared/constants/transaction';
import { EVENT, EVENT_NAMES } from '../../../../shared/constants/metametrics';
import DetectedTokenSelectionPopover from './detected-token-selection-popover/detected-token-selection-popover'; import DetectedTokenSelectionPopover from './detected-token-selection-popover/detected-token-selection-popover';
import DetectedTokenIgnoredPopover from './detected-token-ignored-popover/detected-token-ignored-popover'; import DetectedTokenIgnoredPopover from './detected-token-ignored-popover/detected-token-ignored-popover';
@ -26,8 +30,10 @@ const sortingBasedOnTokenSelection = (tokensDetected) => {
.value() .value()
); );
}; };
const DetectedToken = ({ setShowDetectedTokens }) => { const DetectedToken = ({ setShowDetectedTokens }) => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const trackEvent = useContext(MetaMetricsContext);
const detectedTokens = useSelector(getDetectedTokensInCurrentNetwork); const detectedTokens = useSelector(getDetectedTokensInCurrentNetwork);
@ -42,21 +48,49 @@ const DetectedToken = ({ setShowDetectedTokens }) => {
setShowDetectedTokenIgnoredPopover, setShowDetectedTokenIgnoredPopover,
] = useState(false); ] = useState(false);
const importSelectedTokens = async (selectedTokens) => {
selectedTokens.forEach((importedToken) => {
trackEvent({
event: EVENT_NAMES.TOKEN_ADDED,
category: EVENT.CATEGORIES.WALLET,
sensitiveProperties: {
token_symbol: importedToken.symbol,
token_contract_address: importedToken.address,
token_decimal_precision: importedToken.decimals,
source: EVENT.SOURCE.TOKEN.DETECTED,
token_standard: TOKEN_STANDARDS.ERC20,
asset_type: ASSET_TYPES.TOKEN,
},
});
});
await dispatch(importTokens(selectedTokens));
const tokenSymbols = selectedTokens.map(({ symbol }) => symbol);
dispatch(setNewTokensImported(tokenSymbols.join(', ')));
};
const handleClearTokensSelection = async () => { const handleClearTokensSelection = async () => {
// create a lodash chain on this object
const { const {
selected: selectedTokens, selected: selectedTokens = [],
deselected: deSelectedTokens, deselected: deSelectedTokens = [],
} = sortingBasedOnTokenSelection(tokensListDetected); } = sortingBasedOnTokenSelection(tokensListDetected);
if (deSelectedTokens.length < detectedTokens.length) { if (deSelectedTokens.length < detectedTokens.length) {
await dispatch(ignoreTokens(deSelectedTokens)); await importSelectedTokens(selectedTokens);
await dispatch(importTokens(selectedTokens));
const tokenSymbols = selectedTokens.map(({ symbol }) => symbol);
dispatch(setNewTokensImported(tokenSymbols.join(', ')));
} else {
await dispatch(ignoreTokens(deSelectedTokens));
} }
const tokensDetailsList = deSelectedTokens.map(
({ symbol, address }) => `${symbol} - ${address}`,
);
trackEvent({
event: EVENT_NAMES.TOKEN_HIDDEN,
category: EVENT.CATEGORIES.WALLET,
sensitiveProperties: {
tokens: tokensDetailsList,
location: EVENT.LOCATION.TOKEN_DETECTION,
token_standard: TOKEN_STANDARDS.ERC20,
asset_type: ASSET_TYPES.TOKEN,
},
});
await dispatch(ignoreTokens(deSelectedTokens));
setShowDetectedTokens(false); setShowDetectedTokens(false);
}; };
@ -71,17 +105,14 @@ const DetectedToken = ({ setShowDetectedTokens }) => {
}; };
const onImport = async () => { const onImport = async () => {
// create a lodash chain on this object const { selected: selectedTokens = [] } = sortingBasedOnTokenSelection(
const { selected: selectedTokens } = sortingBasedOnTokenSelection(
tokensListDetected, tokensListDetected,
); );
if (selectedTokens.length < detectedTokens.length) { if (selectedTokens.length < detectedTokens.length) {
setShowDetectedTokenIgnoredPopover(true); setShowDetectedTokenIgnoredPopover(true);
} else { } else {
const tokenSymbols = selectedTokens.map(({ symbol }) => symbol); await importSelectedTokens(selectedTokens);
await dispatch(importTokens(selectedTokens));
dispatch(setNewTokensImported(tokenSymbols.join(', ')));
setShowDetectedTokens(false); setShowDetectedTokens(false);
} }
}; };

@ -136,7 +136,7 @@ const EthOverview = ({ className }) => {
event: 'Swaps Opened', event: 'Swaps Opened',
category: EVENT.CATEGORIES.SWAPS, category: EVENT.CATEGORIES.SWAPS,
properties: { properties: {
source: 'Main View', source: EVENT.SOURCE.SWAPS.MAIN_VIEW,
active_currency: 'ETH', active_currency: 'ETH',
}, },
}); });

@ -120,7 +120,7 @@ const TokenOverview = ({ className, token }) => {
event: 'Swaps Opened', event: 'Swaps Opened',
category: EVENT.CATEGORIES.SWAPS, category: EVENT.CATEGORIES.SWAPS,
properties: { properties: {
source: 'Token View', source: EVENT.SOURCE.SWAPS.TOKEN_VIEW,
active_currency: token.symbol, active_currency: token.symbol,
}, },
}); });

@ -27,6 +27,7 @@ import { getCollectiblesDetectionNoticeDismissed } from '../../ducks/metamask/me
import CollectiblesDetectionNotice from '../../components/app/collectibles-detection-notice'; import CollectiblesDetectionNotice from '../../components/app/collectibles-detection-notice';
import { MetaMetricsContext } from '../../contexts/metametrics'; import { MetaMetricsContext } from '../../contexts/metametrics';
import { ASSET_TYPES } from '../../../shared/constants/transaction'; import { ASSET_TYPES } from '../../../shared/constants/transaction';
import { EVENT, EVENT_NAMES } from '../../../shared/constants/metametrics';
export default function AddCollectible() { export default function AddCollectible() {
const t = useI18nContext(); const t = useI18nContext();
@ -77,7 +78,7 @@ export default function AddCollectible() {
); );
trackEvent({ trackEvent({
event: 'Token Added', event: EVENT_NAMES.TOKEN_ADDED,
category: 'Wallet', category: 'Wallet',
sensitiveProperties: { sensitiveProperties: {
token_contract_address: address, token_contract_address: address,
@ -85,7 +86,7 @@ export default function AddCollectible() {
tokenId: tokenId.toString(), tokenId: tokenId.toString(),
asset_type: ASSET_TYPES.COLLECTIBLE, asset_type: ASSET_TYPES.COLLECTIBLE,
token_standard: tokenDetails?.standard, token_standard: tokenDetails?.standard,
source: 'custom', source: EVENT.SOURCE.TOKEN.CUSTOM,
}, },
}); });

@ -14,7 +14,7 @@ import { isEqualCaseInsensitive } from '../../../shared/modules/string-utils';
import { getSuggestedAssets } from '../../selectors'; import { getSuggestedAssets } from '../../selectors';
import { rejectWatchAsset, acceptWatchAsset } from '../../store/actions'; import { rejectWatchAsset, acceptWatchAsset } from '../../store/actions';
import { TOKEN_STANDARDS } from '../../helpers/constants/common'; import { TOKEN_STANDARDS } from '../../helpers/constants/common';
import { EVENT } from '../../../shared/constants/metametrics'; import { EVENT, EVENT_NAMES } from '../../../shared/constants/metametrics';
import { ASSET_TYPES } from '../../../shared/constants/transaction'; import { ASSET_TYPES } from '../../../shared/constants/transaction';
function getTokenName(name, symbol) { function getTokenName(name, symbol) {
@ -115,14 +115,14 @@ const ConfirmAddSuggestedToken = () => {
await dispatch(acceptWatchAsset(id)); await dispatch(acceptWatchAsset(id));
trackEvent({ trackEvent({
event: 'Token Added', event: EVENT_NAMES.TOKEN_ADDED,
category: EVENT.CATEGORIES.WALLET, category: EVENT.CATEGORIES.WALLET,
sensitiveProperties: { sensitiveProperties: {
token_symbol: asset.symbol, token_symbol: asset.symbol,
token_contract_address: asset.address, token_contract_address: asset.address,
token_decimal_precision: asset.decimals, token_decimal_precision: asset.decimals,
unlisted: asset.unlisted, unlisted: asset.unlisted,
source: 'dapp', source: EVENT.SOURCE.TOKEN.DAPP,
token_standard: TOKEN_STANDARDS.ERC20, token_standard: TOKEN_STANDARDS.ERC20,
asset_type: ASSET_TYPES.TOKEN, asset_type: ASSET_TYPES.TOKEN,
}, },

@ -13,7 +13,8 @@ import { MetaMetricsContext } from '../../contexts/metametrics';
import { getMostRecentOverviewPage } from '../../ducks/history/history'; import { getMostRecentOverviewPage } from '../../ducks/history/history';
import { getPendingTokens } from '../../ducks/metamask/metamask'; import { getPendingTokens } from '../../ducks/metamask/metamask';
import { addTokens, clearPendingTokens } from '../../store/actions'; import { addTokens, clearPendingTokens } from '../../store/actions';
import { EVENT } from '../../../shared/constants/metametrics'; import { TOKEN_STANDARDS } from '../../helpers/constants/common';
import { EVENT, EVENT_NAMES } from '../../../shared/constants/metametrics';
import { ASSET_TYPES } from '../../../shared/constants/transaction'; import { ASSET_TYPES } from '../../../shared/constants/transaction';
const getTokenName = (name, symbol) => { const getTokenName = (name, symbol) => {
@ -37,15 +38,17 @@ const ConfirmImportToken = () => {
addedTokenValues.forEach((pendingToken) => { addedTokenValues.forEach((pendingToken) => {
trackEvent({ trackEvent({
event: 'Token Added', event: EVENT_NAMES.TOKEN_ADDED,
category: EVENT.CATEGORIES.WALLET, category: EVENT.CATEGORIES.WALLET,
sensitiveProperties: { sensitiveProperties: {
token_symbol: pendingToken.symbol, token_symbol: pendingToken.symbol,
token_contract_address: pendingToken.address, token_contract_address: pendingToken.address,
token_decimal_precision: pendingToken.decimals, token_decimal_precision: pendingToken.decimals,
unlisted: pendingToken.unlisted, unlisted: pendingToken.unlisted,
source: pendingToken.isCustom ? 'custom' : 'list', source: pendingToken.isCustom
token_standard: pendingToken.standard, ? EVENT.SOURCE.TOKEN.CUSTOM
: EVENT.SOURCE.TOKEN.LIST,
token_standard: TOKEN_STANDARDS.ERC20,
asset_type: ASSET_TYPES.TOKEN, asset_type: ASSET_TYPES.TOKEN,
}, },
}); });

Loading…
Cancel
Save