Commit 3ed3ed49 authored by eddie's avatar eddie Committed by GitHub

feat: sort tokens in selector by USD value (#6744)

* feat: sort tokens in selector by USD value

* fix: sync visible balances in list with the sorting values

* fix: tryParseCurrencyAmount

* fix: remove todo

* fix: make shared hook for cached query

* fix: replace true with modalOpen

* fix: default to zero balance

* fix: add test and comment

* feat: fallback to unfilterd tokens

* fix: unconnected balances

* fix: update tests

* fix: test selector
parent 3a0c4ad4
......@@ -58,7 +58,7 @@ describe('Swap', () => {
// Select USDC
cy.get('#swap-currency-output .open-currency-select-button').click()
cy.get(getTestSelector('token-search-input')).type(USDC_MAINNET.address)
cy.contains('USDC').click()
cy.get(getTestSelector('common-base-USDC')).click()
// Enter amount to swap
cy.get('#swap-currency-output .token-amount-input').type('1').should('have.value', '1')
......
......@@ -11,8 +11,6 @@ import { LoadingBubble } from 'components/Tokens/loading'
import { formatDelta } from 'components/Tokens/TokenDetails/PriceChart'
import Tooltip from 'components/Tooltip'
import { getConnection } from 'connection'
import { usePortfolioBalancesQuery } from 'graphql/data/__generated__/types-and-hooks'
import { GQL_MAINNET_CHAINS } from 'graphql/data/util'
import { useDisableNFTRoutes } from 'hooks/useDisableNFTRoutes'
import { useProfilePageState, useSellAsset, useWalletCollections } from 'nft/hooks'
import { useIsNftClaimAvailable } from 'nft/hooks/useIsNftClaimAvailable'
......@@ -34,6 +32,7 @@ import { useToggleAccountDrawer } from '.'
import IconButton, { IconHoverText, IconWithConfirmTextButton } from './IconButton'
import MiniPortfolio from './MiniPortfolio'
import { portfolioFadeInAnimation } from './MiniPortfolio/PortfolioRow'
import { useCachedPortfolioBalancesQuery } from './PrefetchBalancesWrapper'
const AuthenticatedHeaderWrapper = styled.div`
padding: 20px 16px;
......@@ -226,11 +225,7 @@ export default function AuthenticatedHeader({ account, openSettings }: { account
const openFiatOnrampUnavailableTooltip = useCallback(() => setShow(true), [setShow])
const closeFiatOnrampUnavailableTooltip = useCallback(() => setShow(false), [setShow])
const { data: portfolioBalances } = usePortfolioBalancesQuery({
variables: { ownerAddress: account ?? '', chains: GQL_MAINNET_CHAINS },
fetchPolicy: 'cache-only', // PrefetchBalancesWrapper handles balance fetching/staleness; this component only reads from cache
})
const { data: portfolioBalances } = useCachedPortfolioBalancesQuery({ account })
const portfolio = portfolioBalances?.portfolios?.[0]
const totalBalance = portfolio?.tokensTotalDenominatedValue?.value
const absoluteChange = portfolio?.tokensTotalDenominatedValueChange?.absolute?.value
......
import { TraceEvent } from '@uniswap/analytics'
import { BrowserEvent, InterfaceElementName, SharedEventName } from '@uniswap/analytics-events'
import { formatNumber, NumberType } from '@uniswap/conedison/format'
import { useCachedPortfolioBalancesQuery } from 'components/AccountDrawer/PrefetchBalancesWrapper'
import Row from 'components/Row'
import { formatDelta } from 'components/Tokens/TokenDetails/PriceChart'
import { PortfolioBalancesQuery, usePortfolioBalancesQuery } from 'graphql/data/__generated__/types-and-hooks'
import {
getTokenDetailsURL,
GQL_MAINNET_CHAINS,
gqlToCurrency,
logSentryErrorForUnsupportedChain,
} from 'graphql/data/util'
import { PortfolioBalancesQuery } from 'graphql/data/__generated__/types-and-hooks'
import { getTokenDetailsURL, gqlToCurrency, logSentryErrorForUnsupportedChain } from 'graphql/data/util'
import { useAtomValue } from 'jotai/utils'
import { EmptyWalletModule } from 'nft/components/profile/view/EmptyWalletContent'
import { useCallback, useMemo, useState } from 'react'
......@@ -35,11 +31,7 @@ export default function Tokens({ account }: { account: string }) {
const hideSmallBalances = useAtomValue(hideSmallBalancesAtom)
const [showHiddenTokens, setShowHiddenTokens] = useState(false)
const { data } = usePortfolioBalancesQuery({
variables: { ownerAddress: account, chains: GQL_MAINNET_CHAINS },
fetchPolicy: 'cache-only', // PrefetchBalancesWrapper handles balance fetching/staleness; this component only reads from cache
errorPolicy: 'all',
})
const { data } = useCachedPortfolioBalancesQuery({ account })
const visibleTokens = useMemo(() => {
return !hideSmallBalances
......
import { useWeb3React } from '@web3-react/core'
import { usePortfolioBalancesLazyQuery } from 'graphql/data/__generated__/types-and-hooks'
import { usePortfolioBalancesLazyQuery, usePortfolioBalancesQuery } from 'graphql/data/__generated__/types-and-hooks'
import { GQL_MAINNET_CHAINS } from 'graphql/data/util'
import usePrevious from 'hooks/usePrevious'
import { PropsWithChildren, useCallback, useEffect, useMemo, useState } from 'react'
import { atom, useAtom } from 'jotai'
import { PropsWithChildren, useCallback, useEffect, useMemo } from 'react'
import { useAllTransactions } from 'state/transactions/hooks'
import { TransactionDetails } from 'state/transactions/types'
import { useAccountDrawer } from '.'
const isTxPending = (tx: TransactionDetails) => !tx.receipt
function wasPending(previousTxs: { [hash: string]: TransactionDetails | undefined }, current: TransactionDetails) {
const previousTx = previousTxs[current.hash]
......@@ -36,36 +35,50 @@ function useHasUpdatedTx(account: string | undefined) {
}, [account, currentChainTxs, previousPendingTxs])
}
export function useCachedPortfolioBalancesQuery({ account }: { account?: string }) {
return usePortfolioBalancesQuery({
skip: !account,
variables: { ownerAddress: account ?? '', chains: GQL_MAINNET_CHAINS },
fetchPolicy: 'cache-only', // PrefetchBalancesWrapper handles balance fetching/staleness; this component only reads from cache
errorPolicy: 'all',
})
}
const hasUnfetchedBalancesAtom = atom<boolean>(true)
/* Prefetches & caches portfolio balances when the wrapped component is hovered or the user completes a transaction */
export default function PrefetchBalancesWrapper({ children }: PropsWithChildren) {
export default function PrefetchBalancesWrapper({
children,
shouldFetchOnAccountUpdate,
}: PropsWithChildren<{ shouldFetchOnAccountUpdate: boolean }>) {
const { account } = useWeb3React()
const [prefetchPortfolioBalances] = usePortfolioBalancesLazyQuery()
const [drawerOpen] = useAccountDrawer()
const [hasUnfetchedBalances, setHasUnfetchedBalances] = useState(true)
// Use an atom to track unfetched state to avoid duplicating fetches if this component appears multiple times on the page.
const [hasUnfetchedBalances, setHasUnfetchedBalances] = useAtom(hasUnfetchedBalancesAtom)
const fetchBalances = useCallback(() => {
if (account) {
prefetchPortfolioBalances({ variables: { ownerAddress: account, chains: GQL_MAINNET_CHAINS } })
setHasUnfetchedBalances(false)
}
}, [account, prefetchPortfolioBalances])
}, [account, prefetchPortfolioBalances, setHasUnfetchedBalances])
const prevAccount = usePrevious(account)
// TODO(cartcrom): add delay for refetching on optimism, as there is high latency in new balances being available
const hasUpdatedTx = useHasUpdatedTx(account)
// Listens for account changes & recently updated transactions to keep portfolio balances fresh in apollo cache
useEffect(() => {
const accountChanged = prevAccount !== undefined && prevAccount !== account
if (hasUpdatedTx || accountChanged) {
// If the drawer is open, fetch balances immediately, else set a flag to fetch on next hover
if (drawerOpen) {
// The parent configures whether these conditions should trigger an immediate fetch,
// if not, we set a flag to fetch on next hover.
if (shouldFetchOnAccountUpdate) {
fetchBalances()
} else {
setHasUnfetchedBalances(true)
}
}
}, [account, prevAccount, drawerOpen, fetchBalances, hasUpdatedTx])
}, [account, prevAccount, shouldFetchOnAccountUpdate, fetchBalances, hasUpdatedTx, setHasUnfetchedBalances])
const onHover = useCallback(() => {
if (hasUnfetchedBalances) fetchBalances()
......
......@@ -5,6 +5,7 @@ import { formatCurrencyAmount, NumberType } from '@uniswap/conedison/format'
import { Currency, CurrencyAmount, Percent } from '@uniswap/sdk-core'
import { Pair } from '@uniswap/v2-sdk'
import { useWeb3React } from '@web3-react/core'
import PrefetchBalancesWrapper from 'components/AccountDrawer/PrefetchBalancesWrapper'
import { AutoColumn } from 'components/Column'
import { LoadingOpacityContainer, loadingOpacityMixin } from 'components/Loader/styled'
import CurrencyLogo from 'components/Logo/CurrencyLogo'
......@@ -264,45 +265,46 @@ export default function SwapCurrencyInputPanel({
$loading={loading}
/>
)}
<CurrencySelect
disabled={!chainAllowed || disabled}
visible={currency !== undefined}
selected={!!currency}
hideInput={hideInput}
className="open-currency-select-button"
onClick={() => {
if (onCurrencySelect) {
setModalOpen(true)
}
}}
>
<Aligner>
<RowFixed>
{pair ? (
<span style={{ marginRight: '0.5rem' }}>
<DoubleCurrencyLogo currency0={pair.token0} currency1={pair.token1} size={24} margin={true} />
</span>
) : currency ? (
<CurrencyLogo style={{ marginRight: '2px' }} currency={currency} size="24px" />
) : null}
{pair ? (
<StyledTokenName className="pair-name-container">
{pair?.token0.symbol}:{pair?.token1.symbol}
</StyledTokenName>
) : (
<StyledTokenName className="token-symbol-container" active={Boolean(currency && currency.symbol)}>
{(currency && currency.symbol && currency.symbol.length > 20
? currency.symbol.slice(0, 4) +
'...' +
currency.symbol.slice(currency.symbol.length - 5, currency.symbol.length)
: currency?.symbol) || <Trans>Select token</Trans>}
</StyledTokenName>
)}
</RowFixed>
{onCurrencySelect && <StyledDropDown selected={!!currency} />}
</Aligner>
</CurrencySelect>
<PrefetchBalancesWrapper shouldFetchOnAccountUpdate={modalOpen}>
<CurrencySelect
disabled={!chainAllowed || disabled}
visible={currency !== undefined}
selected={!!currency}
hideInput={hideInput}
className="open-currency-select-button"
onClick={() => {
if (onCurrencySelect) {
setModalOpen(true)
}
}}
>
<Aligner>
<RowFixed>
{pair ? (
<span style={{ marginRight: '0.5rem' }}>
<DoubleCurrencyLogo currency0={pair.token0} currency1={pair.token1} size={24} margin={true} />
</span>
) : currency ? (
<CurrencyLogo style={{ marginRight: '2px' }} currency={currency} size="24px" />
) : null}
{pair ? (
<StyledTokenName className="pair-name-container">
{pair?.token0.symbol}:{pair?.token1.symbol}
</StyledTokenName>
) : (
<StyledTokenName className="token-symbol-container" active={Boolean(currency && currency.symbol)}>
{(currency && currency.symbol && currency.symbol.length > 20
? currency.symbol.slice(0, 4) +
'...' +
currency.symbol.slice(currency.symbol.length - 5, currency.symbol.length)
: currency?.symbol) || <Trans>Select token</Trans>}
</StyledTokenName>
)}
</RowFixed>
{onCurrencySelect && <StyledDropDown selected={!!currency} />}
</Aligner>
</CurrencySelect>
</PrefetchBalancesWrapper>
</InputRow>
{Boolean(!hideInput && !hideBalance) && (
<FiatRow>
......
......@@ -81,6 +81,7 @@ export default function CommonBases({
onClick={() => !isSelected && onSelect(currency)}
disable={isSelected}
key={currencyId(currency)}
data-testid={`common-base-${currency.symbol}`}
>
<CurrencyLogoFromList currency={currency} />
<Text fontWeight={500} fontSize={16}>
......
import { screen } from '@testing-library/react'
import { Currency, CurrencyAmount as mockCurrencyAmount, Token as mockToken } from '@uniswap/sdk-core'
import { useWeb3React } from '@web3-react/core'
import { DAI, USDC_MAINNET, WBTC } from 'constants/tokens'
import * as mockJSBI from 'jsbi'
import { mocked } from 'test-utils/mocked'
import { render } from 'test-utils/render'
import CurrencyList from '.'
......@@ -42,6 +44,7 @@ it('renders loading rows when isLoading is true', () => {
isLoading={true}
searchQuery=""
isAddressSearch=""
balances={{}}
/>
)
expect(component.findByTestId('loading-rows')).toBeTruthy()
......@@ -61,9 +64,37 @@ it('renders currency rows correctly when currencies list is non-empty', () => {
isLoading={false}
searchQuery=""
isAddressSearch=""
balances={{}}
/>
)
expect(screen.getByText('Wrapped BTC')).toBeInTheDocument()
expect(screen.getByText('DAI')).toBeInTheDocument()
expect(screen.getByText('USDC')).toBeInTheDocument()
})
it('renders currency rows correctly with balances', () => {
mocked(useWeb3React).mockReturnValue({
account: '0x52270d8234b864dcAC9947f510CE9275A8a116Db',
isActive: true,
} as ReturnType<typeof useWeb3React>)
render(
<CurrencyList
height={10}
currencies={[DAI, USDC_MAINNET, WBTC]}
otherListTokens={[]}
selectedCurrency={null}
onCurrencySelect={noOp}
isLoading={false}
searchQuery=""
isAddressSearch=""
showCurrencyAmount
balances={{
[DAI.address.toLowerCase()]: { usdValue: 2, balance: 2 },
}}
/>
)
expect(screen.getByText('Wrapped BTC')).toBeInTheDocument()
expect(screen.getByText('DAI')).toBeInTheDocument()
expect(screen.getByText('USDC')).toBeInTheDocument()
expect(screen.getByText('2')).toBeInTheDocument()
})
......@@ -5,6 +5,8 @@ import { useWeb3React } from '@web3-react/core'
import Loader from 'components/Icons/LoadingSpinner'
import TokenSafetyIcon from 'components/TokenSafety/TokenSafetyIcon'
import { checkWarning } from 'constants/tokenSafety'
import { TokenBalances } from 'lib/hooks/useTokenList/sorting'
import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount'
import { CSSProperties, MutableRefObject, useCallback, useMemo } from 'react'
import { Check } from 'react-feather'
import { FixedSizeList } from 'react-window'
......@@ -12,7 +14,6 @@ import { Text } from 'rebass'
import styled from 'styled-components/macro'
import { useIsUserAddedToken } from '../../../hooks/Tokens'
import { useCurrencyBalance } from '../../../state/connection/hooks'
import { WrappedTokenInfo } from '../../../state/lists/wrappedTokenInfo'
import { ThemedText } from '../../../theme'
import Column, { AutoColumn } from '../../Column'
......@@ -115,6 +116,7 @@ export function CurrencyRow({
style,
showCurrencyAmount,
eventProperties,
balance,
}: {
currency: Currency
onSelect: (hasWarning: boolean) => void
......@@ -123,11 +125,11 @@ export function CurrencyRow({
style?: CSSProperties
showCurrencyAmount?: boolean
eventProperties: Record<string, unknown>
balance?: CurrencyAmount<Currency>
}) {
const { account } = useWeb3React()
const key = currencyKey(currency)
const customAdded = useIsUserAddedToken(currency)
const balance = useCurrencyBalance(account ?? undefined, currency)
const warning = currency.isNative ? null : checkWarning(currency.address)
const isBlockedToken = !!warning && !warning.canProceed
const blockedTokenOpacity = '0.6'
......@@ -175,7 +177,7 @@ export function CurrencyRow({
</Column>
{showCurrencyAmount ? (
<RowFixed style={{ justifySelf: 'flex-end' }}>
{balance ? <Balance balance={balance} /> : account ? <Loader /> : null}
{account ? balance ? <Balance balance={balance} /> : <Loader /> : null}
{isSelected && <CheckIcon />}
</RowFixed>
) : (
......@@ -235,6 +237,7 @@ export default function CurrencyList({
isLoading,
searchQuery,
isAddressSearch,
balances,
}: {
height: number
currencies: Currency[]
......@@ -247,6 +250,7 @@ export default function CurrencyList({
isLoading: boolean
searchQuery: string
isAddressSearch: string | false
balances: TokenBalances
}) {
const itemData: Currency[] = useMemo(() => {
if (otherListTokens && otherListTokens?.length > 0) {
......@@ -261,6 +265,12 @@ export default function CurrencyList({
const currency = row
const balance =
tryParseCurrencyAmount(
String(balances[currency.isNative ? 'ETH' : currency.address?.toLowerCase()]?.balance ?? 0),
currency
) ?? CurrencyAmount.fromRawAmount(currency, 0)
const isSelected = Boolean(currency && selectedCurrency && selectedCurrency.equals(currency))
const otherSelected = Boolean(currency && otherCurrency && otherCurrency.equals(currency))
const handleSelect = (hasWarning: boolean) => currency && onCurrencySelect(currency, hasWarning)
......@@ -279,13 +289,23 @@ export default function CurrencyList({
otherSelected={otherSelected}
showCurrencyAmount={showCurrencyAmount}
eventProperties={formatAnalyticsEventProperties(token, index, data, searchQuery, isAddressSearch)}
balance={balance}
/>
)
} else {
return null
}
},
[onCurrencySelect, otherCurrency, selectedCurrency, showCurrencyAmount, isLoading, isAddressSearch, searchQuery]
[
selectedCurrency,
otherCurrency,
isLoading,
onCurrencySelect,
showCurrencyAmount,
searchQuery,
isAddressSearch,
balances,
]
)
const itemKey = useCallback((index: number, data: typeof itemData) => {
......
......@@ -4,18 +4,19 @@ import { Trace } from '@uniswap/analytics'
import { InterfaceEventName, InterfaceModalName } from '@uniswap/analytics-events'
import { Currency, Token } from '@uniswap/sdk-core'
import { useWeb3React } from '@web3-react/core'
import { useCachedPortfolioBalancesQuery } from 'components/AccountDrawer/PrefetchBalancesWrapper'
import { sendEvent } from 'components/analytics'
import { supportedChainIdFromGQLChain } from 'graphql/data/util'
import useDebounce from 'hooks/useDebounce'
import { useOnClickOutside } from 'hooks/useOnClickOutside'
import useToggle from 'hooks/useToggle'
import useNativeCurrency from 'lib/hooks/useNativeCurrency'
import { getTokenFilter } from 'lib/hooks/useTokenList/filtering'
import { tokenComparator, useSortTokensByQuery } from 'lib/hooks/useTokenList/sorting'
import { TokenBalances, tokenComparator, useSortTokensByQuery } from 'lib/hooks/useTokenList/sorting'
import { ChangeEvent, KeyboardEvent, RefObject, useCallback, useEffect, useMemo, useRef, useState } from 'react'
import AutoSizer from 'react-virtualized-auto-sizer'
import { FixedSizeList } from 'react-window'
import { Text } from 'rebass'
import { useAllTokenBalances } from 'state/connection/hooks'
import styled, { useTheme } from 'styled-components/macro'
import { UserAddedToken } from 'types/tokens'
......@@ -61,7 +62,7 @@ export function CurrencySearch({
isOpen,
onlyShowCurrenciesWithBalance,
}: CurrencySearchProps) {
const { chainId } = useWeb3React()
const { chainId, account } = useWeb3React()
const theme = useTheme()
const [tokenLoaderTimerElapsed, setTokenLoaderTimerElapsed] = useState(false)
......@@ -90,33 +91,52 @@ export function CurrencySearch({
return Object.values(defaultTokens).filter(getTokenFilter(debouncedQuery))
}, [defaultTokens, debouncedQuery])
const [balances, balancesAreLoading] = useAllTokenBalances()
const { data, loading: balancesAreLoading } = useCachedPortfolioBalancesQuery({ account })
const balances: TokenBalances = useMemo(() => {
return (
data?.portfolios?.[0].tokenBalances?.reduce((balanceMap, tokenBalance) => {
if (
tokenBalance.token?.chain &&
supportedChainIdFromGQLChain(tokenBalance.token?.chain) === chainId &&
tokenBalance.token?.address !== undefined &&
tokenBalance.denominatedValue?.value !== undefined
) {
const address = tokenBalance.token?.standard === 'ERC20' ? tokenBalance.token?.address?.toLowerCase() : 'ETH'
const usdValue = tokenBalance.denominatedValue?.value
const balance = tokenBalance.quantity
balanceMap[address] = { usdValue, balance: balance ?? 0 }
}
return balanceMap
}, {} as TokenBalances) ?? {}
)
}, [chainId, data?.portfolios])
const sortedTokens: Token[] = useMemo(
() =>
!balancesAreLoading
? filteredTokens
.filter((token) => {
if (onlyShowCurrenciesWithBalance) {
return balances[token.address]?.greaterThan(0)
return balances[token.address?.toLowerCase()]?.usdValue > 0
}
// If there is no query, filter out unselected user-added tokens with no balance.
if (!debouncedQuery && token instanceof UserAddedToken) {
if (selectedCurrency?.equals(token) || otherSelectedCurrency?.equals(token)) return true
return balances[token.address]?.greaterThan(0)
return balances[token.address.toLowerCase()]?.usdValue > 0
}
return true
})
.sort(tokenComparator.bind(null, balances))
: [],
: filteredTokens,
[
balances,
balancesAreLoading,
debouncedQuery,
filteredTokens,
otherSelectedCurrency,
selectedCurrency,
balances,
onlyShowCurrenciesWithBalance,
debouncedQuery,
selectedCurrency,
otherSelectedCurrency,
]
)
const isLoading = Boolean(balancesAreLoading && !tokenLoaderTimerElapsed)
......@@ -131,7 +151,7 @@ export function CurrencySearch({
const tokens = filteredSortedTokens.filter((t) => !(t.equals(wrapped) || (disableNonToken && t.isNative)))
const shouldShowWrapped =
!onlyShowCurrenciesWithBalance || (!balancesAreLoading && balances[wrapped.address]?.greaterThan(0))
!onlyShowCurrenciesWithBalance || (!balancesAreLoading && balances[wrapped.address]?.usdValue > 0)
const natives = (
disableNonToken || native.equals(wrapped) ? [wrapped] : shouldShowWrapped ? [native, wrapped] : [native]
).filter((n) => n.symbol?.toLowerCase()?.indexOf(s) !== -1 || n.name?.toLowerCase()?.indexOf(s) !== -1)
......@@ -280,6 +300,7 @@ export function CurrencySearch({
isLoading={isLoading}
searchQuery={searchQuery}
isAddressSearch={isAddressSearch}
balances={balances}
/>
)}
</AutoSizer>
......
......@@ -212,8 +212,9 @@ function Web3StatusInner() {
}
export default function Web3Status() {
const [isDrawerOpen] = useAccountDrawer()
return (
<PrefetchBalancesWrapper>
<PrefetchBalancesWrapper shouldFetchOnAccountUpdate={isDrawerOpen}>
<Web3StatusInner />
<Portal>
<PortfolioDrawer />
......
import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core'
import { Token } from '@uniswap/sdk-core'
import { TokenInfo } from '@uniswap/token-lists'
import { useMemo } from 'react'
/** Sorts currency amounts (descending). */
function balanceComparator(a?: CurrencyAmount<Currency>, b?: CurrencyAmount<Currency>) {
function balanceComparator(a?: number, b?: number) {
if (a && b) {
return a.greaterThan(b) ? -1 : a.equalTo(b) ? 0 : 1
} else if (a?.greaterThan('0')) {
return a > b ? -1 : a === b ? 0 : 1
} else if ((a ?? 0) > 0) {
return -1
} else if (b?.greaterThan('0')) {
} else if ((b ?? 0) > 0) {
return 1
}
return 0
}
type TokenBalances = { [tokenAddress: string]: CurrencyAmount<Token> | undefined }
export type TokenBalances = { [tokenAddress: string]: { usdValue: number; balance: number } }
/** Sorts tokens by currency amount (descending), then safety, then symbol (ascending). */
export function tokenComparator(balances: TokenBalances, a: Token, b: Token) {
// Sorts by balances
const balanceComparison = balanceComparator(balances[a.address], balances[b.address])
const balanceComparison = balanceComparator(
balances[a.address.toLowerCase()]?.usdValue,
balances[b.address.toLowerCase()]?.usdValue
)
if (balanceComparison !== 0) return balanceComparison
// Sorts by symbol
......
......@@ -1761,38 +1761,40 @@ exports[`disable nft on landing page does not render nft information and card 1`
type="text"
value=""
/>
<button
class="c23 c24 c25 c26 open-currency-select-button"
>
<span
class="c27"
<div>
<button
class="c23 c24 c25 c26 open-currency-select-button"
>
<div
class="c6 c7 c10"
<span
class="c27"
>
<div
class="c28"
style="margin-right: 2px;"
class="c6 c7 c10"
>
<img
alt="ETH logo"
class="c29"
src="ethereum-logo.png"
/>
<div
class="c28"
style="margin-right: 2px;"
>
<img
alt="ETH logo"
class="c29"
src="ethereum-logo.png"
/>
</div>
<span
class="c30 token-symbol-container"
>
ETH
</span>
</div>
<span
class="c30 token-symbol-container"
<svg
class="c31"
>
ETH
</span>
</div>
<svg
class="c31"
>
dropdown.svg
</svg>
</span>
</button>
dropdown.svg
</svg>
</span>
</button>
</div>
</div>
<div
class="c32 c33"
......@@ -1872,28 +1874,30 @@ exports[`disable nft on landing page does not render nft information and card 1`
type="text"
value=""
/>
<button
class="c23 c24 c25 c39 open-currency-select-button"
>
<span
class="c27"
<div>
<button
class="c23 c24 c25 c39 open-currency-select-button"
>
<div
class="c6 c7 c10"
<span
class="c27"
>
<span
class="c30 token-symbol-container"
<div
class="c6 c7 c10"
>
Select token
</span>
</div>
<svg
class="c40"
>
dropdown.svg
</svg>
</span>
</button>
<span
class="c30 token-symbol-container"
>
Select token
</span>
</div>
<svg
class="c40"
>
dropdown.svg
</svg>
</span>
</button>
</div>
</div>
<div
class="c32 c33"
......@@ -4263,38 +4267,40 @@ exports[`disable nft on landing page renders nft information and card 1`] = `
type="text"
value=""
/>
<button
class="c23 c24 c25 c26 open-currency-select-button"
>
<span
class="c27"
<div>
<button
class="c23 c24 c25 c26 open-currency-select-button"
>
<div
class="c6 c7 c10"
<span
class="c27"
>
<div
class="c28"
style="margin-right: 2px;"
class="c6 c7 c10"
>
<img
alt="ETH logo"
class="c29"
src="ethereum-logo.png"
/>
<div
class="c28"
style="margin-right: 2px;"
>
<img
alt="ETH logo"
class="c29"
src="ethereum-logo.png"
/>
</div>
<span
class="c30 token-symbol-container"
>
ETH
</span>
</div>
<span
class="c30 token-symbol-container"
<svg
class="c31"
>
ETH
</span>
</div>
<svg
class="c31"
>
dropdown.svg
</svg>
</span>
</button>
dropdown.svg
</svg>
</span>
</button>
</div>
</div>
<div
class="c32 c33"
......@@ -4374,28 +4380,30 @@ exports[`disable nft on landing page renders nft information and card 1`] = `
type="text"
value=""
/>
<button
class="c23 c24 c25 c39 open-currency-select-button"
>
<span
class="c27"
<div>
<button
class="c23 c24 c25 c39 open-currency-select-button"
>
<div
class="c6 c7 c10"
<span
class="c27"
>
<span
class="c30 token-symbol-container"
<div
class="c6 c7 c10"
>
Select token
</span>
</div>
<svg
class="c40"
>
dropdown.svg
</svg>
</span>
</button>
<span
class="c30 token-symbol-container"
>
Select token
</span>
</div>
<svg
class="c40"
>
dropdown.svg
</svg>
</span>
</button>
</div>
</div>
<div
class="c32 c33"
......
import { CurrencyAmount, Token } from '@uniswap/sdk-core'
import { useWeb3React } from '@web3-react/core'
import { useTokenBalancesWithLoadingIndicator } from 'lib/hooks/useCurrencyBalance'
import { useMemo } from 'react'
import { useDefaultActiveTokens } from '../../hooks/Tokens'
export {
default as useCurrencyBalance,
useCurrencyBalances,
......@@ -13,12 +6,3 @@ export {
useTokenBalances,
useTokenBalancesWithLoadingIndicator,
} from 'lib/hooks/useCurrencyBalance'
// mimics useAllBalances
export function useAllTokenBalances(): [{ [tokenAddress: string]: CurrencyAmount<Token> | undefined }, boolean] {
const { account, chainId } = useWeb3React()
const allTokens = useDefaultActiveTokens(chainId)
const allTokensArray = useMemo(() => Object.values(allTokens ?? {}), [allTokens])
const [balances, balancesIsLoading] = useTokenBalancesWithLoadingIndicator(account ?? undefined, allTokensArray)
return [balances ?? {}, balancesIsLoading]
}
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