Commit 3a2566b4 authored by Ian Lapham's avatar Ian Lapham Committed by GitHub

Changes to useReserves, escapreRegex moved to utils, code cleanup (#762)

* bug fixes on non-existent vs no reserves, fix scanning on pair search, small ui tweaks

* remove unused vars

* remove mainnet in injected connector

* code cleanup for pr

* update pair value check
parent c9db5fb2
import React, { useState, useEffect, useContext } from 'react' import React, { useState, useEffect, useContext } from 'react'
import styled, { ThemeContext } from 'styled-components' import styled, { ThemeContext } from 'styled-components'
// import QR from '../../assets/svg/QR.svg'
import { isAddress } from '../../utils' import { isAddress } from '../../utils'
import { useWeb3React, useDebounce } from '../../hooks' import { useWeb3React, useDebounce } from '../../hooks'
import { Link, TYPE } from '../../theme' import { Link, TYPE } from '../../theme'
...@@ -64,16 +63,6 @@ const Input = styled.input<{ error?: boolean }>` ...@@ -64,16 +63,6 @@ const Input = styled.input<{ error?: boolean }>`
} }
` `
// const QRWrapper = styled.div`
// display: flex;
// align-items: center;
// justify-content: center;
// border: 1px solid ${({ theme }) => theme.bg3};
// background: #fbfbfb;
// padding: 4px;
// border-radius: 8px;
// `
export default function AddressInputPanel({ export default function AddressInputPanel({
initialInput = '', initialInput = '',
onChange, onChange,
...@@ -190,7 +179,7 @@ export default function AddressInputPanel({ ...@@ -190,7 +179,7 @@ export default function AddressInputPanel({
<TYPE.black color={theme.text2} fontWeight={500} fontSize={14}> <TYPE.black color={theme.text2} fontWeight={500} fontSize={14}>
Recipient Recipient
</TYPE.black> </TYPE.black>
{(data.name || data.address) && ( {data.address && (
<Link <Link
href={getEtherscanLink(chainId, data.name || data.address, 'address')} href={getEtherscanLink(chainId, data.name || data.address, 'address')}
style={{ fontSize: '14px' }} style={{ fontSize: '14px' }}
...@@ -210,9 +199,6 @@ export default function AddressInputPanel({ ...@@ -210,9 +199,6 @@ export default function AddressInputPanel({
onChange={onInput} onChange={onInput}
value={input} value={input}
/> />
{/* <QRWrapper>
<img src={QR} alt="" />
</QRWrapper> */}
</AutoColumn> </AutoColumn>
</InputContainer> </InputContainer>
</ContainerRow> </ContainerRow>
......
import React, { useState, useEffect } from 'react' import React, { useState, useEffect } from 'react'
import { withRouter } from 'react-router-dom' import { withRouter, RouteComponentProps } from 'react-router-dom'
import { Token, JSBI, WETH } from '@uniswap/sdk' import { Token, WETH } from '@uniswap/sdk'
import Row, { AutoRow } from '../Row' import Row, { AutoRow } from '../Row'
import TokenLogo from '../TokenLogo' import TokenLogo from '../TokenLogo'
...@@ -21,7 +21,13 @@ const Fields = { ...@@ -21,7 +21,13 @@ const Fields = {
TOKEN1: 1 TOKEN1: 1
} }
function CreatePool({ history }) { const STEP = {
SELECT_TOKENS: 'SELECT_TOKENS', // choose input and output tokens
READY_TO_CREATE: 'READY_TO_CREATE', // enable 'create' button
SHOW_CREATE_PAGE: 'SHOW_CREATE_PAGE' // show create page
}
function CreatePool({ history }: RouteComponentProps<{}>) {
const { chainId } = useWeb3React() const { chainId } = useWeb3React()
const [showSearch, setShowSearch] = useState<boolean>(false) const [showSearch, setShowSearch] = useState<boolean>(false)
const [activeField, setActiveField] = useState<number>(Fields.TOKEN0) const [activeField, setActiveField] = useState<number>(Fields.TOKEN0)
...@@ -32,21 +38,22 @@ function CreatePool({ history }) { ...@@ -32,21 +38,22 @@ function CreatePool({ history }) {
const token0: Token = useToken(token0Address) const token0: Token = useToken(token0Address)
const token1: Token = useToken(token1Address) const token1: Token = useToken(token1Address)
const [step, setStep] = useState<number>(1) const [step, setStep] = useState<string>(STEP.SELECT_TOKENS)
const pair = usePair(token0, token1) const pair = usePair(token0, token1)
const pairExists = // used to detect new exchange
pair && JSBI.notEqual(pair.reserve0.raw, JSBI.BigInt(0)) && JSBI.notEqual(pair.reserve1.raw, JSBI.BigInt(0))
// if both tokens selected but pair doesnt exist, enable button to create pair
useEffect(() => { useEffect(() => {
if (token0Address && token1Address && pair && !pairExists) { if (token0Address && token1Address && pair === null) {
setStep(2) setStep(STEP.READY_TO_CREATE)
} }
}, [pair, pairExists, token0Address, token1Address]) }, [pair, token0Address, token1Address])
if (step === 2 && !pairExists) { // if theyve clicked create, show add liquidity page
if (step === STEP.SHOW_CREATE_PAGE) {
return <AddLiquidity token0={token0Address} token1={token1Address} /> return <AddLiquidity token0={token0Address} token1={token1Address} />
} else }
return ( return (
<AutoColumn gap="20px"> <AutoColumn gap="20px">
<AutoColumn gap="24px"> <AutoColumn gap="24px">
...@@ -86,7 +93,7 @@ function CreatePool({ history }) { ...@@ -86,7 +93,7 @@ function CreatePool({ history }) {
setShowSearch(true) setShowSearch(true)
setActiveField(Fields.TOKEN1) setActiveField(Fields.TOKEN1)
}} }}
disabled={step !== 1} disabled={step !== STEP.SELECT_TOKENS}
> >
<Text fontSize={20}>Select second token</Text> <Text fontSize={20}>Select second token</Text>
</ButtonDropwdown> </ButtonDropwdown>
...@@ -105,7 +112,7 @@ function CreatePool({ history }) { ...@@ -105,7 +112,7 @@ function CreatePool({ history }) {
</Row> </Row>
</ButtonDropwdownLight> </ButtonDropwdownLight>
)} )}
{pairExists ? ( {pair ? ( // pair already exists - prompt to add liquidity to existing pool
<AutoRow padding="10px" justify="center"> <AutoRow padding="10px" justify="center">
<TYPE.body textAlign="center"> <TYPE.body textAlign="center">
Pool already exists! Pool already exists!
...@@ -113,7 +120,7 @@ function CreatePool({ history }) { ...@@ -113,7 +120,7 @@ function CreatePool({ history }) {
</TYPE.body> </TYPE.body>
</AutoRow> </AutoRow>
) : ( ) : (
<ButtonPrimary disabled={step !== 2}> <ButtonPrimary disabled={step !== STEP.READY_TO_CREATE} onClick={() => setStep(STEP.SHOW_CREATE_PAGE)}>
<Text fontWeight={500} fontSize={20}> <Text fontWeight={500} fontSize={20}>
Create Pool Create Pool
</Text> </Text>
......
...@@ -23,7 +23,7 @@ export default function Footer() { ...@@ -23,7 +23,7 @@ export default function Footer() {
return ( return (
<FooterFrame> <FooterFrame>
<form action="https://forms.gle/DaLuqvJsVhVaAM3J9"> <form action="https://forms.gle/DaLuqvJsVhVaAM3J9" target="_blank">
<ButtonSecondary <ButtonSecondary
style={{ style={{
padding: ' 8px 12px', padding: ' 8px 12px',
......
import React from 'react' import React from 'react'
import styled from 'styled-components' import styled from 'styled-components'
import { escapeRegExp } from '../../utils'
const StyledInput = styled.input<{ error?: boolean; fontSize?: string; align?: string }>` const StyledInput = styled.input<{ error?: boolean; fontSize?: string; align?: string }>`
color: ${({ error, theme }) => error && theme.red1}; color: ${({ error, theme }) => error && theme.red1};
...@@ -41,10 +42,6 @@ const StyledInput = styled.input<{ error?: boolean; fontSize?: string; align?: s ...@@ -41,10 +42,6 @@ const StyledInput = styled.input<{ error?: boolean; fontSize?: string; align?: s
const inputRegex = RegExp(`^\\d*(?:\\\\.)?\\d*$`) // match escaped "." characters via in a non-capturing group const inputRegex = RegExp(`^\\d*(?:\\\\.)?\\d*$`) // match escaped "." characters via in a non-capturing group
function escapeRegExp(string: string): string {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') // $& means the whole matched string
}
export const Input = React.memo(function InnerInput({ export const Input = React.memo(function InnerInput({
value, value,
onUserInput, onUserInput,
......
...@@ -46,7 +46,8 @@ function PoolFinder({ history }: RouteComponentProps) { ...@@ -46,7 +46,8 @@ function PoolFinder({ history }: RouteComponentProps) {
const position: TokenAmount = useAddressBalance(account, pair?.liquidityToken) const position: TokenAmount = useAddressBalance(account, pair?.liquidityToken)
const newPair: boolean = const newPair: boolean =
!!pair && JSBI.equal(pair.reserve0.raw, JSBI.BigInt(0)) && JSBI.equal(pair.reserve1.raw, JSBI.BigInt(0)) pair === null ||
(!!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))
return ( return (
......
import React, { useState, useRef, useMemo, useEffect, useContext } from 'react' import React, { useState, useRef, useMemo, useEffect, useContext } from 'react'
import '@reach/tooltip/styles.css' import '@reach/tooltip/styles.css'
import styled, { ThemeContext } from 'styled-components' import styled, { ThemeContext } from 'styled-components'
import escapeStringRegex from 'escape-string-regexp'
import { JSBI, Token, WETH } from '@uniswap/sdk' import { JSBI, Token, WETH } from '@uniswap/sdk'
import { isMobile } from 'react-device-detect' import { isMobile } from 'react-device-detect'
import { RouteComponentProps, withRouter } from 'react-router-dom' import { RouteComponentProps, withRouter } from 'react-router-dom'
...@@ -22,7 +21,7 @@ import { ButtonPrimary, ButtonSecondary } from '../../components/Button' ...@@ -22,7 +21,7 @@ import { ButtonPrimary, ButtonSecondary } from '../../components/Button'
import { Spinner, TYPE } from '../../theme' import { Spinner, TYPE } from '../../theme'
import { RowBetween, RowFixed, AutoRow } from '../Row' import { RowBetween, RowFixed, AutoRow } from '../Row'
import { isAddress } from '../../utils' import { isAddress, escapeRegExp } from '../../utils'
import { useWeb3React } from '../../hooks' import { useWeb3React } from '../../hooks'
import { import {
useAllDummyPairs, useAllDummyPairs,
...@@ -191,6 +190,16 @@ function SearchModal({ ...@@ -191,6 +190,16 @@ function SearchModal({
// if the current input is an address, and we don't have the token in context, try to fetch it // if the current input is an address, and we don't have the token in context, try to fetch it
const token = useToken(searchQuery) const token = useToken(searchQuery)
const [temporaryToken, setTemporaryToken] = useState<Token | null>() const [temporaryToken, setTemporaryToken] = useState<Token | null>()
// filters for ordering
const [activeFilter, setActiveFilter] = useState(FILTERS.BALANCES)
// toggle specific token import view
const [showTokenImport, setShowTokenImport] = useState(false)
// used to help scanning on results, put token found from input on left
const [identifiedToken, setIdentifiedToken] = useState<Token | null>()
useEffect(() => { useEffect(() => {
const address = isAddress(searchQuery) const address = isAddress(searchQuery)
if (address && !token) { if (address && !token) {
...@@ -207,10 +216,6 @@ function SearchModal({ ...@@ -207,10 +216,6 @@ function SearchModal({
} }
}, [searchQuery, token, fetchTokenByAddress]) }, [searchQuery, token, fetchTokenByAddress])
const [activeFilter, setActiveFilter] = useState(FILTERS.BALANCES)
const [showTokenImport, setShowTokenImport] = useState(false)
// reset view on close // reset view on close
useEffect(() => { useEffect(() => {
if (!isOpen) { if (!isOpen) {
...@@ -272,13 +277,13 @@ function SearchModal({ ...@@ -272,13 +277,13 @@ function SearchModal({
include && include &&
inputIsAddress && inputIsAddress &&
typeof tokenEntry[tokenEntryKey] === 'string' && typeof tokenEntry[tokenEntryKey] === 'string' &&
!!tokenEntry[tokenEntryKey].match(new RegExp(escapeStringRegex(searchQuery), 'i')) !!tokenEntry[tokenEntryKey].match(new RegExp(escapeRegExp(searchQuery), 'i'))
) )
} }
return ( return (
include && include &&
typeof tokenEntry[tokenEntryKey] === 'string' && typeof tokenEntry[tokenEntryKey] === 'string' &&
!!tokenEntry[tokenEntryKey].match(new RegExp(escapeStringRegex(searchQuery), 'i')) !!tokenEntry[tokenEntryKey].match(new RegExp(escapeRegExp(searchQuery), 'i'))
) )
}) })
return regexMatches.some(m => m) return regexMatches.some(m => m)
...@@ -293,7 +298,6 @@ function SearchModal({ ...@@ -293,7 +298,6 @@ function SearchModal({
// manage focus on modal show // manage focus on modal show
const inputRef = useRef() const inputRef = useRef()
function onInput(event) { function onInput(event) {
const input = event.target.value const input = event.target.value
const checksummedInput = isAddress(input) const checksummedInput = isAddress(input)
...@@ -305,9 +309,6 @@ function SearchModal({ ...@@ -305,9 +309,6 @@ function SearchModal({
onDismiss() onDismiss()
} }
// sort tokens
const escapeStringRegexp = string => string
const sortedPairList = useMemo(() => { const sortedPairList = useMemo(() => {
return allPairs.sort((a, b): number => { return allPairs.sort((a, b): number => {
// sort by balance // sort by balance
...@@ -342,9 +343,15 @@ function SearchModal({ ...@@ -342,9 +343,15 @@ function SearchModal({
(field === 'name' && !isAddress) || (field === 'name' && !isAddress) ||
(field === 'symbol' && !isAddress) (field === 'symbol' && !isAddress)
) { ) {
if (token0[field].match(new RegExp(escapeRegExp(searchQuery), 'i'))) {
setIdentifiedToken(token0)
}
if (token1[field].match(new RegExp(escapeRegExp(searchQuery), 'i'))) {
setIdentifiedToken(token1)
}
return ( return (
token0[field].match(new RegExp(escapeStringRegexp(searchQuery), 'i')) || token0[field].match(new RegExp(escapeRegExp(searchQuery), 'i')) ||
token1[field].match(new RegExp(escapeStringRegexp(searchQuery), 'i')) token1[field].match(new RegExp(escapeRegExp(searchQuery), 'i'))
) )
} }
return false return false
...@@ -366,8 +373,9 @@ function SearchModal({ ...@@ -366,8 +373,9 @@ function SearchModal({
return ( return (
filteredPairList && filteredPairList &&
filteredPairList.map((pair, i) => { filteredPairList.map((pair, i) => {
const token0 = pair.token0 // reset ordering to help scan search results
const token1 = pair.token1 const token0 = identifiedToken ? (identifiedToken.equals(pair.token0) ? pair.token0 : pair.token1) : pair.token0
const token1 = identifiedToken ? (identifiedToken.equals(pair.token0) ? pair.token1 : pair.token0) : pair.token1
const pairAddress = pair.liquidityToken.address const pairAddress = pair.liquidityToken.address
const balance = allBalances?.[account]?.[pairAddress]?.toSignificant(6) const balance = allBalances?.[account]?.[pairAddress]?.toSignificant(6)
const zeroBalance = const zeroBalance =
...@@ -434,20 +442,6 @@ function SearchModal({ ...@@ -434,20 +442,6 @@ function SearchModal({
return <TokenModalInfo>{t('noToken')}</TokenModalInfo> return <TokenModalInfo>{t('noToken')}</TokenModalInfo>
} }
} else { } else {
/**
* @TODO
// TODO is this the right place to link to create exchange?
// else if (isAddress(searchQuery) && tokenAddress === ethers.constants.AddressZero) {
// return (
// <>
// <TokenModalInfo>{t('noToken')}</TokenModalInfo>
// <TokenModalInfo>
// <Link to={`/create-exchange/${searchQuery}`}>{t('createExchange')}</Link>
// </TokenModalInfo>
// </>
// )
// }
*/
return filteredTokenList return filteredTokenList
.sort((a, b) => { .sort((a, b) => {
if (a.address === WETH[chainId].address) { if (a.address === WETH[chainId].address) {
......
import React from 'react' import React from 'react'
import styled from 'styled-components' import styled from 'styled-components'
import QRCode from 'qrcode.react' import QRCode from 'qrcode.react'
import { useDarkModeManager } from '../../state/user/hooks'
const QRCodeWrapper = styled.div` const QRCodeWrapper = styled.div`
${({ theme }) => theme.flexColumnNoWrap}; ${({ theme }) => theme.flexColumnNoWrap};
...@@ -17,12 +16,5 @@ interface WalletConnectDataProps { ...@@ -17,12 +16,5 @@ interface WalletConnectDataProps {
} }
export default function WalletConnectData({ uri = '', size }: WalletConnectDataProps) { export default function WalletConnectData({ uri = '', size }: WalletConnectDataProps) {
const [isDark] = useDarkModeManager() return <QRCodeWrapper>{uri && <QRCode size={size} value={uri} />}</QRCodeWrapper>
return (
<QRCodeWrapper>
{uri && (
<QRCode size={size} value={uri} bgColor={isDark ? '#333639' : 'white'} fgColor={isDark ? 'white' : 'black'} />
)}
</QRCodeWrapper>
)
} }
...@@ -15,9 +15,16 @@ function getReserves(contract: Contract, token0: Token, token1: Token): () => Pr ...@@ -15,9 +15,16 @@ function getReserves(contract: Contract, token0: Token, token1: Token): () => Pr
return new Pair(new TokenAmount(token0, reserve0.toString()), new TokenAmount(token1, reserve1.toString())) return new Pair(new TokenAmount(token0, reserve0.toString()), new TokenAmount(token1, reserve1.toString()))
} }
) )
.catch(() => {
return null
})
} }
// undefined while loading, null if no liquidity, pair otherwise /*
* if loading, return undefined
* if no pair created yet, return null
* if pair already created (even if 0 reserves), return pair
*/
export function usePair(tokenA?: Token, tokenB?: Token): undefined | Pair | null { export function usePair(tokenA?: Token, tokenB?: Token): undefined | Pair | null {
const bothDefined = !!tokenA && !!tokenB const bothDefined = !!tokenA && !!tokenB
const invalid = bothDefined && tokenA.equals(tokenB) const invalid = bothDefined && tokenA.equals(tokenB)
......
...@@ -221,7 +221,8 @@ function AddLiquidity({ token0, token1 }: AddLiquidityProps) { ...@@ -221,7 +221,8 @@ function AddLiquidity({ token0, token1 }: AddLiquidityProps) {
const route: Route = pair ? new Route([pair], tokens[independentField]) : undefined const route: Route = pair ? new Route([pair], tokens[independentField]) : undefined
const totalSupply: TokenAmount = useTotalSupply(pair?.liquidityToken) const totalSupply: TokenAmount = useTotalSupply(pair?.liquidityToken)
const noLiquidity = // used to detect new exchange const noLiquidity = // used to detect new exchange
!!pair && JSBI.equal(pair.reserve0.raw, JSBI.BigInt(0)) && JSBI.equal(pair.reserve1.raw, JSBI.BigInt(0)) pair === null ||
(!!pair && JSBI.equal(pair.reserve0.raw, JSBI.BigInt(0)) && JSBI.equal(pair.reserve1.raw, JSBI.BigInt(0)))
// get user-pecific and token-specific lookup data // get user-pecific and token-specific lookup data
const userBalances: { [field: number]: TokenAmount } = { const userBalances: { [field: number]: TokenAmount } = {
......
...@@ -218,3 +218,7 @@ export async function getTokenBalance(tokenAddress, address, library) { ...@@ -218,3 +218,7 @@ export async function getTokenBalance(tokenAddress, address, library) {
return getContract(tokenAddress, ERC20_ABI, library).balanceOf(address) return getContract(tokenAddress, ERC20_ABI, library).balanceOf(address)
} }
export function escapeRegExp(string: string): string {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') // $& means the whole matched string
}
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