Commit bcd4c1c1 authored by lynn's avatar lynn Committed by GitHub

feat: only track usdc, weth, native token balances (#4424)

* init

* fix unit test

* extract log token logic into custom hook
parent d954026c
import { Token } from '@uniswap/sdk-core'
import { nativeOnChain } from '../../constants/tokens'
/** /**
* Event names that can occur in this application. * Event names that can occur in this application.
* *
...@@ -37,14 +41,21 @@ export enum CUSTOM_USER_PROPERTIES { ...@@ -37,14 +41,21 @@ export enum CUSTOM_USER_PROPERTIES {
SCREEN_RESOLUTION_HEIGHT = 'screen_resolution_height', SCREEN_RESOLUTION_HEIGHT = 'screen_resolution_height',
SCREEN_RESOLUTION_WIDTH = 'screen_resolution_width', SCREEN_RESOLUTION_WIDTH = 'screen_resolution_width',
WALLET_ADDRESS = 'wallet_address', WALLET_ADDRESS = 'wallet_address',
WALLET_NATIVE_CURRENCY_AMOUNT = 'wallet_native_currency_amount',
WALLET_NATIVE_CURRENCY_BALANCE_USD = 'wallet_native_currency_balance_usd', WALLET_NATIVE_CURRENCY_BALANCE_USD = 'wallet_native_currency_balance_usd',
WALLET_TOKENS_ADDRESSES = 'wallet_tokens_addresses',
WALLET_TOKENS_SYMBOLS = 'wallet_tokens_symbols',
WALLET_TYPE = 'wallet_type', WALLET_TYPE = 'wallet_type',
WALLET_USDC_AMOUNT = 'wallet_usdc_amount',
WALLET_USDC_BALANCE_USD = 'wallet_usdc_balance_usd',
WALLET_WETH_AMOUNT = 'wallet_weth_amount',
WALLET_WETH_BALANCE_USD = 'wallet_weth_balance_usd',
} }
export enum CUSTOM_USER_PROPERTY_SUFFIXES { const ETH = nativeOnChain(1)
WALLET_TOKEN_AMOUNT_SUFFIX = '_token_amount', const USDC = new Token(1, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC')
export const TOKENS_TO_TRACK = {
USDC,
WETH: ETH.wrapped,
} }
export enum BROWSER { export enum BROWSER {
......
import { Currency, CurrencyAmount } from '@uniswap/sdk-core' import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core'
import * as connectionUtils from 'connection/utils' import * as connectionUtils from 'connection/utils'
import JSBI from 'jsbi'
import { ApplicationModal } from 'state/application/reducer' import { ApplicationModal } from 'state/application/reducer'
import { nativeOnChain } from '../../constants/tokens' import { nativeOnChain } from '../../constants/tokens'
...@@ -12,10 +11,7 @@ afterEach(() => { ...@@ -12,10 +11,7 @@ afterEach(() => {
jest.resetModules() jest.resetModules()
}) })
const currencyAmount = (token: Currency, amount: number) => CurrencyAmount.fromRawAmount(token, JSBI.BigInt(amount))
const mockEth = () => nativeOnChain(1) const mockEth = () => nativeOnChain(1)
const mockCurrencyAmount = currencyAmount(mockEth(), 1)
const UserAgentMock = jest.requireMock('utils/userAgent') const UserAgentMock = jest.requireMock('utils/userAgent')
jest.mock('utils/userAgent', () => ({ jest.mock('utils/userAgent', () => ({
...@@ -39,24 +35,14 @@ jest.mock('hooks/useStablecoinPrice', () => { ...@@ -39,24 +35,14 @@ jest.mock('hooks/useStablecoinPrice', () => {
} }
}) })
jest.mock('state/connection/hooks', () => {
return {
useAllTokenBalances: () => {
return [{}, false]
},
}
})
jest.mock('../../hooks/Tokens', () => {
return {
useAllTokens: () => ({}),
}
})
jest.mock('lib/hooks/useCurrencyBalance', () => { jest.mock('lib/hooks/useCurrencyBalance', () => {
return { return {
useCurrencyBalances: (account?: string, currencies?: (Currency | undefined)[]) => { __esModule: true,
return [mockCurrencyAmount] default: (account?: string, currency?: Currency) => {
return
},
useTokenBalance: (account?: string, token?: Token) => {
return
}, },
} }
}) })
......
...@@ -5,23 +5,21 @@ import { Connector } from '@web3-react/types' ...@@ -5,23 +5,21 @@ import { Connector } from '@web3-react/types'
import { sendAnalyticsEvent, user } from 'components/AmplitudeAnalytics' import { sendAnalyticsEvent, user } from 'components/AmplitudeAnalytics'
import { import {
CUSTOM_USER_PROPERTIES, CUSTOM_USER_PROPERTIES,
CUSTOM_USER_PROPERTY_SUFFIXES,
EventName, EventName,
TOKENS_TO_TRACK,
WALLET_CONNECTION_RESULT, WALLET_CONNECTION_RESULT,
} from 'components/AmplitudeAnalytics/constants' } from 'components/AmplitudeAnalytics/constants'
import { formatToDecimal, getTokenAddress } from 'components/AmplitudeAnalytics/utils' import { formatToDecimal } from 'components/AmplitudeAnalytics/utils'
import { sendEvent } from 'components/analytics' import { sendEvent } from 'components/analytics'
import { AutoColumn } from 'components/Column' import { AutoColumn } from 'components/Column'
import { AutoRow } from 'components/Row' import { AutoRow } from 'components/Row'
import { getConnection, getConnectionName, getIsCoinbaseWallet, getIsInjected, getIsMetaMask } from 'connection/utils' import { getConnection, getConnectionName, getIsCoinbaseWallet, getIsInjected, getIsMetaMask } from 'connection/utils'
import { RedesignVariant, useRedesignFlag } from 'featureFlags/flags/redesign' import { RedesignVariant, useRedesignFlag } from 'featureFlags/flags/redesign'
import { useStablecoinValue } from 'hooks/useStablecoinPrice' import { useStablecoinValue } from 'hooks/useStablecoinPrice'
import { useCurrencyBalances } from 'lib/hooks/useCurrencyBalance' import useCurrencyBalance, { useTokenBalance } from 'lib/hooks/useCurrencyBalance'
import useNativeCurrency from 'lib/hooks/useNativeCurrency' import useNativeCurrency from 'lib/hooks/useNativeCurrency'
import { tokenComparator } from 'lib/hooks/useTokenList/sorting' import { useCallback, useEffect, useState } from 'react'
import { useCallback, useEffect, useMemo, useState } from 'react'
import { ArrowLeft } from 'react-feather' import { ArrowLeft } from 'react-feather'
import { useAllTokenBalances } from 'state/connection/hooks'
import { updateConnectionError } from 'state/connection/reducer' import { updateConnectionError } from 'state/connection/reducer'
import { useAppDispatch, useAppSelector } from 'state/hooks' import { useAppDispatch, useAppSelector } from 'state/hooks'
import { updateSelectedWallet } from 'state/user/reducer' import { updateSelectedWallet } from 'state/user/reducer'
...@@ -30,7 +28,6 @@ import styled from 'styled-components/macro' ...@@ -30,7 +28,6 @@ import styled from 'styled-components/macro'
import { isMobile } from 'utils/userAgent' import { isMobile } from 'utils/userAgent'
import { ReactComponent as Close } from '../../assets/images/x.svg' import { ReactComponent as Close } from '../../assets/images/x.svg'
import { useAllTokens } from '../../hooks/Tokens'
import { useModalIsOpen, useToggleWalletModal } from '../../state/application/hooks' import { useModalIsOpen, useToggleWalletModal } from '../../state/application/hooks'
import { ApplicationModal } from '../../state/application/reducer' import { ApplicationModal } from '../../state/application/reducer'
import { ExternalLink, ThemedText } from '../../theme' import { ExternalLink, ThemedText } from '../../theme'
...@@ -131,29 +128,6 @@ const WALLET_VIEWS = { ...@@ -131,29 +128,6 @@ const WALLET_VIEWS = {
PENDING: 'pending', PENDING: 'pending',
} }
const sendAnalyticsWalletBalanceUserInfo = (
balances: (CurrencyAmount<Currency> | undefined)[],
nativeCurrencyBalanceUsd: number
) => {
const walletTokensSymbols: string[] = []
const walletTokensAddresses: string[] = []
balances.forEach((currencyAmount) => {
if (currencyAmount !== undefined) {
const tokenBalanceAmount = formatToDecimal(currencyAmount, currencyAmount.currency.decimals)
if (tokenBalanceAmount > 0) {
const tokenAddress = getTokenAddress(currencyAmount.currency)
walletTokensAddresses.push(getTokenAddress(currencyAmount.currency))
walletTokensSymbols.push(currencyAmount.currency.symbol ?? '')
const tokenPrefix = currencyAmount.currency.symbol ?? tokenAddress
user.set(`${tokenPrefix}${CUSTOM_USER_PROPERTY_SUFFIXES.WALLET_TOKEN_AMOUNT_SUFFIX}`, tokenBalanceAmount)
}
}
})
user.set(CUSTOM_USER_PROPERTIES.WALLET_NATIVE_CURRENCY_BALANCE_USD, nativeCurrencyBalanceUsd)
user.set(CUSTOM_USER_PROPERTIES.WALLET_TOKENS_ADDRESSES, walletTokensAddresses)
user.set(CUSTOM_USER_PROPERTIES.WALLET_TOKENS_SYMBOLS, walletTokensSymbols)
}
const sendAnalyticsEventAndUserInfo = ( const sendAnalyticsEventAndUserInfo = (
account: string, account: string,
walletType: string, walletType: string,
...@@ -174,6 +148,32 @@ const sendAnalyticsEventAndUserInfo = ( ...@@ -174,6 +148,32 @@ const sendAnalyticsEventAndUserInfo = (
user.postInsert(CUSTOM_USER_PROPERTIES.ALL_WALLET_ADDRESSES_CONNECTED, account) user.postInsert(CUSTOM_USER_PROPERTIES.ALL_WALLET_ADDRESSES_CONNECTED, account)
} }
function useLogToken(
tokenBalanceUsdValue: string | undefined,
tokenBalance: CurrencyAmount<Token | Currency> | undefined,
shouldLogTokenBalance: boolean,
setShouldLogTokenBalance: (shouldLog: boolean) => void,
tokenAmountProperty: string,
tokenUsdBalanceProperty: string
) {
useEffect(() => {
if (shouldLogTokenBalance && tokenBalance && tokenBalanceUsdValue) {
const tokenBalanceUsd = tokenBalanceUsdValue ? parseFloat(tokenBalanceUsdValue) : 0
const tokenBalanceAmount = formatToDecimal(tokenBalance, tokenBalance.currency.decimals)
user.set(tokenAmountProperty, tokenBalanceAmount)
user.set(tokenUsdBalanceProperty, tokenBalanceUsd)
setShouldLogTokenBalance(false)
}
}, [
tokenBalanceUsdValue,
tokenBalance,
shouldLogTokenBalance,
setShouldLogTokenBalance,
tokenAmountProperty,
tokenUsdBalanceProperty,
])
}
export default function WalletModal({ export default function WalletModal({
pendingTransactions, pendingTransactions,
confirmedTransactions, confirmedTransactions,
...@@ -191,7 +191,9 @@ export default function WalletModal({ ...@@ -191,7 +191,9 @@ export default function WalletModal({
const redesignFlagEnabled = redesignFlag === RedesignVariant.Enabled const redesignFlagEnabled = redesignFlag === RedesignVariant.Enabled
const [walletView, setWalletView] = useState(WALLET_VIEWS.ACCOUNT) const [walletView, setWalletView] = useState(WALLET_VIEWS.ACCOUNT)
const [lastActiveWalletAddress, setLastActiveWalletAddress] = useState<string | undefined>(account) const [lastActiveWalletAddress, setLastActiveWalletAddress] = useState<string | undefined>(account)
const [shouldLogWalletBalances, setShouldLogWalletBalances] = useState(false) const [shouldLogUsdcBalance, setShouldLogUsdcBalance] = useState(false)
const [shouldLogWethBalance, setShouldLogWethBalance] = useState(false)
const [shouldLogNativeBalance, setShouldLogNativeBalance] = useState(false)
const [pendingConnector, setPendingConnector] = useState<Connector | undefined>() const [pendingConnector, setPendingConnector] = useState<Connector | undefined>()
const pendingError = useAppSelector((state) => const pendingError = useAppSelector((state) =>
...@@ -201,24 +203,14 @@ export default function WalletModal({ ...@@ -201,24 +203,14 @@ export default function WalletModal({
const walletModalOpen = useModalIsOpen(ApplicationModal.WALLET) const walletModalOpen = useModalIsOpen(ApplicationModal.WALLET)
const toggleWalletModal = useToggleWalletModal() const toggleWalletModal = useToggleWalletModal()
const allTokens = useAllTokens()
const [tokenBalances, tokenBalancesIsLoading] = useAllTokenBalances()
const sortedTokens: Token[] = useMemo(
() => (!tokenBalancesIsLoading ? Object.values(allTokens).sort(tokenComparator.bind(null, tokenBalances)) : []),
[tokenBalances, allTokens, tokenBalancesIsLoading]
)
const native = useNativeCurrency() const native = useNativeCurrency()
const usdcBalance = useTokenBalance(account, TOKENS_TO_TRACK.USDC)
const wethBalance = useTokenBalance(account, TOKENS_TO_TRACK.WETH)
const nativeCurrencyBalance = useCurrencyBalance(account, native)
const sortedTokensWithETH: Currency[] = useMemo( const usdcBalanceUsdValue = useStablecoinValue(usdcBalance)?.toFixed(2)
() => const wethBalanceUsdValue = useStablecoinValue(wethBalance)?.toFixed(2)
// Always bump the native token to the top of the list. const nativeCurrencyBalanceUsdValue = useStablecoinValue(nativeCurrencyBalance)?.toFixed(2)
native ? [native, ...sortedTokens.filter((t) => !t.equals(native))] : sortedTokens,
[native, sortedTokens]
)
const balances = useCurrencyBalances(account, sortedTokensWithETH)
const nativeBalance = balances.length > 0 ? balances[0] : null
const nativeCurrencyBalanceUsdValue = useStablecoinValue(nativeBalance)?.toFixed(2)
const openOptions = useCallback(() => { const openOptions = useCallback(() => {
setWalletView(WALLET_VIEWS.OPTIONS) setWalletView(WALLET_VIEWS.OPTIONS)
...@@ -244,28 +236,39 @@ export default function WalletModal({ ...@@ -244,28 +236,39 @@ export default function WalletModal({
const isReconnect = const isReconnect =
connectedWallets.filter((wallet) => wallet.account === account && wallet.walletType === walletType).length > 0 connectedWallets.filter((wallet) => wallet.account === account && wallet.walletType === walletType).length > 0
sendAnalyticsEventAndUserInfo(account, walletType, chainId, isReconnect) sendAnalyticsEventAndUserInfo(account, walletType, chainId, isReconnect)
setShouldLogWalletBalances(true) setShouldLogNativeBalance(true)
setShouldLogUsdcBalance(true)
setShouldLogWethBalance(true)
if (!isReconnect) addWalletToConnectedWallets({ account, walletType }) if (!isReconnect) addWalletToConnectedWallets({ account, walletType })
} }
setLastActiveWalletAddress(account) setLastActiveWalletAddress(account)
}, [connectedWallets, addWalletToConnectedWallets, lastActiveWalletAddress, account, connector, chainId]) }, [connectedWallets, addWalletToConnectedWallets, lastActiveWalletAddress, account, connector, chainId])
// Send wallet balance info once it becomes available. // Send wallet balances info once it becomes available.
useEffect(() => { useLogToken(
if (!tokenBalancesIsLoading && shouldLogWalletBalances && balances && nativeCurrencyBalanceUsdValue) {
const nativeCurrencyBalanceUsd =
native && nativeCurrencyBalanceUsdValue ? parseFloat(nativeCurrencyBalanceUsdValue) : 0
sendAnalyticsWalletBalanceUserInfo(balances, nativeCurrencyBalanceUsd)
setShouldLogWalletBalances(false)
}
}, [
balances,
nativeCurrencyBalanceUsdValue, nativeCurrencyBalanceUsdValue,
shouldLogWalletBalances, nativeCurrencyBalance,
setShouldLogWalletBalances, shouldLogNativeBalance,
tokenBalancesIsLoading, setShouldLogNativeBalance,
native, CUSTOM_USER_PROPERTIES.WALLET_NATIVE_CURRENCY_AMOUNT,
]) CUSTOM_USER_PROPERTIES.WALLET_NATIVE_CURRENCY_BALANCE_USD
)
useLogToken(
usdcBalanceUsdValue,
usdcBalance,
shouldLogUsdcBalance,
setShouldLogUsdcBalance,
CUSTOM_USER_PROPERTIES.WALLET_USDC_AMOUNT,
CUSTOM_USER_PROPERTIES.WALLET_USDC_BALANCE_USD
)
useLogToken(
wethBalanceUsdValue,
wethBalance,
shouldLogWethBalance,
setShouldLogWethBalance,
CUSTOM_USER_PROPERTIES.WALLET_WETH_AMOUNT,
CUSTOM_USER_PROPERTIES.WALLET_USDC_BALANCE_USD
)
const tryActivation = useCallback( const tryActivation = useCallback(
async (connector: Connector) => { async (connector: Connector) => {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment