From daf783a0d8cb9069277174edc3e50f0451a06601 Mon Sep 17 00:00:00 2001 From: Brad Decker Date: Tue, 17 Nov 2020 11:39:21 -0600 Subject: [PATCH] Track a new schema event when adding a token (#9810) Co-authored-by: Mark Stacey --- app/scripts/controllers/preferences.js | 9 ++++++++- shared/constants/tokens.js | 10 ++++++++++ .../confirm-add-suggested-token.component.js | 14 ++++++++++++++ .../confirm-add-token.component.js | 19 ++++++++++++++++--- ui/app/store/actions.js | 15 ++++++++++++++- 5 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 shared/constants/tokens.js diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 5df65dfe5..5e376a797 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -5,6 +5,7 @@ import { isValidAddress, sha3, bufferToHex } from 'ethereumjs-util' import ethers from 'ethers' import log from 'loglevel' import { isPrefixedFormattedHexString } from '../lib/util' +import { LISTED_CONTRACT_ADDRESSES } from '../../../shared/constants/tokens' import { addInternalMethodPrefix } from './permissions' import { NETWORK_TYPE_TO_ID_MAP } from './network/enums' @@ -175,7 +176,13 @@ export default class PreferencesController { const suggested = this.getSuggestedTokens() const { rawAddress, symbol, decimals, image } = tokenOpts const address = normalizeAddress(rawAddress) - const newEntry = { address, symbol, decimals, image } + const newEntry = { + address, + symbol, + decimals, + image, + unlisted: !LISTED_CONTRACT_ADDRESSES.includes(address.toLowerCase()), + } suggested[address] = newEntry this.store.updateState({ suggestedTokens: suggested }) } diff --git a/shared/constants/tokens.js b/shared/constants/tokens.js new file mode 100644 index 000000000..a31c1ec18 --- /dev/null +++ b/shared/constants/tokens.js @@ -0,0 +1,10 @@ +import contractMap from 'eth-contract-metadata' + +/** + * A normalized list of addresses exported as part of the contractMap in + * eth-contract-metadata. Used primarily to validate if manually entered + * contract addresses do not match one of our listed tokens + */ +export const LISTED_CONTRACT_ADDRESSES = Object.keys( + contractMap, +).map((address) => address.toLowerCase()) diff --git a/ui/app/pages/confirm-add-suggested-token/confirm-add-suggested-token.component.js b/ui/app/pages/confirm-add-suggested-token/confirm-add-suggested-token.component.js index 8243a10bb..2ef4e0ea3 100644 --- a/ui/app/pages/confirm-add-suggested-token/confirm-add-suggested-token.component.js +++ b/ui/app/pages/confirm-add-suggested-token/confirm-add-suggested-token.component.js @@ -9,6 +9,7 @@ import { ENVIRONMENT_TYPE_NOTIFICATION } from '../../../../app/scripts/lib/enums export default class ConfirmAddSuggestedToken extends Component { static contextTypes = { t: PropTypes.func, + trackEvent: PropTypes.func, } static propTypes = { @@ -139,6 +140,19 @@ export default class ConfirmAddSuggestedToken extends Component { onClick={() => { addToken(pendingToken) .then(() => removeSuggestedTokens()) + .then(() => { + this.context.trackEvent({ + event: 'Token Added', + category: 'Wallet', + sensitiveProperties: { + token_symbol: pendingToken.symbol, + token_contract_address: pendingToken.address, + token_decimal_precision: pendingToken.decimals, + unlisted: pendingToken.unlisted, + source: 'dapp', + }, + }) + }) .then(() => history.push(mostRecentOverviewPage)) }} > diff --git a/ui/app/pages/confirm-add-token/confirm-add-token.component.js b/ui/app/pages/confirm-add-token/confirm-add-token.component.js index 3a0b0b3d0..4334f377a 100644 --- a/ui/app/pages/confirm-add-token/confirm-add-token.component.js +++ b/ui/app/pages/confirm-add-token/confirm-add-token.component.js @@ -8,6 +8,7 @@ import TokenBalance from '../../components/ui/token-balance' export default class ConfirmAddToken extends Component { static contextTypes = { t: PropTypes.func, + trackEvent: PropTypes.func, } static propTypes = { @@ -103,10 +104,22 @@ export default class ConfirmAddToken extends Component { className="page-container__footer-button" onClick={() => { addTokens(pendingTokens).then(() => { + const pendingTokenValues = Object.values(pendingTokens) + pendingTokenValues.forEach((pendingToken) => { + this.context.trackEvent({ + event: 'Token Added', + category: 'Wallet', + sensitiveProperties: { + token_symbol: pendingToken.symbol, + token_contract_address: pendingToken.address, + token_decimal_precision: pendingToken.decimals, + unlisted: pendingToken.unlisted, + source: pendingToken.isCustom ? 'custom' : 'list', + }, + }) + }) clearPendingTokens() - const firstTokenAddress = Object.values( - pendingTokens, - )?.[0].address?.toLowerCase() + const firstTokenAddress = pendingTokenValues?.[0].address?.toLowerCase() if (firstTokenAddress) { history.push(`${ASSET_ROUTE}/${firstTokenAddress}`) } else { diff --git a/ui/app/store/actions.js b/ui/app/store/actions.js index 15daa555c..f9d9de22d 100644 --- a/ui/app/store/actions.js +++ b/ui/app/store/actions.js @@ -23,6 +23,7 @@ import { } from '../selectors' import { switchedToUnconnectedAccount } from '../ducks/alerts/unconnected-account' import { getUnconnectedAccountAlertEnabledness } from '../ducks/metamask/metamask' +import { LISTED_CONTRACT_ADDRESSES } from '../../../shared/constants/tokens' import * as actionConstants from './actionConstants' let background = null @@ -2210,9 +2211,21 @@ export function setPendingTokens(pendingTokens) { const { address, symbol, decimals } = customToken const tokens = address && symbol && decimals - ? { ...selectedTokens, [address]: { ...customToken, isCustom: true } } + ? { + ...selectedTokens, + [address]: { + ...customToken, + isCustom: true, + }, + } : selectedTokens + Object.keys(tokens).forEach((tokenAddress) => { + tokens[tokenAddress].unlisted = !LISTED_CONTRACT_ADDRESSES.includes( + tokenAddress.toLowerCase(), + ) + }) + return { type: actionConstants.SET_PENDING_TOKENS, payload: tokens,