Compare commits

...

5 Commits

Author SHA1 Message Date
Moody Salem
7d45ff5ca8 fix 0 decimal tokens error 2021-05-12 17:29:02 -05:00
Moody Salem
8964cf86aa nit with how we convert percent to negative value 2021-05-12 17:13:40 -05:00
Moody Salem
0e9f23ed56 hover text nit 2021-05-12 17:12:16 -05:00
Moody Salem
e08e597655 show list in import token dialog 2021-05-12 17:01:20 -05:00
Moody Salem
744db49803 do not show duplicate token results, and stop searching as soon as possible 2021-05-12 16:54:05 -05:00
7 changed files with 41 additions and 28 deletions

View File

@@ -25,7 +25,7 @@ export function FiatValue({
return ( return (
<TYPE.body fontSize={14} color={fiatValue ? theme.text2 : theme.text4}> <TYPE.body fontSize={14} color={fiatValue ? theme.text2 : theme.text4}>
{fiatValue ? '~' : ''}$ {fiatValue ? '~' : ''}$
<HoverInlineText text={fiatValue ? Number(fiatValue?.toSignificant(6)).toLocaleString('en') : '-'} />{' '} <HoverInlineText text={fiatValue ? fiatValue?.toSignificant(6, { groupSeparator: ',' }) : '-'} />{' '}
{priceImpact ? ( {priceImpact ? (
<span style={{ color: priceImpactColor }}> ({priceImpact.multiply(-1).toSignificant(3)}%)</span> <span style={{ color: priceImpactColor }}> ({priceImpact.multiply(-1).toSignificant(3)}%)</span>
) : null} ) : null}

View File

@@ -2,8 +2,8 @@ import Tooltip from 'components/Tooltip'
import React, { useState } from 'react' import React, { useState } from 'react'
import styled from 'styled-components' import styled from 'styled-components'
const TextWrapper = styled.span<{ margin: boolean; link: boolean; fontSize?: string; adjustSize?: boolean }>` const TextWrapper = styled.span<{ margin: boolean; link?: boolean; fontSize?: string; adjustSize?: boolean }>`
position: relative; cursor: auto;
margin-left: ${({ margin }) => margin && '4px'}; margin-left: ${({ margin }) => margin && '4px'};
color: ${({ theme, link }) => (link ? theme.blue1 : theme.text1)}; color: ${({ theme, link }) => (link ? theme.blue1 : theme.text1)};
font-size: ${({ fontSize }) => fontSize ?? 'inherit'}; font-size: ${({ fontSize }) => fontSize ?? 'inherit'};
@@ -32,7 +32,7 @@ const HoverInlineText = ({
const [showHover, setShowHover] = useState(false) const [showHover, setShowHover] = useState(false)
if (!text) { if (!text) {
return <span></span> return <span />
} }
if (text.length > maxCharacters) { if (text.length > maxCharacters) {
@@ -43,7 +43,7 @@ const HoverInlineText = ({
onMouseLeave={() => setShowHover(false)} onMouseLeave={() => setShowHover(false)}
margin={margin} margin={margin}
adjustSize={adjustSize} adjustSize={adjustSize}
link={!!link} link={link}
fontSize={fontSize} fontSize={fontSize}
{...rest} {...rest}
> >
@@ -54,7 +54,7 @@ const HoverInlineText = ({
} }
return ( return (
<TextWrapper margin={margin} adjustSize={adjustSize} link={!!link} fontSize={fontSize} {...rest}> <TextWrapper margin={margin} adjustSize={adjustSize} link={link} fontSize={fontSize} {...rest}>
{text} {text}
</TextWrapper> </TextWrapper>
) )

View File

@@ -1,6 +1,7 @@
import { Currency, Token } from '@uniswap/sdk-core' import { Currency, Token } from '@uniswap/sdk-core'
import React, { useCallback, useEffect, useState } from 'react' import React, { useCallback, useEffect, useState } from 'react'
import useLast from '../../hooks/useLast' import useLast from '../../hooks/useLast'
import { WrappedTokenInfo } from '../../state/lists/wrappedTokenInfo'
import Modal from '../Modal' import Modal from '../Modal'
import { CurrencySearch } from './CurrencySearch' import { CurrencySearch } from './CurrencySearch'
import { ImportToken } from './ImportToken' import { ImportToken } from './ImportToken'
@@ -81,6 +82,7 @@ export default function CurrencySearchModal({
<ImportToken <ImportToken
tokens={[importToken]} tokens={[importToken]}
onDismiss={onDismiss} onDismiss={onDismiss}
list={importToken instanceof WrappedTokenInfo ? importToken.list : undefined}
onBack={() => onBack={() =>
setModalView(prevView && prevView !== CurrencyModalView.importToken ? prevView : CurrencyModalView.search) setModalView(prevView && prevView !== CurrencyModalView.importToken ? prevView : CurrencyModalView.search)
} }

View File

@@ -3,13 +3,18 @@ import { useMemo } from 'react'
import { isAddress } from '../../utils' import { isAddress } from '../../utils'
import { Token } from '@uniswap/sdk-core' import { Token } from '@uniswap/sdk-core'
export function filterTokens<T extends Token | TokenInfo>(tokens: T[], search: string): T[] { const alwaysTrue = () => true
if (search.length === 0) return tokens
/**
* Create a filter function to apply to a token for whether it matches a particular search query
* @param search the search query to apply to the token
*/
export function createTokenFilterFunction<T extends Token | TokenInfo>(search: string): (tokens: T) => boolean {
const searchingAddress = isAddress(search) const searchingAddress = isAddress(search)
if (searchingAddress) { if (searchingAddress) {
return tokens.filter((token) => token.address === searchingAddress) const lower = searchingAddress.toLowerCase()
return (t: T) => ('isToken' in t ? searchingAddress === t.address : lower === t.address.toLowerCase())
} }
const lowerSearchParts = search const lowerSearchParts = search
@@ -17,9 +22,7 @@ export function filterTokens<T extends Token | TokenInfo>(tokens: T[], search: s
.split(/\s+/) .split(/\s+/)
.filter((s) => s.length > 0) .filter((s) => s.length > 0)
if (lowerSearchParts.length === 0) { if (lowerSearchParts.length === 0) return alwaysTrue
return tokens
}
const matchesSearch = (s: string): boolean => { const matchesSearch = (s: string): boolean => {
const sParts = s const sParts = s
@@ -30,10 +33,11 @@ export function filterTokens<T extends Token | TokenInfo>(tokens: T[], search: s
return lowerSearchParts.every((p) => p.length === 0 || sParts.some((sp) => sp.startsWith(p) || sp.endsWith(p))) return lowerSearchParts.every((p) => p.length === 0 || sParts.some((sp) => sp.startsWith(p) || sp.endsWith(p)))
} }
return tokens.filter((token) => { return ({ name, symbol }: T): boolean => Boolean((symbol && matchesSearch(symbol)) || (name && matchesSearch(name)))
const { symbol, name } = token }
return (symbol && matchesSearch(symbol)) || (name && matchesSearch(name))
}) export function filterTokens<T extends Token | TokenInfo>(tokens: T[], search: string): T[] {
return tokens.filter(createTokenFilterFunction(search))
} }
export function useSortedTokensByQuery(tokens: Token[] | undefined, searchQuery: string): Token[] { export function useSortedTokensByQuery(tokens: Token[] | undefined, searchQuery: string): Token[] {

View File

@@ -9,7 +9,7 @@ import { ErrorText, ErrorPill } from './styleds'
export default function FormattedPriceImpact({ priceImpact }: { priceImpact?: Percent }) { export default function FormattedPriceImpact({ priceImpact }: { priceImpact?: Percent }) {
return ( return (
<ErrorText fontWeight={500} fontSize={12} severity={warningSeverity(priceImpact)}> <ErrorText fontWeight={500} fontSize={12} severity={warningSeverity(priceImpact)}>
{priceImpact ? `-${priceImpact.toFixed(2)}%` : '-'} {priceImpact ? `${priceImpact.multiply(-1).toFixed(2)}%` : '-'}
</ErrorText> </ErrorText>
) )
} }
@@ -17,7 +17,7 @@ export default function FormattedPriceImpact({ priceImpact }: { priceImpact?: Pe
export function SmallFormattedPriceImpact({ priceImpact }: { priceImpact?: Percent }) { export function SmallFormattedPriceImpact({ priceImpact }: { priceImpact?: Percent }) {
return ( return (
<ErrorPill fontWeight={500} fontSize={12} severity={warningSeverity(priceImpact)}> <ErrorPill fontWeight={500} fontSize={12} severity={warningSeverity(priceImpact)}>
{priceImpact ? `(-${priceImpact.toFixed(2)}%)` : '-'} {priceImpact ? `(${priceImpact.multiply(-1).toFixed(2)}%)` : '-'}
</ErrorPill> </ErrorPill>
) )
} }

View File

@@ -2,7 +2,7 @@ import { parseBytes32String } from '@ethersproject/strings'
import { Currency, currencyEquals, ETHER, Token } from '@uniswap/sdk-core' import { Currency, currencyEquals, ETHER, Token } from '@uniswap/sdk-core'
import { arrayify } from 'ethers/lib/utils' import { arrayify } from 'ethers/lib/utils'
import { useMemo } from 'react' import { useMemo } from 'react'
import { filterTokens } from '../components/SearchModal/filtering' import { createTokenFilterFunction } from '../components/SearchModal/filtering'
import { useAllLists, useCombinedActiveList, useInactiveListUrls } from '../state/lists/hooks' import { useAllLists, useCombinedActiveList, useInactiveListUrls } from '../state/lists/hooks'
import { WrappedTokenInfo } from '../state/lists/wrappedTokenInfo' import { WrappedTokenInfo } from '../state/lists/wrappedTokenInfo'
import { NEVER_RELOAD, useSingleCallResult } from '../state/multicall/hooks' import { NEVER_RELOAD, useSingleCallResult } from '../state/multicall/hooks'
@@ -61,21 +61,28 @@ export function useSearchInactiveTokenLists(search: string | undefined, minResul
const lists = useAllLists() const lists = useAllLists()
const inactiveUrls = useInactiveListUrls() const inactiveUrls = useInactiveListUrls()
const { chainId } = useActiveWeb3React() const { chainId } = useActiveWeb3React()
const activeTokens = useAllTokens()
return useMemo(() => { return useMemo(() => {
if (!search || search.trim().length === 0) return [] if (!search || search.trim().length === 0) return []
let result: WrappedTokenInfo[] = [] const tokenFilter = createTokenFilterFunction(search)
const result: WrappedTokenInfo[] = []
const addressSet: { [address: string]: true } = {}
for (const url of inactiveUrls) { for (const url of inactiveUrls) {
const list = lists[url].current const list = lists[url].current
if (!list) continue if (!list) continue
const matching = filterTokens( for (const tokenInfo of list.tokens) {
list.tokens.filter((token) => token.chainId === chainId), if (tokenInfo.chainId === chainId && tokenFilter(tokenInfo)) {
search const wrapped = new WrappedTokenInfo(tokenInfo, list)
) if (!(wrapped.address in activeTokens) && !addressSet[wrapped.address]) {
result = [...result, ...matching.map((tokenInfo) => new WrappedTokenInfo(tokenInfo, list))] addressSet[wrapped.address] = true
if (result.length >= minResults) return result result.push(wrapped)
if (result.length >= minResults) return result
}
}
}
} }
return result return result
}, [chainId, inactiveUrls, lists, minResults, search]) }, [activeTokens, chainId, inactiveUrls, lists, minResults, search])
} }
export function useIsTokenActive(token: Token | undefined | null): boolean { export function useIsTokenActive(token: Token | undefined | null): boolean {

View File

@@ -14,7 +14,7 @@ export function formatTokenAmount(amount: CurrencyAmount<Currency> | undefined,
return '<0.00001' return '<0.00001'
} }
return amount.toSignificant(Math.min(sigFigs, amount.currency.decimals)) return amount.toSignificant(sigFigs)
} }
export function formatPrice(price: Price<Currency, Currency> | undefined, sigFigs: number) { export function formatPrice(price: Price<Currency, Currency> | undefined, sigFigs: number) {