Commit 7e49babf authored by Moody Salem's avatar Moody Salem Committed by GitHub

improvement(token search): No automatic add (#888)

* no automatic add, major refactors

* fix nit with version link

* add/remove links in the token search modal

* close tooltip when user types

* remove skip
parent b35653ad
import { Pair, Token } from '@uniswap/sdk' import { Pair, Token } from '@uniswap/sdk'
import React, { useState, useContext } from 'react' import React, { useState, useContext, useCallback } from 'react'
import styled, { ThemeContext } from 'styled-components' import styled, { ThemeContext } from 'styled-components'
import { darken } from 'polished' import { darken } from 'polished'
import { Field } from '../../state/swap/actions' import { Field } from '../../state/swap/actions'
import { useTokenBalanceTreatingWETHasETH } from '../../state/wallet/hooks' import { useTokenBalanceTreatingWETHasETH } from '../../state/wallet/hooks'
import TokenSearchModal from '../SearchModal/TokenSearchModal'
import TokenLogo from '../TokenLogo' import TokenLogo from '../TokenLogo'
import DoubleLogo from '../DoubleLogo' import DoubleLogo from '../DoubleLogo'
import SearchModal from '../SearchModal'
import { RowBetween } from '../Row' import { RowBetween } from '../Row'
import { TYPE, CursorPointer } from '../../theme' import { TYPE, CursorPointer } from '../../theme'
import { Input as NumericalInput } from '../NumericalInput' import { Input as NumericalInput } from '../NumericalInput'
...@@ -159,6 +159,10 @@ export default function CurrencyInputPanel({ ...@@ -159,6 +159,10 @@ export default function CurrencyInputPanel({
const userTokenBalance = useTokenBalanceTreatingWETHasETH(account, token) const userTokenBalance = useTokenBalanceTreatingWETHasETH(account, token)
const theme = useContext(ThemeContext) const theme = useContext(ThemeContext)
const handleDismissSearch = useCallback(() => {
setModalOpen(false)
}, [setModalOpen])
return ( return (
<InputPanel id={id}> <InputPanel id={id}>
<Container hideInput={hideInput}> <Container hideInput={hideInput}>
...@@ -235,12 +239,9 @@ export default function CurrencyInputPanel({ ...@@ -235,12 +239,9 @@ export default function CurrencyInputPanel({
</InputRow> </InputRow>
</Container> </Container>
{!disableTokenSelect && ( {!disableTokenSelect && (
<SearchModal <TokenSearchModal
isOpen={modalOpen} isOpen={modalOpen}
onDismiss={() => { onDismiss={handleDismissSearch}
setModalOpen(false)
}}
filterType="tokens"
onTokenSelect={onTokenSelection} onTokenSelect={onTokenSelection}
showSendWithSwap={showSendWithSwap} showSendWithSwap={showSendWithSwap}
hiddenToken={token?.address} hiddenToken={token?.address}
......
...@@ -25,13 +25,7 @@ export default function PairList({ ...@@ -25,13 +25,7 @@ export default function PairList({
} }
return ( return (
<FixedSizeList <FixedSizeList itemSize={56} height={500} itemCount={pairs.length} width="100%" style={{ flex: '1' }}>
itemSize={54}
height={500}
itemCount={pairs.length}
width="100%"
style={{ flex: '1', minHeight: 200 }}
>
{({ index, style }) => { {({ index, style }) => {
const pair = pairs[index] const pair = pairs[index]
......
import { Pair } from '@uniswap/sdk'
import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'
import { isMobile } from 'react-device-detect'
import { useTranslation } from 'react-i18next'
import { RouteComponentProps, withRouter } from 'react-router-dom'
import { Text } from 'rebass'
import { ThemeContext } from 'styled-components'
import Card from '../../components/Card'
import { useActiveWeb3React } from '../../hooks'
import { useAllTokens } from '../../hooks/Tokens'
import { useAllDummyPairs } from '../../state/user/hooks'
import { useTokenBalances } from '../../state/wallet/hooks'
import { CloseIcon, StyledInternalLink } from '../../theme/components'
import { isAddress } from '../../utils'
import Column from '../Column'
import Modal from '../Modal'
import QuestionHelper from '../QuestionHelper'
import { AutoRow, RowBetween } from '../Row'
import { filterPairs } from './filtering'
import PairList from './PairList'
import { pairComparator } from './sorting'
import { PaddedColumn, SearchInput } from './styleds'
interface PairSearchModalProps extends RouteComponentProps {
isOpen?: boolean
onDismiss?: () => void
}
function PairSearchModal({ history, isOpen, onDismiss }: PairSearchModalProps) {
const { t } = useTranslation()
const { account } = useActiveWeb3React()
const theme = useContext(ThemeContext)
const [searchQuery, setSearchQuery] = useState<string>('')
const allTokens = useAllTokens()
const allPairs = useAllDummyPairs()
const allPairBalances = useTokenBalances(
account,
allPairs.map(p => p.liquidityToken)
)
// clear the input on open
useEffect(() => {
if (isOpen) setSearchQuery('')
}, [isOpen, setSearchQuery])
// manage focus on modal show
const inputRef = useRef<HTMLInputElement>()
function onInput(event) {
const input = event.target.value
const checksummedInput = isAddress(input)
setSearchQuery(checksummedInput || input)
}
const sortedPairList = useMemo(() => {
return allPairs.sort((a, b): number => {
const balanceA = allPairBalances[a.liquidityToken.address]
const balanceB = allPairBalances[b.liquidityToken.address]
return pairComparator(a, b, balanceA, balanceB)
})
}, [allPairs, allPairBalances])
const filteredPairs = useMemo(() => {
return filterPairs(sortedPairList, searchQuery)
}, [searchQuery, sortedPairList])
const selectPair = useCallback(
(pair: Pair) => {
history.push(`/add/${pair.token0.address}-${pair.token1.address}`)
},
[history]
)
const focusedToken = Object.values(allTokens ?? {}).filter(token => {
return token.symbol.toLowerCase() === searchQuery || searchQuery === token.address
})[0]
return (
<Modal
isOpen={isOpen}
onDismiss={onDismiss}
maxHeight={70}
initialFocusRef={isMobile ? undefined : inputRef}
minHeight={70}
>
<Column style={{ width: '100%' }}>
<PaddedColumn gap="20px">
<RowBetween>
<Text fontWeight={500} fontSize={16}>
Select a pool
<QuestionHelper text="Find a pair by searching for its name below." />
</Text>
<CloseIcon onClick={onDismiss} />
</RowBetween>
<SearchInput
type="text"
id="token-search-input"
placeholder={t('tokenSearchPlaceholder')}
value={searchQuery}
ref={inputRef}
onChange={onInput}
/>
<RowBetween>
<Text fontSize={14} fontWeight={500}>
Pool Name
</Text>
</RowBetween>
</PaddedColumn>
<div style={{ width: '100%', height: '1px', backgroundColor: theme.bg2 }} />
<PairList
pairs={filteredPairs}
focusTokenAddress={focusedToken?.address}
onAddLiquidity={selectPair}
onSelectPair={selectPair}
pairBalances={allPairBalances}
/>
<div style={{ width: '100%', height: '1px', backgroundColor: theme.bg2 }} />
<Card>
<AutoRow justify={'center'}>
<div>
<Text fontWeight={500}>
{!isMobile && "Don't see a pool? "}
<StyledInternalLink to="/find">{!isMobile ? 'Import it.' : 'Import pool.'}</StyledInternalLink>
</Text>
</div>
</AutoRow>
</Card>
</Column>
</Modal>
)
}
export default withRouter(PairSearchModal)
...@@ -6,8 +6,9 @@ import { Text } from 'rebass' ...@@ -6,8 +6,9 @@ import { Text } from 'rebass'
import { ThemeContext } from 'styled-components' import { ThemeContext } from 'styled-components'
import { ALL_TOKENS } from '../../constants/tokens' import { ALL_TOKENS } from '../../constants/tokens'
import { useActiveWeb3React } from '../../hooks' import { useActiveWeb3React } from '../../hooks'
import { useAllTokens } from '../../hooks/Tokens'
import { useAddUserToken, useRemoveUserAddedToken } from '../../state/user/hooks'
import { LinkStyledButton, TYPE } from '../../theme' import { LinkStyledButton, TYPE } from '../../theme'
import { isAddress } from '../../utils'
import { ButtonSecondary } from '../Button' import { ButtonSecondary } from '../Button'
import Column, { AutoColumn } from '../Column' import Column, { AutoColumn } from '../Column'
import { RowFixed } from '../Row' import { RowFixed } from '../Row'
...@@ -16,8 +17,7 @@ import { FadedSpan, GreySpan, MenuItem, ModalInfo } from './styleds' ...@@ -16,8 +17,7 @@ import { FadedSpan, GreySpan, MenuItem, ModalInfo } from './styleds'
import Loader from '../Loader' import Loader from '../Loader'
function isDefaultToken(tokenAddress: string, chainId?: number): boolean { function isDefaultToken(tokenAddress: string, chainId?: number): boolean {
const address = isAddress(tokenAddress) return Boolean(chainId && ALL_TOKENS[chainId as ChainId]?.[tokenAddress])
return Boolean(chainId && address && ALL_TOKENS[chainId as ChainId]?.[tokenAddress])
} }
export default function TokenList({ export default function TokenList({
...@@ -27,39 +27,42 @@ export default function TokenList({ ...@@ -27,39 +27,42 @@ export default function TokenList({
onTokenSelect, onTokenSelect,
otherToken, otherToken,
showSendWithSwap, showSendWithSwap,
onRemoveAddedToken, otherSelectedText
otherSelectedText,
hideRemove
}: { }: {
tokens: Token[] tokens: Token[]
selectedToken: string selectedToken: string
allTokenBalances: { [tokenAddress: string]: TokenAmount } allTokenBalances: { [tokenAddress: string]: TokenAmount }
onTokenSelect: (tokenAddress: string) => void onTokenSelect: (tokenAddress: string) => void
onRemoveAddedToken: (chainId: number, tokenAddress: string) => void
otherToken: string otherToken: string
showSendWithSwap?: boolean showSendWithSwap?: boolean
otherSelectedText: string otherSelectedText: string
hideRemove?: boolean
}) { }) {
const { t } = useTranslation() const { t } = useTranslation()
const { account, chainId } = useActiveWeb3React() const { account, chainId } = useActiveWeb3React()
const theme = useContext(ThemeContext) const theme = useContext(ThemeContext)
const allTokens = useAllTokens()
const addToken = useAddUserToken()
const removeToken = useRemoveUserAddedToken()
if (tokens.length === 0) { if (tokens.length === 0) {
return <ModalInfo>{t('noToken')}</ModalInfo> return <ModalInfo>{t('noToken')}</ModalInfo>
} }
return ( return (
<FixedSizeList <FixedSizeList
width="100%" width="100%"
height={500} height={500}
itemCount={tokens.length} itemCount={tokens.length}
itemSize={50} itemSize={56}
style={{ flex: '1', minHeight: 200 }} style={{ flex: '1' }}
itemKey={index => tokens[index].address}
> >
{({ index, style }) => { {({ index, style }) => {
const { address, symbol } = tokens[index] const token = tokens[index]
const { address, symbol } = token
const customAdded = !isDefaultToken(address, chainId) const isDefault = isDefaultToken(address, chainId)
const customAdded = Boolean(!isDefault && allTokens[address])
const balance = allTokenBalances[address] const balance = allTokenBalances[address]
const zeroBalance = balance && JSBI.equal(JSBI.BigInt(0), balance.raw) const zeroBalance = balance && JSBI.equal(JSBI.BigInt(0), balance.raw)
...@@ -81,22 +84,36 @@ export default function TokenList({ ...@@ -81,22 +84,36 @@ export default function TokenList({
{otherToken === address && <GreySpan> ({otherSelectedText})</GreySpan>} {otherToken === address && <GreySpan> ({otherSelectedText})</GreySpan>}
</Text> </Text>
<FadedSpan> <FadedSpan>
<TYPE.main fontWeight={500}>{customAdded && 'Added by user'}</TYPE.main> {customAdded ? (
{customAdded && !hideRemove && ( <TYPE.main fontWeight={500}>
<LinkStyledButton Added by user
onClick={event => { <LinkStyledButton
event.stopPropagation() onClick={event => {
onRemoveAddedToken(chainId, address) event.stopPropagation()
}} removeToken(chainId, address)
style={{ marginLeft: '4px', fontWeight: 400 }} }}
> >
(Remove) (Remove)
</LinkStyledButton> </LinkStyledButton>
)} </TYPE.main>
) : null}
{!isDefault && !customAdded ? (
<TYPE.main fontWeight={500}>
Found by address
<LinkStyledButton
onClick={event => {
event.stopPropagation()
addToken(token)
}}
>
(Add)
</LinkStyledButton>
</TYPE.main>
) : null}
</FadedSpan> </FadedSpan>
</Column> </Column>
</RowFixed> </RowFixed>
<AutoColumn gap="4px" justify="end"> <AutoColumn>
{balance ? ( {balance ? (
<Text> <Text>
{zeroBalance && showSendWithSwap ? ( {zeroBalance && showSendWithSwap ? (
......
...@@ -8,8 +8,8 @@ export const ModalInfo = styled.div` ...@@ -8,8 +8,8 @@ export const ModalInfo = styled.div`
padding: 1rem 1rem; padding: 1rem 1rem;
margin: 0.25rem 0.5rem; margin: 0.25rem 0.5rem;
justify-content: center; justify-content: center;
flex: 1;
user-select: none; user-select: none;
min-height: 200px;
` `
export const FadedSpan = styled(RowFixed)` export const FadedSpan = styled(RowFixed)`
...@@ -50,12 +50,9 @@ export const PaddedColumn = styled(AutoColumn)` ...@@ -50,12 +50,9 @@ export const PaddedColumn = styled(AutoColumn)`
padding-bottom: 12px; padding-bottom: 12px;
` `
const PaddedItem = styled(RowBetween)` export const MenuItem = styled(RowBetween)`
padding: 4px 20px; padding: 4px 20px;
height: 56px; height: 56px;
`
export const MenuItem = styled(PaddedItem)`
cursor: ${({ disabled }) => !disabled && 'pointer'}; cursor: ${({ disabled }) => !disabled && 'pointer'};
pointer-events: ${({ disabled }) => disabled && 'none'}; pointer-events: ${({ disabled }) => disabled && 'none'};
:hover { :hover {
......
...@@ -4,7 +4,7 @@ import { useLocation } from 'react-router' ...@@ -4,7 +4,7 @@ import { useLocation } from 'react-router'
import { Text } from 'rebass' import { Text } from 'rebass'
import { ThemeContext } from 'styled-components' import { ThemeContext } from 'styled-components'
import useParsedQueryString from '../../hooks/useParsedQueryString' import useParsedQueryString from '../../hooks/useParsedQueryString'
import { Version } from '../../hooks/useToggledVersion' import { DEFAULT_VERSION, Version } from '../../hooks/useToggledVersion'
import { StyledInternalLink } from '../../theme' import { StyledInternalLink } from '../../theme'
import { YellowCard } from '../Card' import { YellowCard } from '../Card'
...@@ -20,7 +20,7 @@ export default function BetterTradeLink({ version }: { version: Version }) { ...@@ -20,7 +20,7 @@ export default function BetterTradeLink({ version }: { version: Version }) {
...location, ...location,
search: `?${stringify({ search: `?${stringify({
...search, ...search,
use: version use: version !== DEFAULT_VERSION ? version : undefined
})}` })}`
} }
}, [location, search, version]) }, [location, search, version])
......
import { parseBytes32String } from '@ethersproject/strings' import { parseBytes32String } from '@ethersproject/strings'
import { ChainId, Token, WETH } from '@uniswap/sdk' import { ChainId, Token, WETH } from '@uniswap/sdk'
import { useEffect, useMemo } from 'react' import { useMemo } from 'react'
import { ALL_TOKENS } from '../constants/tokens' import { ALL_TOKENS } from '../constants/tokens'
import { NEVER_RELOAD, useSingleCallResult } from '../state/multicall/hooks' import { NEVER_RELOAD, useSingleCallResult } from '../state/multicall/hooks'
import { useAddUserToken, useUserAddedTokens } from '../state/user/hooks' import { useUserAddedTokens } from '../state/user/hooks'
import { isAddress } from '../utils' import { isAddress } from '../utils'
import { useActiveWeb3React } from './index' import { useActiveWeb3React } from './index'
...@@ -100,21 +100,3 @@ export function useToken(tokenAddress?: string): Token | undefined | null { ...@@ -100,21 +100,3 @@ export function useToken(tokenAddress?: string): Token | undefined | null {
tokenNameBytes32.result tokenNameBytes32.result
]) ])
} }
// gets token information by address (typically user input) and
// automatically adds it for the user if it's a valid token address
export function useTokenByAddressAndAutomaticallyAdd(tokenAddress?: string): Token | undefined | null {
const addToken = useAddUserToken()
const token = useToken(tokenAddress)
const { chainId } = useActiveWeb3React()
const allTokens = useAllTokens()
useEffect(() => {
if (!chainId || !token) return
if (WETH[chainId as ChainId]?.address === token.address) return
if (allTokens[token.address]) return
addToken(token)
}, [token, addToken, chainId, allTokens])
return token
}
...@@ -5,9 +5,11 @@ export enum Version { ...@@ -5,9 +5,11 @@ export enum Version {
v2 = 'v2' v2 = 'v2'
} }
export const DEFAULT_VERSION: Version = Version.v2
export default function useToggledVersion(): Version { export default function useToggledVersion(): Version {
const { use } = useParsedQueryString() const { use } = useParsedQueryString()
if (!use || typeof use !== 'string') return Version.v2 if (!use || typeof use !== 'string') return Version.v2
if (use.toLowerCase() === 'v1') return Version.v1 if (use.toLowerCase() === 'v1') return Version.v1
return Version.v2 return DEFAULT_VERSION
} }
...@@ -5,7 +5,7 @@ import AppBody from '../AppBody' ...@@ -5,7 +5,7 @@ import AppBody from '../AppBody'
import Row, { AutoRow } from '../../components/Row' import Row, { AutoRow } from '../../components/Row'
import TokenLogo from '../../components/TokenLogo' import TokenLogo from '../../components/TokenLogo'
import SearchModal from '../../components/SearchModal' import TokenSearchModal from '../../components/SearchModal/TokenSearchModal'
import { Text } from 'rebass' import { Text } from 'rebass'
import { Plus } from 'react-feather' import { Plus } from 'react-feather'
import { TYPE, StyledInternalLink } from '../../theme' import { TYPE, StyledInternalLink } from '../../theme'
...@@ -128,9 +128,8 @@ export default function CreatePool({ location }: RouteComponentProps) { ...@@ -128,9 +128,8 @@ export default function CreatePool({ location }: RouteComponentProps) {
</ButtonPrimary> </ButtonPrimary>
)} )}
</AutoColumn> </AutoColumn>
<SearchModal <TokenSearchModal
isOpen={showSearch} isOpen={showSearch}
filterType="tokens"
onTokenSelect={address => { onTokenSelect={address => {
activeField === Fields.TOKEN0 ? setToken0Address(address) : setToken1Address(address) activeField === Fields.TOKEN0 ? setToken0Address(address) : setToken1Address(address)
}} }}
......
...@@ -15,7 +15,7 @@ import { MIGRATOR_ADDRESS } from '../../constants/abis/migrator' ...@@ -15,7 +15,7 @@ import { MIGRATOR_ADDRESS } from '../../constants/abis/migrator'
import { usePair } from '../../data/Reserves' import { usePair } from '../../data/Reserves'
import { useTotalSupply } from '../../data/TotalSupply' import { useTotalSupply } from '../../data/TotalSupply'
import { useActiveWeb3React } from '../../hooks' import { useActiveWeb3React } from '../../hooks'
import { useTokenByAddressAndAutomaticallyAdd } from '../../hooks/Tokens' import { useToken } from '../../hooks/Tokens'
import { ApprovalState, useApproveCallback } from '../../hooks/useApproveCallback' import { ApprovalState, useApproveCallback } from '../../hooks/useApproveCallback'
import { useV1ExchangeContract, useV2MigratorContract } from '../../hooks/useContract' import { useV1ExchangeContract, useV2MigratorContract } from '../../hooks/useContract'
import { NEVER_RELOAD, useSingleCallResult } from '../../state/multicall/hooks' import { NEVER_RELOAD, useSingleCallResult } from '../../state/multicall/hooks'
...@@ -242,7 +242,7 @@ export default function MigrateV1Exchange({ ...@@ -242,7 +242,7 @@ export default function MigrateV1Exchange({
const tokenAddress = useSingleCallResult(exchangeContract, 'tokenAddress', undefined, NEVER_RELOAD)?.result?.[0] const tokenAddress = useSingleCallResult(exchangeContract, 'tokenAddress', undefined, NEVER_RELOAD)?.result?.[0]
const token = useTokenByAddressAndAutomaticallyAdd(tokenAddress) const token = useToken(tokenAddress)
const liquidityToken: Token | undefined = useMemo( const liquidityToken: Token | undefined = useMemo(
() => (validated && token ? new Token(chainId, validated, 18, `UNI-V1-${token.symbol}`) : undefined), () => (validated && token ? new Token(chainId, validated, 18, `UNI-V1-${token.symbol}`) : undefined),
......
...@@ -10,7 +10,7 @@ import { SearchInput } from '../../components/SearchModal/styleds' ...@@ -10,7 +10,7 @@ import { SearchInput } from '../../components/SearchModal/styleds'
import TokenLogo from '../../components/TokenLogo' import TokenLogo from '../../components/TokenLogo'
import { useAllTokenV1Exchanges } from '../../data/V1' import { useAllTokenV1Exchanges } from '../../data/V1'
import { useActiveWeb3React } from '../../hooks' import { useActiveWeb3React } from '../../hooks'
import { useTokenByAddressAndAutomaticallyAdd } from '../../hooks/Tokens' import { useToken } from '../../hooks/Tokens'
import { useWalletModalToggle } from '../../state/application/hooks' import { useWalletModalToggle } from '../../state/application/hooks'
import { useTokenBalances } from '../../state/wallet/hooks' import { useTokenBalances } from '../../state/wallet/hooks'
import { TYPE } from '../../theme' import { TYPE } from '../../theme'
...@@ -45,7 +45,7 @@ export default function MigrateV1({ history }: RouteComponentProps) { ...@@ -45,7 +45,7 @@ export default function MigrateV1({ history }: RouteComponentProps) {
const [tokenSearch, setTokenSearch] = useState<string>('') const [tokenSearch, setTokenSearch] = useState<string>('')
const handleTokenSearchChange = useCallback(e => setTokenSearch(e.target.value), [setTokenSearch]) const handleTokenSearchChange = useCallback(e => setTokenSearch(e.target.value), [setTokenSearch])
const searchedToken: Token | undefined = useTokenByAddressAndAutomaticallyAdd(tokenSearch) const searchedToken: Token | undefined = useToken(tokenSearch)
const unmigratedLiquidityExchangeAddresses: TokenAmount[] = useMemo( const unmigratedLiquidityExchangeAddresses: TokenAmount[] = useMemo(
() => () =>
......
import React, { useState, useContext } from 'react' import React, { useState, useContext, useCallback } from 'react'
import styled, { ThemeContext } from 'styled-components' import styled, { ThemeContext } from 'styled-components'
import { JSBI, Pair } from '@uniswap/sdk' import { JSBI, Pair } from '@uniswap/sdk'
import { RouteComponentProps } from 'react-router-dom' import { RouteComponentProps } from 'react-router-dom'
import Question from '../../components/QuestionHelper' import Question from '../../components/QuestionHelper'
import SearchModal from '../../components/SearchModal' import PairSearchModal from '../../components/SearchModal/PairSearchModal'
import PositionCard from '../../components/PositionCard' import PositionCard from '../../components/PositionCard'
import { useUserHasLiquidityInAllTokens } from '../../data/V1' import { useUserHasLiquidityInAllTokens } from '../../data/V1'
import { useTokenBalances } from '../../state/wallet/hooks' import { useTokenBalances } from '../../state/wallet/hooks'
...@@ -61,6 +61,10 @@ export default function Pool({ history }: RouteComponentProps) { ...@@ -61,6 +61,10 @@ export default function Pool({ history }: RouteComponentProps) {
const hasV1Liquidity = useUserHasLiquidityInAllTokens() const hasV1Liquidity = useUserHasLiquidityInAllTokens()
const handleSearchDismiss = useCallback(() => {
setShowPoolSearch(false)
}, [setShowPoolSearch])
return ( return (
<AppBody> <AppBody>
<AutoColumn gap="lg" justify="center"> <AutoColumn gap="lg" justify="center">
...@@ -117,7 +121,7 @@ export default function Pool({ history }: RouteComponentProps) { ...@@ -117,7 +121,7 @@ export default function Pool({ history }: RouteComponentProps) {
</ColumnCenter> </ColumnCenter>
</FixedBottom> </FixedBottom>
</Positions> </Positions>
<SearchModal isOpen={showPoolSearch} onDismiss={() => setShowPoolSearch(false)} /> <PairSearchModal isOpen={showPoolSearch} onDismiss={handleSearchDismiss} />
</AutoColumn> </AutoColumn>
</AppBody> </AppBody>
) )
......
import { JSBI, Pair, Token, TokenAmount } from '@uniswap/sdk' import { JSBI, Pair, Token, TokenAmount } from '@uniswap/sdk'
import React, { useEffect, useState } from 'react' import React, { useCallback, useEffect, useState } from 'react'
import { Plus } from 'react-feather' import { Plus } from 'react-feather'
import { RouteComponentProps } from 'react-router-dom' import { RouteComponentProps } from 'react-router-dom'
import { Text } from 'rebass' import { Text } from 'rebass'
...@@ -8,7 +8,7 @@ import { LightCard } from '../../components/Card' ...@@ -8,7 +8,7 @@ import { LightCard } from '../../components/Card'
import { AutoColumn, ColumnCenter } from '../../components/Column' import { AutoColumn, ColumnCenter } from '../../components/Column'
import PositionCard from '../../components/PositionCard' import PositionCard from '../../components/PositionCard'
import Row from '../../components/Row' import Row from '../../components/Row'
import SearchModal from '../../components/SearchModal' import TokenSearchModal from '../../components/SearchModal/TokenSearchModal'
import TokenLogo from '../../components/TokenLogo' import TokenLogo from '../../components/TokenLogo'
import { usePair } from '../../data/Reserves' import { usePair } from '../../data/Reserves'
import { useActiveWeb3React } from '../../hooks' import { useActiveWeb3React } from '../../hooks'
...@@ -49,6 +49,17 @@ export default function PoolFinder({ history }: RouteComponentProps) { ...@@ -49,6 +49,17 @@ export default function PoolFinder({ history }: RouteComponentProps) {
(!!pair && JSBI.equal(pair.reserve0.raw, JSBI.BigInt(0)) && JSBI.equal(pair.reserve1.raw, JSBI.BigInt(0))) (!!pair && JSBI.equal(pair.reserve0.raw, JSBI.BigInt(0)) && JSBI.equal(pair.reserve1.raw, JSBI.BigInt(0)))
const allowImport: boolean = position && JSBI.greaterThan(position.raw, JSBI.BigInt(0)) const allowImport: boolean = position && JSBI.greaterThan(position.raw, JSBI.BigInt(0))
const handleTokenSelect = useCallback(
(address: string) => {
activeField === Fields.TOKEN0 ? setToken0Address(address) : setToken1Address(address)
},
[activeField]
)
const handleSearchDismiss = useCallback(() => {
setShowSearch(false)
}, [setShowSearch])
return ( return (
<AppBody> <AppBody>
<AutoColumn gap="md"> <AutoColumn gap="md">
...@@ -146,15 +157,10 @@ export default function PoolFinder({ history }: RouteComponentProps) { ...@@ -146,15 +157,10 @@ export default function PoolFinder({ history }: RouteComponentProps) {
</Text> </Text>
</ButtonPrimary> </ButtonPrimary>
</AutoColumn> </AutoColumn>
<SearchModal <TokenSearchModal
isOpen={showSearch} isOpen={showSearch}
filterType="tokens" onTokenSelect={handleTokenSelect}
onTokenSelect={address => { onDismiss={handleSearchDismiss}
activeField === Fields.TOKEN0 ? setToken0Address(address) : setToken1Address(address)
}}
onDismiss={() => {
setShowSearch(false)
}}
hiddenToken={activeField === Fields.TOKEN0 ? token1Address : token0Address} hiddenToken={activeField === Fields.TOKEN0 ? token1Address : token0Address}
/> />
</AppBody> </AppBody>
......
...@@ -5,7 +5,7 @@ import { useActiveWeb3React } from '../../hooks' ...@@ -5,7 +5,7 @@ import { useActiveWeb3React } from '../../hooks'
import { AppDispatch, AppState } from '../index' import { AppDispatch, AppState } from '../index'
import { Field, typeInput } from './actions' import { Field, typeInput } from './actions'
import { setDefaultsFromURLMatchParams } from '../mint/actions' import { setDefaultsFromURLMatchParams } from '../mint/actions'
import { useTokenByAddressAndAutomaticallyAdd } from '../../hooks/Tokens' import { useToken } from '../../hooks/Tokens'
import { Token, Pair, TokenAmount, Percent, JSBI, Route } from '@uniswap/sdk' import { Token, Pair, TokenAmount, Percent, JSBI, Route } from '@uniswap/sdk'
import { usePair } from '../../data/Reserves' import { usePair } from '../../data/Reserves'
import { useTokenBalances } from '../wallet/hooks' import { useTokenBalances } from '../wallet/hooks'
...@@ -40,12 +40,12 @@ export function useDerivedBurnInfo(): { ...@@ -40,12 +40,12 @@ export function useDerivedBurnInfo(): {
} = useBurnState() } = useBurnState()
// tokens // tokens
const tokenA = useTokenByAddressAndAutomaticallyAdd(tokenAAddress) const tokenA = useToken(tokenAAddress)
const tokenB = useTokenByAddressAndAutomaticallyAdd(tokenBAddress) const tokenB = useToken(tokenBAddress)
const tokens: { [field in Extract<Field, Field.TOKEN_A | Field.TOKEN_B>]?: Token } = useMemo( const tokens: { [field in Extract<Field, Field.TOKEN_A | Field.TOKEN_B>]?: Token } = useMemo(
() => ({ () => ({
[Field.TOKEN_A]: tokenA, [Field.TOKEN_A]: tokenA ?? undefined,
[Field.TOKEN_B]: tokenB [Field.TOKEN_B]: tokenB ?? undefined
}), }),
[tokenA, tokenB] [tokenA, tokenB]
) )
......
...@@ -5,7 +5,7 @@ import { Token, TokenAmount, Route, JSBI, Price, Percent, Pair } from '@uniswap/ ...@@ -5,7 +5,7 @@ import { Token, TokenAmount, Route, JSBI, Price, Percent, Pair } from '@uniswap/
import { useActiveWeb3React } from '../../hooks' import { useActiveWeb3React } from '../../hooks'
import { AppDispatch, AppState } from '../index' import { AppDispatch, AppState } from '../index'
import { setDefaultsFromURLMatchParams, Field, typeInput } from './actions' import { setDefaultsFromURLMatchParams, Field, typeInput } from './actions'
import { useTokenByAddressAndAutomaticallyAdd } from '../../hooks/Tokens' import { useToken } from '../../hooks/Tokens'
import { useTokenBalancesTreatWETHAsETH } from '../wallet/hooks' import { useTokenBalancesTreatWETHAsETH } from '../wallet/hooks'
import { usePair } from '../../data/Reserves' import { usePair } from '../../data/Reserves'
import { useTotalSupply } from '../../data/TotalSupply' import { useTotalSupply } from '../../data/TotalSupply'
...@@ -42,8 +42,8 @@ export function useDerivedMintInfo(): { ...@@ -42,8 +42,8 @@ export function useDerivedMintInfo(): {
const dependentField = independentField === Field.TOKEN_A ? Field.TOKEN_B : Field.TOKEN_A const dependentField = independentField === Field.TOKEN_A ? Field.TOKEN_B : Field.TOKEN_A
// tokens // tokens
const tokenA = useTokenByAddressAndAutomaticallyAdd(tokenAAddress) const tokenA = useToken(tokenAAddress)
const tokenB = useTokenByAddressAndAutomaticallyAdd(tokenBAddress) const tokenB = useToken(tokenBAddress)
const tokens: { [field in Field]?: Token } = useMemo( const tokens: { [field in Field]?: Token } = useMemo(
() => ({ () => ({
[Field.TOKEN_A]: tokenA, [Field.TOKEN_A]: tokenA,
......
...@@ -5,7 +5,7 @@ import { useCallback, useEffect } from 'react' ...@@ -5,7 +5,7 @@ import { useCallback, useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux' import { useDispatch, useSelector } from 'react-redux'
import { useV1Trade } from '../../data/V1' import { useV1Trade } from '../../data/V1'
import { useActiveWeb3React } from '../../hooks' import { useActiveWeb3React } from '../../hooks'
import { useTokenByAddressAndAutomaticallyAdd } from '../../hooks/Tokens' import { useToken } from '../../hooks/Tokens'
import { useTradeExactIn, useTradeExactOut } from '../../hooks/Trades' import { useTradeExactIn, useTradeExactOut } from '../../hooks/Trades'
import useParsedQueryString from '../../hooks/useParsedQueryString' import useParsedQueryString from '../../hooks/useParsedQueryString'
import { isAddress } from '../../utils' import { isAddress } from '../../utils'
...@@ -90,8 +90,8 @@ export function useDerivedSwapInfo(): { ...@@ -90,8 +90,8 @@ export function useDerivedSwapInfo(): {
[Field.OUTPUT]: { address: tokenOutAddress } [Field.OUTPUT]: { address: tokenOutAddress }
} = useSwapState() } = useSwapState()
const tokenIn = useTokenByAddressAndAutomaticallyAdd(tokenInAddress) const tokenIn = useToken(tokenInAddress)
const tokenOut = useTokenByAddressAndAutomaticallyAdd(tokenOutAddress) const tokenOut = useToken(tokenOutAddress)
const relevantTokenBalances = useTokenBalancesTreatWETHAsETH(account ?? undefined, [ const relevantTokenBalances = useTokenBalancesTreatWETHAsETH(account ?? undefined, [
tokenIn ?? undefined, tokenIn ?? undefined,
......
...@@ -171,7 +171,7 @@ export function useAllDummyPairs(): Pair[] { ...@@ -171,7 +171,7 @@ export function useAllDummyPairs(): Pair[] {
// pairs saved by users // pairs saved by users
const savedSerializedPairs = useSelector<AppState, AppState['user']['pairs']>(({ user: { pairs } }) => pairs) const savedSerializedPairs = useSelector<AppState, AppState['user']['pairs']>(({ user: { pairs } }) => pairs)
const userPairs = useMemo( const userPairs: Pair[] = useMemo(
() => () =>
Object.values<SerializedPair>(savedSerializedPairs[chainId ?? -1] ?? {}).map( Object.values<SerializedPair>(savedSerializedPairs[chainId ?? -1] ?? {}).map(
pair => pair =>
......
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