fix: include user-added tokens in selector (#5319)
This commit is contained in:
parent
8cd32138ac
commit
ce51ffae75
@ -17,8 +17,9 @@ import { FixedSizeList } from 'react-window'
|
|||||||
import { Text } from 'rebass'
|
import { Text } from 'rebass'
|
||||||
import { useAllTokenBalances } from 'state/connection/hooks'
|
import { useAllTokenBalances } from 'state/connection/hooks'
|
||||||
import styled, { useTheme } from 'styled-components/macro'
|
import styled, { useTheme } from 'styled-components/macro'
|
||||||
|
import { UserAddedToken } from 'types/tokens'
|
||||||
|
|
||||||
import { useActiveTokens, useIsUserAddedToken, useSearchInactiveTokenLists, useToken } from '../../hooks/Tokens'
|
import { useAllTokens, useIsUserAddedToken, useSearchInactiveTokenLists, useToken } from '../../hooks/Tokens'
|
||||||
import { CloseIcon, ThemedText } from '../../theme'
|
import { CloseIcon, ThemedText } from '../../theme'
|
||||||
import { isAddress } from '../../utils'
|
import { isAddress } from '../../utils'
|
||||||
import Column from '../Column'
|
import Column from '../Column'
|
||||||
@ -66,15 +67,8 @@ export function CurrencySearch({
|
|||||||
|
|
||||||
const [searchQuery, setSearchQuery] = useState<string>('')
|
const [searchQuery, setSearchQuery] = useState<string>('')
|
||||||
const debouncedQuery = useDebounce(searchQuery, 200)
|
const debouncedQuery = useDebounce(searchQuery, 200)
|
||||||
|
|
||||||
// Only display 'imported' tokens when the search filter has input
|
|
||||||
const defaultTokens = useActiveTokens(debouncedQuery.length > 0)
|
|
||||||
|
|
||||||
// if they input an address, use it
|
|
||||||
const isAddressSearch = isAddress(debouncedQuery)
|
const isAddressSearch = isAddress(debouncedQuery)
|
||||||
|
|
||||||
const searchToken = useToken(debouncedQuery)
|
const searchToken = useToken(debouncedQuery)
|
||||||
|
|
||||||
const searchTokenIsAdded = useIsUserAddedToken(searchToken)
|
const searchTokenIsAdded = useIsUserAddedToken(searchToken)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -87,13 +81,26 @@ export function CurrencySearch({
|
|||||||
}
|
}
|
||||||
}, [isAddressSearch])
|
}, [isAddressSearch])
|
||||||
|
|
||||||
|
const defaultTokens = useAllTokens()
|
||||||
const filteredTokens: Token[] = useMemo(() => {
|
const filteredTokens: Token[] = useMemo(() => {
|
||||||
return Object.values(defaultTokens).filter(getTokenFilter(debouncedQuery))
|
return Object.values(defaultTokens).filter(getTokenFilter(debouncedQuery))
|
||||||
}, [defaultTokens, debouncedQuery])
|
}, [defaultTokens, debouncedQuery])
|
||||||
|
|
||||||
const [balances, balancesAreLoading] = useAllTokenBalances()
|
const [balances, balancesAreLoading] = useAllTokenBalances()
|
||||||
const sortedTokens: Token[] = useMemo(
|
const sortedTokens: Token[] = useMemo(
|
||||||
() => (!balancesAreLoading ? [...filteredTokens].sort(tokenComparator.bind(null, balances)) : []),
|
() =>
|
||||||
|
!balancesAreLoading
|
||||||
|
? [...filteredTokens]
|
||||||
|
.filter((token) => {
|
||||||
|
// Filter out user-added tokens with no balance
|
||||||
|
if (token instanceof UserAddedToken) {
|
||||||
|
const balance = balances[token.address]
|
||||||
|
return balance?.greaterThan(0)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
.sort(tokenComparator.bind(null, balances))
|
||||||
|
: [],
|
||||||
[balances, filteredTokens, balancesAreLoading]
|
[balances, filteredTokens, balancesAreLoading]
|
||||||
)
|
)
|
||||||
const isLoading = Boolean(balancesAreLoading && !tokenLoaderTimerElapsed)
|
const isLoading = Boolean(balancesAreLoading && !tokenLoaderTimerElapsed)
|
||||||
|
@ -14,23 +14,24 @@ import { useUserAddedTokens, useUserAddedTokensOnChain } from '../state/user/hoo
|
|||||||
import { TokenAddressMap, useUnsupportedTokenList } from './../state/lists/hooks'
|
import { TokenAddressMap, useUnsupportedTokenList } from './../state/lists/hooks'
|
||||||
|
|
||||||
// reduce token map into standard address <-> Token mapping, optionally include user added tokens
|
// reduce token map into standard address <-> Token mapping, optionally include user added tokens
|
||||||
function useTokensFromMap(tokenMap: TokenAddressMap, includeUserAdded: boolean): { [address: string]: Token } {
|
function useTokensFromMap(tokenMap: TokenAddressMap): { [address: string]: Token } {
|
||||||
const { chainId } = useWeb3React()
|
const { chainId } = useWeb3React()
|
||||||
const userAddedTokens = useUserAddedTokens()
|
|
||||||
|
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
if (!chainId) return {}
|
if (!chainId) return {}
|
||||||
|
|
||||||
// reduce to just tokens
|
// reduce to just tokens
|
||||||
const mapWithoutUrls = Object.keys(tokenMap[chainId] ?? {}).reduce<{ [address: string]: Token }>(
|
return Object.keys(tokenMap[chainId] ?? {}).reduce<{ [address: string]: Token }>((newMap, address) => {
|
||||||
(newMap, address) => {
|
|
||||||
newMap[address] = tokenMap[chainId][address].token
|
newMap[address] = tokenMap[chainId][address].token
|
||||||
return newMap
|
return newMap
|
||||||
},
|
}, {})
|
||||||
{}
|
}, [chainId, tokenMap])
|
||||||
)
|
}
|
||||||
|
|
||||||
if (includeUserAdded) {
|
export function useAllTokens(): { [address: string]: Token } {
|
||||||
|
const allTokens = useCombinedActiveList()
|
||||||
|
const tokensFromMap = useTokensFromMap(allTokens)
|
||||||
|
const userAddedTokens = useUserAddedTokens()
|
||||||
|
return useMemo(() => {
|
||||||
return (
|
return (
|
||||||
userAddedTokens
|
userAddedTokens
|
||||||
// reduce into all ALL_TOKENS filtered by the current chain
|
// reduce into all ALL_TOKENS filtered by the current chain
|
||||||
@ -41,23 +42,10 @@ function useTokensFromMap(tokenMap: TokenAddressMap, includeUserAdded: boolean):
|
|||||||
},
|
},
|
||||||
// must make a copy because reduce modifies the map, and we do not
|
// must make a copy because reduce modifies the map, and we do not
|
||||||
// want to make a copy in every iteration
|
// want to make a copy in every iteration
|
||||||
{ ...mapWithoutUrls }
|
{ ...tokensFromMap }
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}, [tokensFromMap, userAddedTokens])
|
||||||
|
|
||||||
return mapWithoutUrls
|
|
||||||
}, [chainId, userAddedTokens, tokenMap, includeUserAdded])
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useAllTokens(): { [address: string]: Token } {
|
|
||||||
const allTokens = useCombinedActiveList()
|
|
||||||
return useTokensFromMap(allTokens, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useActiveTokens(includeUserAdded: boolean): { [address: string]: Token } {
|
|
||||||
const allTokens = useCombinedActiveList()
|
|
||||||
return useTokensFromMap(allTokens, includeUserAdded)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type BridgeInfo = Record<
|
type BridgeInfo = Record<
|
||||||
@ -73,7 +61,7 @@ export function useUnsupportedTokens(): { [address: string]: Token } {
|
|||||||
const { chainId } = useWeb3React()
|
const { chainId } = useWeb3React()
|
||||||
const listsByUrl = useAllLists()
|
const listsByUrl = useAllLists()
|
||||||
const unsupportedTokensMap = useUnsupportedTokenList()
|
const unsupportedTokensMap = useUnsupportedTokenList()
|
||||||
const unsupportedTokens = useTokensFromMap(unsupportedTokensMap, false)
|
const unsupportedTokens = useTokensFromMap(unsupportedTokensMap)
|
||||||
|
|
||||||
// checks the default L2 lists to see if `bridgeInfo` has an L1 address value that is unsupported
|
// checks the default L2 lists to see if `bridgeInfo` has an L1 address value that is unsupported
|
||||||
const l2InferredBlockedTokens: typeof unsupportedTokens = useMemo(() => {
|
const l2InferredBlockedTokens: typeof unsupportedTokens = useMemo(() => {
|
||||||
|
@ -8,6 +8,7 @@ import JSBI from 'jsbi'
|
|||||||
import { useCallback, useMemo } from 'react'
|
import { useCallback, useMemo } from 'react'
|
||||||
import { shallowEqual } from 'react-redux'
|
import { shallowEqual } from 'react-redux'
|
||||||
import { useAppDispatch, useAppSelector } from 'state/hooks'
|
import { useAppDispatch, useAppSelector } from 'state/hooks'
|
||||||
|
import { UserAddedToken } from 'types/tokens'
|
||||||
|
|
||||||
import { V2_FACTORY_ADDRESSES } from '../../constants/addresses'
|
import { V2_FACTORY_ADDRESSES } from '../../constants/addresses'
|
||||||
import { BASES_TO_TRACK_LIQUIDITY_FOR, PINNED_PAIRS } from '../../constants/routing'
|
import { BASES_TO_TRACK_LIQUIDITY_FOR, PINNED_PAIRS } from '../../constants/routing'
|
||||||
@ -38,8 +39,8 @@ function serializeToken(token: Token): SerializedToken {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function deserializeToken(serializedToken: SerializedToken): Token {
|
function deserializeToken(serializedToken: SerializedToken, Class: typeof Token = Token): Token {
|
||||||
return new Token(
|
return new Class(
|
||||||
serializedToken.chainId,
|
serializedToken.chainId,
|
||||||
serializedToken.address,
|
serializedToken.address,
|
||||||
serializedToken.decimals,
|
serializedToken.decimals,
|
||||||
@ -238,7 +239,7 @@ export function useUserAddedTokensOnChain(chainId: number | undefined | null): T
|
|||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
if (!chainId) return []
|
if (!chainId) return []
|
||||||
const tokenMap: Token[] = serializedTokensMap?.[chainId]
|
const tokenMap: Token[] = serializedTokensMap?.[chainId]
|
||||||
? Object.values(serializedTokensMap[chainId]).map(deserializeToken)
|
? Object.values(serializedTokensMap[chainId]).map((value) => deserializeToken(value, UserAddedToken))
|
||||||
: []
|
: []
|
||||||
return tokenMap
|
return tokenMap
|
||||||
}, [serializedTokensMap, chainId])
|
}, [serializedTokensMap, chainId])
|
||||||
|
3
src/types/tokens.ts
Normal file
3
src/types/tokens.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import { Token } from '@uniswap/sdk-core'
|
||||||
|
|
||||||
|
export class UserAddedToken extends Token {}
|
Loading…
Reference in New Issue
Block a user