Commit eaf8d5a3 authored by Ian Lapham's avatar Ian Lapham Committed by GitHub

Add routes through ETH (#665)

* add fix for ETH balance fetching

* add tokens to other testnets

* update with Exchange -> Pair

* routes throuh ETH

* fix logs

* fix conflict
parent 02dedcbc
...@@ -152,7 +152,6 @@ export default function CurrencyInputPanel({ ...@@ -152,7 +152,6 @@ export default function CurrencyInputPanel({
value, value,
field, field,
onUserInput, onUserInput,
title,
onMax, onMax,
atMax, atMax,
error, error,
...@@ -164,7 +163,7 @@ export default function CurrencyInputPanel({ ...@@ -164,7 +163,7 @@ export default function CurrencyInputPanel({
disableTokenSelect = false, disableTokenSelect = false,
hideBalance = false, hideBalance = false,
isExchange = false, isExchange = false,
exchange = null, // used for double token logo pair = null, // used for double token logo
customBalance = null, // used for LP balances instead of token balance customBalance = null, // used for LP balances instead of token balance
hideInput = false, hideInput = false,
showSendWithSwap = false showSendWithSwap = false
...@@ -251,13 +250,13 @@ export default function CurrencyInputPanel({ ...@@ -251,13 +250,13 @@ export default function CurrencyInputPanel({
> >
<Aligner> <Aligner>
{isExchange ? ( {isExchange ? (
<DoubleLogo a0={exchange?.token0.address} a1={exchange?.token1.address} size={24} margin={true} /> <DoubleLogo a0={pair?.token0.address} a1={pair?.token1.address} size={24} margin={true} />
) : token?.address ? ( ) : token?.address ? (
<TokenLogo address={token?.address} size={'24px'} /> <TokenLogo address={token?.address} size={'24px'} />
) : null} ) : null}
{isExchange ? ( {isExchange ? (
<StyledTokenName> <StyledTokenName>
{exchange?.token0.symbol}:{exchange?.token1.symbol} {pair?.token0.symbol}:{pair?.token1.symbol}
</StyledTokenName> </StyledTokenName>
) : ( ) : (
<StyledTokenName>{(token && token.symbol) || t('selectToken')}</StyledTokenName> <StyledTokenName>{(token && token.symbol) || t('selectToken')}</StyledTokenName>
......
...@@ -3,7 +3,7 @@ import styled from 'styled-components' ...@@ -3,7 +3,7 @@ import styled from 'styled-components'
import { ethers } from 'ethers' import { ethers } from 'ethers'
import { withRouter } from 'react-router-dom' import { withRouter } from 'react-router-dom'
import { parseUnits, parseEther } from '@ethersproject/units' import { parseUnits, parseEther } from '@ethersproject/units'
import { WETH, TradeType, Route, Exchange, Trade, TokenAmount, JSBI, Percent } from '@uniswap/sdk' import { WETH, TradeType, Pair, Trade, TokenAmount, JSBI, Percent } from '@uniswap/sdk'
import TokenLogo from '../TokenLogo' import TokenLogo from '../TokenLogo'
import QuestionHelper from '../Question' import QuestionHelper from '../Question'
...@@ -21,9 +21,10 @@ import { AutoColumn, ColumnCenter } from '../../components/Column' ...@@ -21,9 +21,10 @@ import { AutoColumn, ColumnCenter } from '../../components/Column'
import { ButtonPrimary, ButtonError } from '../Button' import { ButtonPrimary, ButtonError } from '../Button'
import { RowBetween, RowFixed, AutoRow } from '../../components/Row' import { RowBetween, RowFixed, AutoRow } from '../../components/Row'
import { usePair } from '../../contexts/Pairs'
import { useToken } from '../../contexts/Tokens' import { useToken } from '../../contexts/Tokens'
import { usePopups } from '../../contexts/Application' import { usePopups } from '../../contexts/Application'
import { useExchange } from '../../contexts/Exchanges' import { useRoute } from '../../contexts/Routes'
import { useTransactionAdder } from '../../contexts/Transactions' import { useTransactionAdder } from '../../contexts/Transactions'
import { useAddressAllowance } from '../../contexts/Allowances' import { useAddressAllowance } from '../../contexts/Allowances'
import { useWeb3React, useTokenContract } from '../../hooks' import { useWeb3React, useTokenContract } from '../../hooks'
...@@ -244,9 +245,10 @@ function ExchangePage({ sendingInput = false, history }) { ...@@ -244,9 +245,10 @@ function ExchangePage({ sendingInput = false, history }) {
[Field.OUTPUT]: useToken(fieldData[Field.OUTPUT].address) [Field.OUTPUT]: useToken(fieldData[Field.OUTPUT].address)
} }
const exchange: Exchange = useExchange(tokens[Field.INPUT], tokens[Field.OUTPUT]) const pair: Pair = usePair(tokens[Field.INPUT], tokens[Field.OUTPUT])
const route: Route = !!exchange ? new Route([exchange], tokens[Field.INPUT]) : undefined const route = useRoute(tokens[Field.INPUT], tokens[Field.OUTPUT])
const emptyReserves: boolean = exchange && JSBI.equal(JSBI.BigInt(0), exchange.reserve0.raw) const noRoute: boolean = !route && !!tokens[Field.INPUT] && !!tokens[Field.OUTPUT]
const emptyReserves = pair && JSBI.equal(JSBI.BigInt(0), pair.reserve0.raw)
// modal and loading // modal and loading
const [showConfirm, setShowConfirm] = useState<boolean>(false) const [showConfirm, setShowConfirm] = useState<boolean>(false)
...@@ -272,6 +274,8 @@ function ExchangePage({ sendingInput = false, history }) { ...@@ -272,6 +274,8 @@ function ExchangePage({ sendingInput = false, history }) {
[Field.OUTPUT]: useAddressBalance(account, tokens[Field.OUTPUT]) [Field.OUTPUT]: useAddressBalance(account, tokens[Field.OUTPUT])
} }
// console.log(userBalances[Field.OUTPUT]?.raw.toString())
const parsedAmounts: { [field: number]: TokenAmount } = {} const parsedAmounts: { [field: number]: TokenAmount } = {}
if (typedValue !== '' && typedValue !== '.' && tokens[independentField]) { if (typedValue !== '' && typedValue !== '.' && tokens[independentField]) {
try { try {
...@@ -621,8 +625,9 @@ function ExchangePage({ sendingInput = false, history }) { ...@@ -621,8 +625,9 @@ function ExchangePage({ sendingInput = false, history }) {
if ( if (
parsedAmounts[Field.INPUT] && parsedAmounts[Field.INPUT] &&
exchange && pair &&
JSBI.greaterThan(parsedAmounts[Field.INPUT].raw, exchange.reserveOf(tokens[Field.INPUT]).raw) route &&
JSBI.greaterThan(parsedAmounts[Field.INPUT].raw, route.pairs[0].reserveOf(tokens[Field.INPUT]).raw)
) { ) {
setTradeError('Insufficient Liquidity') setTradeError('Insufficient Liquidity')
setIsValid(false) setIsValid(false)
...@@ -631,8 +636,12 @@ function ExchangePage({ sendingInput = false, history }) { ...@@ -631,8 +636,12 @@ function ExchangePage({ sendingInput = false, history }) {
if ( if (
!ignoreOutput && !ignoreOutput &&
parsedAmounts[Field.OUTPUT] && parsedAmounts[Field.OUTPUT] &&
exchange && pair &&
JSBI.greaterThan(parsedAmounts[Field.OUTPUT].raw, exchange.reserveOf(tokens[Field.OUTPUT]).raw) route &&
JSBI.greaterThan(
parsedAmounts[Field.OUTPUT].raw,
route.pairs[route.pairs.length - 1].reserveOf(tokens[Field.OUTPUT]).raw
)
) { ) {
setTradeError('Insufficient Liquidity') setTradeError('Insufficient Liquidity')
setIsValid(false) setIsValid(false)
...@@ -657,7 +666,7 @@ function ExchangePage({ sendingInput = false, history }) { ...@@ -657,7 +666,7 @@ function ExchangePage({ sendingInput = false, history }) {
setIsValid(false) setIsValid(false)
} }
}, [ }, [
exchange, pair,
ignoreOutput, ignoreOutput,
parsedAmounts, parsedAmounts,
recipient, recipient,
...@@ -667,7 +676,8 @@ function ExchangePage({ sendingInput = false, history }) { ...@@ -667,7 +676,8 @@ function ExchangePage({ sendingInput = false, history }) {
showInputUnlock, showInputUnlock,
showOutputUnlock, showOutputUnlock,
tokens, tokens,
userBalances userBalances,
route
]) ])
// warnings on slippage // warnings on slippage
...@@ -896,9 +906,8 @@ function ExchangePage({ sendingInput = false, history }) { ...@@ -896,9 +906,8 @@ function ExchangePage({ sendingInput = false, history }) {
atMax={atMaxAmountInput} atMax={atMaxAmountInput}
token={tokens[Field.INPUT]} token={tokens[Field.INPUT]}
onTokenSelection={address => _onTokenSelect(address)} onTokenSelection={address => _onTokenSelect(address)}
title={'Input'}
error={inputError} error={inputError}
exchange={exchange} pair={pair}
showUnlock={showInputUnlock} showUnlock={showInputUnlock}
hideBalance={true} hideBalance={true}
hideInput={true} hideInput={true}
...@@ -916,9 +925,8 @@ function ExchangePage({ sendingInput = false, history }) { ...@@ -916,9 +925,8 @@ function ExchangePage({ sendingInput = false, history }) {
value={formattedAmounts[Field.INPUT]} value={formattedAmounts[Field.INPUT]}
atMax={atMaxAmountInput} atMax={atMaxAmountInput}
token={tokens[Field.INPUT]} token={tokens[Field.INPUT]}
title={'Input'}
error={inputError} error={inputError}
exchange={exchange} pair={pair}
showUnlock={showInputUnlock} showUnlock={showInputUnlock}
onUserInput={onUserInput} onUserInput={onUserInput}
onMax={() => { onMax={() => {
...@@ -942,18 +950,17 @@ function ExchangePage({ sendingInput = false, history }) { ...@@ -942,18 +950,17 @@ function ExchangePage({ sendingInput = false, history }) {
atMax={atMaxAmountOutput} atMax={atMaxAmountOutput}
token={tokens[Field.OUTPUT]} token={tokens[Field.OUTPUT]}
onTokenSelection={address => onTokenSelection(Field.OUTPUT, address)} onTokenSelection={address => onTokenSelection(Field.OUTPUT, address)}
title={'Output'}
error={outputError} error={outputError}
exchange={exchange} pair={pair}
showUnlock={showOutputUnlock} showUnlock={showOutputUnlock}
/> />
{!emptyReserves && ( // hide price if new exchange {!noRoute && ( // hide price if new exchange
<RowBetween> <RowBetween>
<Text fontWeight={500} color="#565A69"> <Text fontWeight={500} color="#565A69">
Price Price
</Text> </Text>
<Text fontWeight={500} color="#565A69"> <Text fontWeight={500} color="#565A69">
{exchange {pair
? `1 ${tokens[Field.INPUT].symbol} = ${route?.midPrice.toSignificant(6)} ${ ? `1 ${tokens[Field.INPUT].symbol} = ${route?.midPrice.toSignificant(6)} ${
tokens[Field.OUTPUT].symbol tokens[Field.OUTPUT].symbol
}` }`
...@@ -989,7 +996,7 @@ function ExchangePage({ sendingInput = false, history }) { ...@@ -989,7 +996,7 @@ function ExchangePage({ sendingInput = false, history }) {
</AutoColumn> </AutoColumn>
)} )}
{emptyReserves ? ( {noRoute ? (
<RowBetween style={{ margin: '10px 0' }}> <RowBetween style={{ margin: '10px 0' }}>
<TYPE.main>No exchange for this pair.</TYPE.main> <TYPE.main>No exchange for this pair.</TYPE.main>
<Link <Link
......
import React, { useState } from 'react' import React, { useState } from 'react'
import { withRouter } from 'react-router-dom' import { withRouter } from 'react-router-dom'
import { TokenAmount, JSBI, Token, Exchange } from '@uniswap/sdk' import { TokenAmount, JSBI, Token, Pair } from '@uniswap/sdk'
import Row from '../Row' import Row from '../Row'
import TokenLogo from '../TokenLogo' import TokenLogo from '../TokenLogo'
...@@ -14,9 +14,9 @@ import { LightCard } from '../Card' ...@@ -14,9 +14,9 @@ import { LightCard } from '../Card'
import { AutoColumn, ColumnCenter } from '../Column' import { AutoColumn, ColumnCenter } from '../Column'
import { ButtonPrimary, ButtonDropwdown, ButtonDropwdownLight } from '../Button' import { ButtonPrimary, ButtonDropwdown, ButtonDropwdownLight } from '../Button'
import { usePair } from '../../contexts/Pairs'
import { useToken } from '../../contexts/Tokens' import { useToken } from '../../contexts/Tokens'
import { usePopups } from '../../contexts/Application' import { usePopups } from '../../contexts/Application'
import { useExchange } from '../../contexts/Exchanges'
import { useWeb3React } from '@web3-react/core' import { useWeb3React } from '@web3-react/core'
import { useAddressBalance } from '../../contexts/Balances' import { useAddressBalance } from '../../contexts/Balances'
...@@ -38,10 +38,10 @@ function PoolFinder({ history }) { ...@@ -38,10 +38,10 @@ function PoolFinder({ history }) {
const token0: Token = useToken(token0Address) const token0: Token = useToken(token0Address)
const token1: Token = useToken(token1Address) const token1: Token = useToken(token1Address)
const exchange: Exchange = useExchange(token0, token1) const pair: Pair = usePair(token0, token1)
const position: TokenAmount = useAddressBalance(account, exchange?.liquidityToken) const position: TokenAmount = useAddressBalance(account, pair?.liquidityToken)
const newExchange: boolean = exchange && JSBI.equal(exchange.reserve0.raw, JSBI.BigInt(0)) const newPair: boolean = pair && JSBI.equal(pair.reserve0.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))
function endSearch() { function endSearch() {
...@@ -120,7 +120,7 @@ function PoolFinder({ history }) { ...@@ -120,7 +120,7 @@ function PoolFinder({ history }) {
{position ? ( {position ? (
!JSBI.equal(position.raw, JSBI.BigInt(0)) ? ( !JSBI.equal(position.raw, JSBI.BigInt(0)) ? (
<PositionCard <PositionCard
exchangeAddress={exchange?.liquidityToken.address} pairAddress={pair?.liquidityToken.address}
token0={token0} token0={token0}
token1={token1} token1={token1}
minimal={true} minimal={true}
...@@ -140,7 +140,7 @@ function PoolFinder({ history }) { ...@@ -140,7 +140,7 @@ function PoolFinder({ history }) {
</AutoColumn> </AutoColumn>
</LightCard> </LightCard>
) )
) : newExchange ? ( ) : newPair ? (
<LightCard padding="45px"> <LightCard padding="45px">
<AutoColumn gap="8px" justify="center"> <AutoColumn gap="8px" justify="center">
<Text color="">No exchange found.</Text> <Text color="">No exchange found.</Text>
......
import React from 'react' import React from 'react'
import styled from 'styled-components' import styled from 'styled-components'
import { withRouter } from 'react-router-dom' import { withRouter } from 'react-router-dom'
import { Percent, Exchange } from '@uniswap/sdk' import { Percent, Pair } from '@uniswap/sdk'
import { useWeb3React } from '@web3-react/core' import { useWeb3React } from '@web3-react/core'
import { useAllBalances } from '../../contexts/Balances' import { useAllBalances } from '../../contexts/Balances'
import { useTotalSupply } from '../../contexts/Exchanges' import { useTotalSupply } from '../../contexts/Pairs'
import Card from '../Card' import Card from '../Card'
import TokenLogo from '../TokenLogo' import TokenLogo from '../TokenLogo'
...@@ -20,17 +20,17 @@ const FixedHeightRow = styled(RowBetween)` ...@@ -20,17 +20,17 @@ const FixedHeightRow = styled(RowBetween)`
height: 24px; height: 24px;
` `
function PositionCard({ exchangeAddress, token0, token1, history, minimal = false, ...rest }) { function PositionCard({ pairAddress, token0, token1, history, minimal = false, ...rest }) {
const { account } = useWeb3React() const { account } = useWeb3React()
const allBalances = useAllBalances() const allBalances = useAllBalances()
const tokenAmount0 = allBalances?.[exchangeAddress]?.[token0.address] const tokenAmount0 = allBalances?.[pairAddress]?.[token0.address]
const tokenAmount1 = allBalances?.[exchangeAddress]?.[token1.address] const tokenAmount1 = allBalances?.[pairAddress]?.[token1.address]
const exchange = tokenAmount0 && tokenAmount1 && new Exchange(tokenAmount0, tokenAmount1) const pair = tokenAmount0 && tokenAmount1 && new Pair(tokenAmount0, tokenAmount1)
const userPoolBalance = allBalances?.[account]?.[exchangeAddress] const userPoolBalance = allBalances?.[account]?.[pairAddress]
const totalPoolTokens = useTotalSupply(exchange) const totalPoolTokens = useTotalSupply(pair)
const poolTokenPercentage = const poolTokenPercentage =
!!userPoolBalance && !!totalPoolTokens ? new Percent(userPoolBalance.raw, totalPoolTokens.raw) : undefined !!userPoolBalance && !!totalPoolTokens ? new Percent(userPoolBalance.raw, totalPoolTokens.raw) : undefined
...@@ -39,12 +39,12 @@ function PositionCard({ exchangeAddress, token0, token1, history, minimal = fals ...@@ -39,12 +39,12 @@ function PositionCard({ exchangeAddress, token0, token1, history, minimal = fals
token0 && token0 &&
totalPoolTokens && totalPoolTokens &&
userPoolBalance && userPoolBalance &&
exchange.getLiquidityValue(token0, totalPoolTokens, userPoolBalance, false) pair.getLiquidityValue(token0, totalPoolTokens, userPoolBalance, false)
const token1Deposited = const token1Deposited =
token1 && token1 &&
totalPoolTokens && totalPoolTokens &&
userPoolBalance && userPoolBalance &&
exchange.getLiquidityValue(token1, totalPoolTokens, userPoolBalance, false) pair.getLiquidityValue(token1, totalPoolTokens, userPoolBalance, false)
function DynamicCard({ children, ...rest }) { function DynamicCard({ children, ...rest }) {
if (!minimal) { if (!minimal) {
......
...@@ -21,10 +21,10 @@ import { ColumnCenter } from '../../components/Column' ...@@ -21,10 +21,10 @@ import { ColumnCenter } from '../../components/Column'
import { RowBetween, RowFixed } from '../Row' import { RowBetween, RowFixed } from '../Row'
import { isAddress } from '../../utils' import { isAddress } from '../../utils'
import { useAllPairs } from '../../contexts/Pairs'
import { useWeb3React } from '../../hooks' import { useWeb3React } from '../../hooks'
import { useAllBalances } from '../../contexts/Balances' import { useAllBalances } from '../../contexts/Balances'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useAllExchanges } from '../../contexts/Exchanges'
import { useToken, useAllTokens, INITIAL_TOKENS_CONTEXT } from '../../contexts/Tokens' import { useToken, useAllTokens, INITIAL_TOKENS_CONTEXT } from '../../contexts/Tokens'
const TokenModalInfo = styled.div` const TokenModalInfo = styled.div`
...@@ -131,7 +131,7 @@ function SearchModal({ ...@@ -131,7 +131,7 @@ function SearchModal({
const { account, chainId } = useWeb3React() const { account, chainId } = useWeb3React()
const allTokens = useAllTokens() const allTokens = useAllTokens()
const allExchanges = useAllExchanges() const allPairs = useAllPairs()
const allBalances = useAllBalances() const allBalances = useAllBalances()
const [searchQuery, setSearchQuery] = useState('') const [searchQuery, setSearchQuery] = useState('')
...@@ -230,7 +230,7 @@ function SearchModal({ ...@@ -230,7 +230,7 @@ function SearchModal({
const escapeStringRegexp = string => string const escapeStringRegexp = string => string
const sortedPairList = useMemo(() => { const sortedPairList = useMemo(() => {
return Object.keys(allExchanges).sort((a, b) => { return Object.keys(allPairs).sort((a, b) => {
// sort by balance // sort by balance
const balanceA = allBalances?.[account]?.[a] const balanceA = allBalances?.[account]?.[a]
const balanceB = allBalances?.[account]?.[b] const balanceB = allBalances?.[account]?.[b]
...@@ -248,17 +248,17 @@ function SearchModal({ ...@@ -248,17 +248,17 @@ function SearchModal({
return 0 return 0
} }
}) })
}, [account, allBalances, allExchanges, sortDirection]) }, [account, allBalances, allPairs, sortDirection])
const filteredPairList = useMemo(() => { const filteredPairList = useMemo(() => {
const isAddress = searchQuery.slice(0, 2) === '0x' const isAddress = searchQuery.slice(0, 2) === '0x'
return sortedPairList.filter(exchangeAddress => { return sortedPairList.filter(pairAddress => {
const exchange = allExchanges[exchangeAddress] const pair = allPairs[pairAddress]
if (searchQuery === '') { if (searchQuery === '') {
return true return true
} }
const token0 = allTokens[exchange.token0] const token0 = allTokens[pair.token0]
const token1 = allTokens[exchange.token1] const token1 = allTokens[pair.token1]
const regexMatches = Object.keys(token0).map(field => { const regexMatches = Object.keys(token0).map(field => {
if ( if (
(field === 'address' && isAddress) || (field === 'address' && isAddress) ||
...@@ -275,7 +275,7 @@ function SearchModal({ ...@@ -275,7 +275,7 @@ function SearchModal({
return regexMatches.some(m => m) return regexMatches.some(m => m)
}) })
}, [allExchanges, allTokens, searchQuery, sortedPairList]) }, [allPairs, allTokens, searchQuery, sortedPairList])
// update the amount shown as filtered list changes // update the amount shown as filtered list changes
useEffect(() => { useEffect(() => {
...@@ -296,10 +296,10 @@ function SearchModal({ ...@@ -296,10 +296,10 @@ function SearchModal({
return ( return (
filteredPairList && filteredPairList &&
filteredPairList.map((exchangeAddress, i) => { filteredPairList.map((pairAddress, i) => {
const token0 = allTokens[allExchanges[exchangeAddress].token0] const token0 = allTokens[allPairs[pairAddress].token0]
const token1 = allTokens[allExchanges[exchangeAddress].token1] const token1 = allTokens[allPairs[pairAddress].token1]
const balance = allBalances?.[account]?.[exchangeAddress]?.toSignificant(6) const balance = allBalances?.[account]?.[pairAddress]?.toSignificant(6)
return ( return (
<MenuItem <MenuItem
key={i} key={i}
......
import React, { createContext, useContext, useReducer, useRef, useMemo, useCallback, useEffect, ReactNode } from 'react' import React, { createContext, useContext, useReducer, useRef, useMemo, useCallback, useEffect, ReactNode } from 'react'
import { TokenAmount, Token, JSBI, WETH } from '@uniswap/sdk' import { TokenAmount, Token, JSBI, WETH } from '@uniswap/sdk'
import { useAllPairs } from './Pairs'
import { useAllTokens } from './Tokens' import { useAllTokens } from './Tokens'
import { useBlockNumber } from './Application' import { useBlockNumber } from './Application'
import { useAllExchanges } from './Exchanges'
import { useWeb3React, useDebounce } from '../hooks' import { useWeb3React, useDebounce } from '../hooks'
import { getEtherBalance, getTokenBalance, isAddress } from '../utils' import { getEtherBalance, getTokenBalance, isAddress } from '../utils'
...@@ -120,20 +120,20 @@ function reducer(state: BalancesState, { type, payload }: { type: Action; payloa ...@@ -120,20 +120,20 @@ function reducer(state: BalancesState, { type, payload }: { type: Action; payloa
} }
} }
case Action.BATCH_UPDATE_EXCHANGES: { case Action.BATCH_UPDATE_EXCHANGES: {
const { chainId, exchangeAddresses, tokenAddresses, values, blockNumber } = payload const { chainId, pairAddresses, tokenAddresses, values, blockNumber } = payload
return { return {
...state, ...state,
[chainId]: { [chainId]: {
...state?.[chainId], ...state?.[chainId],
...exchangeAddresses.reduce((accumulator: any, exchangeAddress: string, i: number) => { ...pairAddresses.reduce((accumulator: any, pairAddress: string, i: number) => {
const tokenAddress = tokenAddresses[i] const tokenAddress = tokenAddresses[i]
const value = values[i] const value = values[i]
accumulator[exchangeAddress] = { accumulator[pairAddress] = {
...state?.[chainId]?.[exchangeAddress], ...state?.[chainId]?.[pairAddress],
...accumulator?.[exchangeAddress], ...accumulator?.[pairAddress],
[tokenAddress]: { [tokenAddress]: {
...state?.[chainId]?.[exchangeAddress]?.[tokenAddress], ...state?.[chainId]?.[pairAddress]?.[tokenAddress],
value, value,
blockNumber blockNumber
} }
...@@ -174,10 +174,10 @@ export default function Provider({ children }: { children: ReactNode }) { ...@@ -174,10 +174,10 @@ export default function Provider({ children }: { children: ReactNode }) {
dispatch({ type: Action.BATCH_UPDATE_ACCOUNT, payload: { chainId, address, tokenAddresses, values, blockNumber } }) dispatch({ type: Action.BATCH_UPDATE_ACCOUNT, payload: { chainId, address, tokenAddresses, values, blockNumber } })
}, []) }, [])
const batchUpdateExchanges = useCallback((chainId, exchangeAddresses, tokenAddresses, values, blockNumber) => { const batchUpdateExchanges = useCallback((chainId, pairAddresses, tokenAddresses, values, blockNumber) => {
dispatch({ dispatch({
type: Action.BATCH_UPDATE_EXCHANGES, type: Action.BATCH_UPDATE_EXCHANGES,
payload: { chainId, exchangeAddresses, tokenAddresses, values, blockNumber } payload: { chainId, pairAddresses, tokenAddresses, values, blockNumber }
}) })
}, []) }, [])
...@@ -325,26 +325,25 @@ export function Updater() { ...@@ -325,26 +325,25 @@ export function Updater() {
}, [chainId, account, blockNumber, allTokens, fetchBalance, batchUpdateAccount]) }, [chainId, account, blockNumber, allTokens, fetchBalance, batchUpdateAccount])
// ensure token balances for all exchanges // ensure token balances for all exchanges
const allExchanges = useAllExchanges() const allPairs = useAllPairs()
useEffect(() => { useEffect(() => {
if (typeof chainId === 'number' && typeof blockNumber === 'number') { if (typeof chainId === 'number' && typeof blockNumber === 'number') {
Promise.all( Promise.all(
Object.keys(allExchanges) Object.keys(allPairs)
.filter(exchangeAddress => { .filter(pairAddress => {
const token0 = allExchanges[exchangeAddress].token0 const token0 = allPairs[pairAddress].token0
const token1 = allExchanges[exchangeAddress].token1 const token1 = allPairs[pairAddress].token1
const hasValueToken0 = !!stateRef.current?.[chainId]?.[exchangeAddress]?.[token0]?.value const hasValueToken0 = !!stateRef.current?.[chainId]?.[pairAddress]?.[token0]?.value
const hasValueToken1 = !!stateRef.current?.[chainId]?.[exchangeAddress]?.[token1]?.value const hasValueToken1 = !!stateRef.current?.[chainId]?.[pairAddress]?.[token1]?.value
const cachedFetchedAsOfToken0 = fetchedAsOfCache.current?.[chainId]?.[exchangeAddress]?.token0 const cachedFetchedAsOfToken0 = fetchedAsOfCache.current?.[chainId]?.[pairAddress]?.token0
const cachedFetchedAsOfToken1 = fetchedAsOfCache.current?.[chainId]?.[exchangeAddress]?.token1 const cachedFetchedAsOfToken1 = fetchedAsOfCache.current?.[chainId]?.[pairAddress]?.token1
const fetchedAsOfToken0 = const fetchedAsOfToken0 =
stateRef.current?.[chainId]?.[exchangeAddress]?.[token0]?.blockNumber ?? cachedFetchedAsOfToken0 stateRef.current?.[chainId]?.[pairAddress]?.[token0]?.blockNumber ?? cachedFetchedAsOfToken0
const fetchedAsOfToken1 = const fetchedAsOfToken1 =
stateRef.current?.[chainId]?.[exchangeAddress]?.[token1]?.blockNumber ?? cachedFetchedAsOfToken1 stateRef.current?.[chainId]?.[pairAddress]?.[token1]?.blockNumber ?? cachedFetchedAsOfToken1
// if there's no values, and they're not being fetched, we need to fetch! // if there's no values, and they're not being fetched, we need to fetch!
if ( if (
...@@ -367,37 +366,37 @@ export function Updater() { ...@@ -367,37 +366,37 @@ export function Updater() {
return false return false
} }
}) })
.map(async exchangeAddress => { .map(async pairAddress => {
const token0 = allExchanges[exchangeAddress].token0 const token0 = allPairs[pairAddress].token0
const token1 = allExchanges[exchangeAddress].token1 const token1 = allPairs[pairAddress].token1
fetchedAsOfCache.current = { fetchedAsOfCache.current = {
...fetchedAsOfCache.current, ...fetchedAsOfCache.current,
[chainId]: { [chainId]: {
...fetchedAsOfCache.current?.[chainId], ...fetchedAsOfCache.current?.[chainId],
[exchangeAddress]: { [pairAddress]: {
...fetchedAsOfCache.current?.[chainId]?.[exchangeAddress], ...fetchedAsOfCache.current?.[chainId]?.[pairAddress],
[token0]: blockNumber, [token0]: blockNumber,
[token1]: blockNumber [token1]: blockNumber
} }
} }
} }
return Promise.all([ return Promise.all([
fetchBalance(exchangeAddress, token0), fetchBalance(pairAddress, token0),
fetchBalance(exchangeAddress, token1) fetchBalance(pairAddress, token1)
]).then(([valueToken0, valueToken1]) => ({ exchangeAddress, token0, token1, valueToken0, valueToken1 })) ]).then(([valueToken0, valueToken1]) => ({ pairAddress, token0, token1, valueToken0, valueToken1 }))
}) })
).then(results => { ).then(results => {
batchUpdateExchanges( batchUpdateExchanges(
chainId, chainId,
results.flatMap(result => [result.exchangeAddress, result.exchangeAddress]), results.flatMap(result => [result.pairAddress, result.pairAddress]),
results.flatMap(result => [result.token0, result.token1]), results.flatMap(result => [result.token0, result.token1]),
results.flatMap(result => [result.valueToken0, result.valueToken1]), results.flatMap(result => [result.valueToken0, result.valueToken1]),
blockNumber blockNumber
) )
}) })
} }
}, [chainId, account, blockNumber, allExchanges, fetchBalance, batchUpdateExchanges]) }, [chainId, account, blockNumber, allPairs, fetchBalance, batchUpdateExchanges])
return null return null
} }
...@@ -472,17 +471,17 @@ export function useAddressBalance(address: string, token: Token): TokenAmount | ...@@ -472,17 +471,17 @@ export function useAddressBalance(address: string, token: Token): TokenAmount |
export function useAccountLPBalances(account: string) { export function useAccountLPBalances(account: string) {
const { chainId } = useWeb3React() const { chainId } = useWeb3React()
const [, { startListening, stopListening }] = useBalancesContext() const [, { startListening, stopListening }] = useBalancesContext()
const allExchanges = useAllExchanges() const allPairs = useAllPairs()
useEffect(() => { useEffect(() => {
Object.keys(allExchanges).map(exchangeAddress => { Object.keys(allPairs).map(pairAddress => {
if (typeof chainId === 'number' && isAddress(account)) { if (typeof chainId === 'number' && isAddress(account)) {
startListening(chainId, account, exchangeAddress) startListening(chainId, account, pairAddress)
return () => { return () => {
stopListening(chainId, account, exchangeAddress) stopListening(chainId, account, pairAddress)
} }
} }
return true return true
}) })
}, [account, allExchanges, chainId, startListening, stopListening]) }, [account, allPairs, chainId, startListening, stopListening])
} }
import React, { createContext, useContext, useReducer, useMemo, useCallback, useEffect, useState } from 'react' import React, { createContext, useContext, useReducer, useMemo, useCallback, useEffect, useState } from 'react'
import { useAddressBalance } from './Balances' import { useAddressBalance } from './Balances'
import { useWeb3React, useExchangeContract } from '../hooks' import { useWeb3React, usePairContract } from '../hooks'
import { INITIAL_TOKENS_CONTEXT } from './Tokens' import { INITIAL_TOKENS_CONTEXT } from './Tokens'
import { ChainId, WETH, Token, TokenAmount, Exchange, JSBI } from '@uniswap/sdk' import { ChainId, WETH, Token, TokenAmount, Pair, JSBI } from '@uniswap/sdk'
const UPDATE = 'UPDATE' const UPDATE = 'UPDATE'
const ALL_EXCHANGES: [Token, Token][] = [ const ALL_PAIRS: [Token, Token][] = [
[ [
INITIAL_TOKENS_CONTEXT[ChainId.RINKEBY][WETH[ChainId.RINKEBY].address], INITIAL_TOKENS_CONTEXT[ChainId.RINKEBY][WETH[ChainId.RINKEBY].address],
INITIAL_TOKENS_CONTEXT[ChainId.RINKEBY]['0xc7AD46e0b8a400Bb3C915120d284AafbA8fc4735'] //dai INITIAL_TOKENS_CONTEXT[ChainId.RINKEBY]['0xc7AD46e0b8a400Bb3C915120d284AafbA8fc4735'] //dai
...@@ -17,30 +17,29 @@ const ALL_EXCHANGES: [Token, Token][] = [ ...@@ -17,30 +17,29 @@ const ALL_EXCHANGES: [Token, Token][] = [
] ]
] ]
const EXCHANGE_MAP: { const PAIR_MAP: {
[chainId: number]: { [token0Address: string]: { [token1Address: string]: string } } [chainId: number]: { [token0Address: string]: { [token1Address: string]: string } }
} = ALL_EXCHANGES.reduce((exchangeMap, [tokenA, tokenB]) => { } = ALL_PAIRS.reduce((pairMap, [tokenA, tokenB]) => {
const tokens: [Token, Token] = tokenA?.sortsBefore(tokenB) ? [tokenA, tokenB] : [tokenB, tokenA] const tokens: [Token, Token] = tokenA?.sortsBefore(tokenB) ? [tokenA, tokenB] : [tokenB, tokenA]
// ensure exchanges are unique // ensure exchanges are unique
if (exchangeMap?.[tokens[0].chainId]?.[tokens[0].address]?.[tokens[1].address] !== undefined) if (pairMap?.[tokens[0].chainId]?.[tokens[0].address]?.[tokens[1].address] !== undefined)
throw Error(`Duplicate exchange: ${tokenA} ${tokenB}`) throw Error(`Duplicate exchange: ${tokenA} ${tokenB}`)
return { return {
...exchangeMap, ...pairMap,
[tokens[0].chainId]: { [tokens[0].chainId]: {
...exchangeMap?.[tokens[0].chainId], ...pairMap?.[tokens[0].chainId],
[tokens[0].address]: { [tokens[0].address]: {
...exchangeMap?.[tokens[0].chainId]?.[tokens[0].address], ...pairMap?.[tokens[0].chainId]?.[tokens[0].address],
[tokens[1].address]: Exchange.getAddress(...tokens) [tokens[1].address]: Pair.getAddress(...tokens)
} }
} }
} }
}, {}) }, {})
const ExchangeContext = createContext([]) const PairContext = createContext([])
function useExchangesContext() { function usePairContext() {
return useContext(ExchangeContext) return useContext(PairContext)
} }
function reducer(state, { type, payload }) { function reducer(state, { type, payload }) {
...@@ -56,7 +55,7 @@ function reducer(state, { type, payload }) { ...@@ -56,7 +55,7 @@ function reducer(state, { type, payload }) {
...state?.[tokensSorted[0].chainId], ...state?.[tokensSorted[0].chainId],
[tokensSorted[0].address]: { [tokensSorted[0].address]: {
...state?.[tokensSorted[0].chainId]?.[tokensSorted[0].address], ...state?.[tokensSorted[0].chainId]?.[tokensSorted[0].address],
[tokensSorted[1].address]: Exchange.getAddress(tokensSorted[0], tokensSorted[1]) [tokensSorted[1].address]: Pair.getAddress(tokensSorted[0], tokensSorted[1])
} }
} }
} }
...@@ -68,22 +67,20 @@ function reducer(state, { type, payload }) { ...@@ -68,22 +67,20 @@ function reducer(state, { type, payload }) {
} }
export default function Provider({ children }) { export default function Provider({ children }) {
const [state, dispatch] = useReducer(reducer, EXCHANGE_MAP) const [state, dispatch] = useReducer(reducer, PAIR_MAP)
const update = useCallback((chainId, tokens) => { const update = useCallback((chainId, tokens) => {
dispatch({ type: UPDATE, payload: { chainId, tokens } }) dispatch({ type: UPDATE, payload: { chainId, tokens } })
}, []) }, [])
return ( return (
<ExchangeContext.Provider value={useMemo(() => [state, { update }], [state, update])}> <PairContext.Provider value={useMemo(() => [state, { update }], [state, update])}>{children}</PairContext.Provider>
{children}
</ExchangeContext.Provider>
) )
} }
export function useExchangeAddress(tokenA?: Token, tokenB?: Token): string | undefined { export function usePairAddress(tokenA?: Token, tokenB?: Token): string | undefined {
const { chainId } = useWeb3React() const { chainId } = useWeb3React()
const [state, { update }] = useExchangesContext() const [state, { update }] = usePairContext()
const tokens: [Token, Token] = tokenA && tokenB && tokenA.sortsBefore(tokenB) ? [tokenA, tokenB] : [tokenB, tokenA] const tokens: [Token, Token] = tokenA && tokenB && tokenA.sortsBefore(tokenB) ? [tokenA, tokenB] : [tokenB, tokenA]
...@@ -91,79 +88,81 @@ export function useExchangeAddress(tokenA?: Token, tokenB?: Token): string | und ...@@ -91,79 +88,81 @@ export function useExchangeAddress(tokenA?: Token, tokenB?: Token): string | und
useEffect(() => { useEffect(() => {
if (address === undefined && tokenA && tokenB) { if (address === undefined && tokenA && tokenB) {
const exchangeAddress = Exchange.getAddress(...tokens) const pairAddress = Pair.getAddress(...tokens)
exchangeAddress && update(chainId, tokens) pairAddress && update(chainId, tokens)
} }
}, [chainId, address, tokenA, tokenB, tokens, update]) }, [chainId, address, tokenA, tokenB, tokens, update])
return address return address
} }
export function useExchange(tokenA?: Token, tokenB?: Token): Exchange | undefined { export function usePair(tokenA?: Token, tokenB?: Token): Pair | undefined {
const address = useExchangeAddress(tokenA, tokenB) const address = usePairAddress(tokenA, tokenB)
const tokenAmountA = useAddressBalance(address, tokenA) const tokenAmountA = useAddressBalance(address, tokenA)
const tokenAmountB = useAddressBalance(address, tokenB) const tokenAmountB = useAddressBalance(address, tokenB)
const pair = tokenAmountA && tokenAmountB && new Pair(tokenAmountA, tokenAmountB)
const exchange = tokenAmountA && tokenAmountB && new Exchange(tokenAmountA, tokenAmountB) // return pair
return exchange return useMemo(() => {
return pair
}, [pair])
} }
export function useAllExchangesRaw() { export function useAllPairsRaw() {
const { chainId } = useWeb3React() const { chainId } = useWeb3React()
const [state] = useExchangesContext() const [state] = usePairContext()
const allExchangeDetails = state?.[chainId] const allExchangeDetails = state?.[chainId]
return allExchangeDetails return allExchangeDetails
} }
export function useAllExchanges() { export function useAllPairs() {
const { chainId } = useWeb3React() const { chainId } = useWeb3React()
const [state] = useExchangesContext() const [state] = usePairContext()
const allExchangeDetails = state?.[chainId] const allPairDetails = state?.[chainId]
const allExchanges = useMemo(() => { const allPairs = useMemo(() => {
if (!allExchangeDetails) { if (!allPairDetails) {
return {} return {}
} }
const formattedExchanges = {} const formattedExchanges = {}
Object.keys(allExchangeDetails).map(token0Address => { Object.keys(allPairDetails).map(token0Address => {
return Object.keys(allExchangeDetails[token0Address]).map(token1Address => { return Object.keys(allPairDetails[token0Address]).map(token1Address => {
const exchangeAddress = allExchangeDetails[token0Address][token1Address] const pairAddress = allPairDetails[token0Address][token1Address]
return (formattedExchanges[exchangeAddress] = { return (formattedExchanges[pairAddress] = {
token0: token0Address, token0: token0Address,
token1: token1Address token1: token1Address
}) })
}) })
}) })
return formattedExchanges return formattedExchanges
}, [allExchangeDetails]) }, [allPairDetails])
return useMemo(() => { return useMemo(() => {
return allExchanges || {} return allPairs || {}
}, [allExchanges]) }, [allPairs])
} }
export function useTotalSupply(exchange: Exchange) { export function useTotalSupply(pair: Pair) {
const { library } = useWeb3React() const { library } = useWeb3React()
const [totalPoolTokens, setTotalPoolTokens] = useState<TokenAmount>() const [totalPoolTokens, setTotalPoolTokens] = useState<TokenAmount>()
const exchangeContract = useExchangeContract(exchange?.liquidityToken.address) const pairContract = usePairContract(pair?.liquidityToken.address)
const fetchPoolTokens = useCallback(async () => { const fetchPoolTokens = useCallback(async () => {
!!exchangeContract && !!pairContract &&
exchangeContract pairContract
.deployed() .deployed()
.then(() => { .then(() => {
if (exchangeContract) { if (pairContract) {
exchangeContract.totalSupply().then(totalSupply => { pairContract.totalSupply().then(totalSupply => {
if (totalSupply !== undefined && exchange?.liquidityToken?.decimals) { if (totalSupply !== undefined && pair?.liquidityToken?.decimals) {
const supplyFormatted = JSBI.BigInt(totalSupply) const supplyFormatted = JSBI.BigInt(totalSupply)
const tokenSupplyFormatted = new TokenAmount(exchange?.liquidityToken, supplyFormatted) const tokenSupplyFormatted = new TokenAmount(pair?.liquidityToken, supplyFormatted)
setTotalPoolTokens(tokenSupplyFormatted) setTotalPoolTokens(tokenSupplyFormatted)
} }
}) })
...@@ -175,7 +174,7 @@ export function useTotalSupply(exchange: Exchange) { ...@@ -175,7 +174,7 @@ export function useTotalSupply(exchange: Exchange) {
* fix this * fix this
*/ */
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [exchangeContract]) }, [pairContract])
// on the block make sure we're updated // on the block make sure we're updated
useEffect(() => { useEffect(() => {
......
import React, { createContext, useContext, useReducer, useMemo, useCallback, useEffect } from 'react'
import { WETH, Token, Route, JSBI } from '@uniswap/sdk'
import { useWeb3React } from '../hooks'
import { usePair } from '../contexts/Pairs'
const UPDATE = 'UPDATE'
interface RouteState {
[chainId: number]: {
[tokenAddress: string]: {
[tokenAddress: string]: {
route: Route
}
}
}
}
const RouteContext = createContext<[RouteState, { [k: string]: (...args: any) => void }]>([{}, {}])
function useRouteContext() {
return useContext(RouteContext)
}
function reducer(state: RouteState, { type, payload }) {
switch (type) {
case UPDATE: {
const { tokens, route, chainId } = payload
return {
...state,
[chainId]: {
...state[chainId],
[tokens[0]]: {
...state[tokens[0]],
[tokens[1]]: {
route
}
}
}
}
}
default: {
throw Error(`Unexpected action type in ExchangesContext reducer: '${type}'.`)
}
}
}
export default function Provider({ children }) {
const [state, dispatch] = useReducer(reducer, {})
const update = useCallback((tokens, route, chainId) => {
dispatch({ type: UPDATE, payload: { tokens, route, chainId } })
}, [])
return (
<RouteContext.Provider value={useMemo(() => [state, { update }], [state, update])}>
{children}
</RouteContext.Provider>
)
}
/**
* @param tokenA input to token to be sold
* @param tokenB output token to be bought
*
* This hook finds either a direct pair between tokenA and tokenB or,
* a one-hop route that goes through token<->WETH pairs
*
* if neither exists returns null
*/
export function useRoute(tokenA: Token, tokenB: Token) {
const [state, { update }] = useRouteContext()
const { chainId } = useWeb3React()
let route: Route = state?.[chainId]?.[tokenA?.address]?.[tokenB?.address]?.route
// check for direct pair between tokens
const defaultPair = usePair(tokenA, tokenB)
// get token<->WETH pairs
const aToETH = usePair(tokenA && !tokenA.equals(WETH[chainId]) ? tokenA : null, WETH[chainId])
const bToETH = usePair(tokenB && !tokenB.equals(WETH[chainId]) ? tokenB : null, WETH[chainId])
// needs to route through WETH
const requiresHop =
defaultPair &&
JSBI.equal(defaultPair.reserve0.raw, JSBI.BigInt(0)) &&
JSBI.equal(defaultPair.reserve1.raw, JSBI.BigInt(0))
useEffect(() => {
if (!route && tokenA && tokenB) {
if (!requiresHop && defaultPair) {
update([tokenA.address, tokenB.address], new Route([defaultPair], tokenA), chainId)
}
if (
requiresHop &&
aToETH &&
bToETH &&
// check there is liquidity in both pairs, possibly to reference empty pair
JSBI.notEqual(JSBI.BigInt(0), aToETH.reserve0.raw) &&
JSBI.notEqual(JSBI.BigInt(0), bToETH.reserve0.raw)
) {
const routeThroughETH = new Route([aToETH, bToETH], tokenA)
update([tokenA.address, tokenB.address], routeThroughETH, chainId)
}
}
/**
* @todo
* same infinite render bug here when including
* any token or pair instance as dependency (bug also in exchanegs and balances)
*/
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [route, requiresHop, update, chainId])
return useMemo(() => route, [route])
}
...@@ -10,6 +10,7 @@ export const ALL_TOKENS = [ ...@@ -10,6 +10,7 @@ export const ALL_TOKENS = [
WETH[ChainId.RINKEBY], WETH[ChainId.RINKEBY],
new Token(ChainId.RINKEBY, '0xc7AD46e0b8a400Bb3C915120d284AafbA8fc4735', 18, 'DAI', 'Dai Stablecoin'), new Token(ChainId.RINKEBY, '0xc7AD46e0b8a400Bb3C915120d284AafbA8fc4735', 18, 'DAI', 'Dai Stablecoin'),
new Token(ChainId.RINKEBY, '0x8ab15C890E5C03B5F240f2D146e3DF54bEf3Df44', 18, 'IANV2', 'IAn V2 /Coin'), new Token(ChainId.RINKEBY, '0x8ab15C890E5C03B5F240f2D146e3DF54bEf3Df44', 18, 'IANV2', 'IAn V2 /Coin'),
new Token(ChainId.RINKEBY, '0xF9bA5210F91D0474bd1e1DcDAeC4C58E359AaD85', 18, 'MKR', 'Maker'),
//Kovan Tokens //Kovan Tokens
WETH[ChainId.KOVAN], WETH[ChainId.KOVAN],
......
...@@ -210,16 +210,16 @@ export function useFactoryContract(withSignerIfPossible = true) { ...@@ -210,16 +210,16 @@ export function useFactoryContract(withSignerIfPossible = true) {
}, [chainId, library, withSignerIfPossible, account]) }, [chainId, library, withSignerIfPossible, account])
} }
export function useExchangeContract(exchangeAddress, withSignerIfPossible = true) { export function usePairContract(pairAddress, withSignerIfPossible = true) {
const { library, account } = useWeb3React() const { library, account } = useWeb3React()
return useMemo(() => { return useMemo(() => {
try { try {
return getExchangeContract(exchangeAddress, library, withSignerIfPossible ? account : undefined) return getExchangeContract(pairAddress, library, withSignerIfPossible ? account : undefined)
} catch { } catch {
return null return null
} }
}, [exchangeAddress, library, withSignerIfPossible, account]) }, [pairAddress, library, withSignerIfPossible, account])
} }
export function useCopyClipboard(timeout = 500) { export function useCopyClipboard(timeout = 500) {
......
...@@ -11,8 +11,9 @@ import ApplicationContextProvider, { Updater as ApplicationContextUpdater } from ...@@ -11,8 +11,9 @@ import ApplicationContextProvider, { Updater as ApplicationContextUpdater } from
import TransactionContextProvider, { Updater as TransactionContextUpdater } from './contexts/Transactions' import TransactionContextProvider, { Updater as TransactionContextUpdater } from './contexts/Transactions'
import BalancesContextProvider, { Updater as BalancesContextUpdater } from './contexts/Balances' import BalancesContextProvider, { Updater as BalancesContextUpdater } from './contexts/Balances'
import TokensContextProvider from './contexts/Tokens' import TokensContextProvider from './contexts/Tokens'
import ExchangesContextProvider from './contexts/Exchanges' import ExchangesContextProvider from './contexts/Pairs'
import AllowancesContextProvider from './contexts/Allowances' import AllowancesContextProvider from './contexts/Allowances'
import RoutesContextProvider from './contexts/Routes'
import App from './pages/App' import App from './pages/App'
import ThemeProvider, { GlobalStyle } from './theme' import ThemeProvider, { GlobalStyle } from './theme'
import './i18n' import './i18n'
...@@ -42,11 +43,13 @@ function ContextProviders({ children }) { ...@@ -42,11 +43,13 @@ function ContextProviders({ children }) {
<ApplicationContextProvider> <ApplicationContextProvider>
<TransactionContextProvider> <TransactionContextProvider>
<ExchangesContextProvider> <ExchangesContextProvider>
<TokensContextProvider> <RoutesContextProvider>
<BalancesContextProvider> <TokensContextProvider>
<AllowancesContextProvider>{children}</AllowancesContextProvider> <BalancesContextProvider>
</BalancesContextProvider> <AllowancesContextProvider>{children}</AllowancesContextProvider>
</TokensContextProvider> </BalancesContextProvider>
</TokensContextProvider>
</RoutesContextProvider>
</ExchangesContextProvider> </ExchangesContextProvider>
</TransactionContextProvider> </TransactionContextProvider>
</ApplicationContextProvider> </ApplicationContextProvider>
......
...@@ -2,7 +2,7 @@ import React, { useReducer, useState, useCallback, useEffect } from 'react' ...@@ -2,7 +2,7 @@ import React, { useReducer, useState, useCallback, useEffect } from 'react'
import styled from 'styled-components' import styled from 'styled-components'
import { ethers } from 'ethers' import { ethers } from 'ethers'
import { parseUnits, parseEther } from '@ethersproject/units' import { parseUnits, parseEther } from '@ethersproject/units'
import { WETH, TokenAmount, JSBI, Percent, Route, Token, Exchange } from '@uniswap/sdk' import { WETH, TokenAmount, JSBI, Percent, Route, Token, Pair } from '@uniswap/sdk'
import TokenLogo from '../../components/TokenLogo' import TokenLogo from '../../components/TokenLogo'
import DoubleLogo from '../../components/DoubleLogo' import DoubleLogo from '../../components/DoubleLogo'
...@@ -22,7 +22,7 @@ import { useWeb3React } from '../../hooks' ...@@ -22,7 +22,7 @@ import { useWeb3React } from '../../hooks'
import { useAddressBalance } from '../../contexts/Balances' import { useAddressBalance } from '../../contexts/Balances'
import { useAddressAllowance } from '../../contexts/Allowances' import { useAddressAllowance } from '../../contexts/Allowances'
import { useTransactionAdder } from '../../contexts/Transactions' import { useTransactionAdder } from '../../contexts/Transactions'
import { useExchange, useTotalSupply } from '../../contexts/Exchanges' import { usePair, useTotalSupply } from '../../contexts/Pairs'
import { BigNumber } from 'ethers/utils' import { BigNumber } from 'ethers/utils'
import { ROUTER_ADDRESSES } from '../../constants' import { ROUTER_ADDRESSES } from '../../constants'
...@@ -159,9 +159,9 @@ export default function AddLiquidity({ token0, token1 }) { ...@@ -159,9 +159,9 @@ export default function AddLiquidity({ token0, token1 }) {
} }
// exhchange data // exhchange data
const exchange: Exchange = useExchange(tokens[Field.INPUT], tokens[Field.OUTPUT]) const pair: Pair = usePair(tokens[Field.INPUT], tokens[Field.OUTPUT])
const route: Route = exchange ? new Route([exchange], tokens[independentField]) : undefined const route: Route = pair ? new Route([pair], tokens[independentField]) : undefined
const totalSupply: TokenAmount = useTotalSupply(exchange) const totalSupply: TokenAmount = useTotalSupply(pair)
const [noLiquidity, setNoLiquidity] = useState<boolean>(false) // used to detect new exchange const [noLiquidity, setNoLiquidity] = useState<boolean>(false) // used to detect new exchange
// state for amount approvals // state for amount approvals
...@@ -178,14 +178,10 @@ export default function AddLiquidity({ token0, token1 }) { ...@@ -178,14 +178,10 @@ export default function AddLiquidity({ token0, token1 }) {
// check if no exchange or no liquidity // check if no exchange or no liquidity
useEffect(() => { useEffect(() => {
if ( if (pair && JSBI.equal(pair.reserve0.raw, JSBI.BigInt(0)) && JSBI.equal(pair.reserve1.raw, JSBI.BigInt(0))) {
exchange &&
JSBI.equal(exchange.reserve0.raw, JSBI.BigInt(0)) &&
JSBI.equal(exchange.reserve1.raw, JSBI.BigInt(0))
) {
setNoLiquidity(true) setNoLiquidity(true)
} }
}, [exchange]) }, [pair])
// track non relational amounts if first person to add liquidity // track non relational amounts if first person to add liquidity
const [nonrelationalAmounts, setNonrelationalAmounts] = useState({ const [nonrelationalAmounts, setNonrelationalAmounts] = useState({
...@@ -238,13 +234,13 @@ export default function AddLiquidity({ token0, token1 }) { ...@@ -238,13 +234,13 @@ export default function AddLiquidity({ token0, token1 }) {
// check for estimated liquidity minted // check for estimated liquidity minted
const liquidityMinted: TokenAmount = const liquidityMinted: TokenAmount =
!!exchange && !!pair &&
!!parsedAmounts[Field.INPUT] && !!parsedAmounts[Field.INPUT] &&
!!parsedAmounts[Field.OUTPUT] && !!parsedAmounts[Field.OUTPUT] &&
!JSBI.equal(parsedAmounts[Field.INPUT].raw, JSBI.BigInt(0)) && !JSBI.equal(parsedAmounts[Field.INPUT].raw, JSBI.BigInt(0)) &&
!JSBI.equal(parsedAmounts[Field.OUTPUT].raw, JSBI.BigInt(0)) !JSBI.equal(parsedAmounts[Field.OUTPUT].raw, JSBI.BigInt(0))
? exchange.getLiquidityMinted( ? pair.getLiquidityMinted(
totalSupply ? totalSupply : new TokenAmount(exchange?.liquidityToken, JSBI.BigInt(0)), totalSupply ? totalSupply : new TokenAmount(pair?.liquidityToken, JSBI.BigInt(0)),
parsedAmounts[Field.INPUT], parsedAmounts[Field.INPUT],
parsedAmounts[Field.OUTPUT] parsedAmounts[Field.OUTPUT]
) )
...@@ -571,9 +567,8 @@ export default function AddLiquidity({ token0, token1 }) { ...@@ -571,9 +567,8 @@ export default function AddLiquidity({ token0, token1 }) {
atMax={atMaxAmountInput} atMax={atMaxAmountInput}
token={tokens[Field.INPUT]} token={tokens[Field.INPUT]}
onTokenSelection={onTokenSelection} onTokenSelection={onTokenSelection}
title={'Deposit'}
error={inputError} error={inputError}
exchange={exchange} pair={pair}
showUnlock={showInputUnlock} showUnlock={showInputUnlock}
disableTokenSelect disableTokenSelect
/> />
...@@ -590,9 +585,8 @@ export default function AddLiquidity({ token0, token1 }) { ...@@ -590,9 +585,8 @@ export default function AddLiquidity({ token0, token1 }) {
atMax={atMaxAmountOutput} atMax={atMaxAmountOutput}
token={tokens[Field.OUTPUT]} token={tokens[Field.OUTPUT]}
onTokenSelection={onTokenSelection} onTokenSelection={onTokenSelection}
title={'Deposit'}
error={outputError} error={outputError}
exchange={exchange} pair={pair}
showUnlock={showOutputUnlock} showUnlock={showOutputUnlock}
disableTokenSelect disableTokenSelect
/> />
...@@ -618,7 +612,7 @@ export default function AddLiquidity({ token0, token1 }) { ...@@ -618,7 +612,7 @@ export default function AddLiquidity({ token0, token1 }) {
{!noLiquidity && ( {!noLiquidity && (
<FixedBottom> <FixedBottom>
<PositionCard <PositionCard
exchangeAddress={exchange?.liquidityToken?.address} pairAddress={pair?.liquidityToken?.address}
token0={tokens[Field.INPUT]} token0={tokens[Field.INPUT]}
token1={tokens[Field.OUTPUT]} token1={tokens[Field.OUTPUT]}
minimal={true} minimal={true}
......
...@@ -2,7 +2,7 @@ import React, { useReducer, useState, useCallback, useEffect } from 'react' ...@@ -2,7 +2,7 @@ import React, { useReducer, useState, useCallback, useEffect } from 'react'
import styled from 'styled-components' import styled from 'styled-components'
import { ethers } from 'ethers' import { ethers } from 'ethers'
import { parseUnits } from '@ethersproject/units' import { parseUnits } from '@ethersproject/units'
import { TokenAmount, JSBI, Route, WETH, Percent, Token, Exchange } from '@uniswap/sdk' import { TokenAmount, JSBI, Route, WETH, Percent, Token, Pair } from '@uniswap/sdk'
import Slider from '../../components/Slider' import Slider from '../../components/Slider'
import TokenLogo from '../../components/TokenLogo' import TokenLogo from '../../components/TokenLogo'
...@@ -21,9 +21,9 @@ import Row, { RowBetween, RowFixed } from '../../components/Row' ...@@ -21,9 +21,9 @@ import Row, { RowBetween, RowFixed } from '../../components/Row'
import { useToken } from '../../contexts/Tokens' import { useToken } from '../../contexts/Tokens'
import { useWeb3React } from '../../hooks' import { useWeb3React } from '../../hooks'
import { useAllBalances } from '../../contexts/Balances' import { useAllBalances } from '../../contexts/Balances'
import { useExchangeContract } from '../../hooks' import { usePairContract } from '../../hooks'
import { useTransactionAdder } from '../../contexts/Transactions' import { useTransactionAdder } from '../../contexts/Transactions'
import { useExchange, useTotalSupply } from '../../contexts/Exchanges' import { usePair, useTotalSupply } from '../../contexts/Pairs'
import { BigNumber } from 'ethers/utils' import { BigNumber } from 'ethers/utils'
import { splitSignature } from '@ethersproject/bytes' import { splitSignature } from '@ethersproject/bytes'
...@@ -160,14 +160,14 @@ export default function RemoveLiquidity({ token0, token1 }) { ...@@ -160,14 +160,14 @@ export default function RemoveLiquidity({ token0, token1 }) {
[Field.TOKEN1]: outputToken [Field.TOKEN1]: outputToken
} }
const exchange: Exchange = useExchange(inputToken, outputToken) const pair: Pair = usePair(inputToken, outputToken)
const exchangeContract: ethers.Contract = useExchangeContract(exchange?.liquidityToken.address) const pairContract: ethers.Contract = usePairContract(pair?.liquidityToken.address)
// pool token data // pool token data
const totalPoolTokens: TokenAmount = useTotalSupply(exchange) const totalPoolTokens: TokenAmount = useTotalSupply(pair)
const allBalances: TokenAmount[] = useAllBalances() const allBalances: TokenAmount[] = useAllBalances()
const userLiquidity: TokenAmount = allBalances?.[account]?.[exchange?.liquidityToken?.address] const userLiquidity: TokenAmount = allBalances?.[account]?.[pair?.liquidityToken?.address]
// input state // input state
const [state, dispatch] = useReducer(reducer, initializeRemoveState(userLiquidity?.toExact(), token0, token1)) const [state, dispatch] = useReducer(reducer, initializeRemoveState(userLiquidity?.toExact(), token0, token1))
...@@ -175,19 +175,19 @@ export default function RemoveLiquidity({ token0, token1 }) { ...@@ -175,19 +175,19 @@ export default function RemoveLiquidity({ token0, token1 }) {
const TokensDeposited: { [field: number]: TokenAmount } = { const TokensDeposited: { [field: number]: TokenAmount } = {
[Field.TOKEN0]: [Field.TOKEN0]:
exchange && pair &&
totalPoolTokens && totalPoolTokens &&
userLiquidity && userLiquidity &&
exchange.getLiquidityValue(tokens[Field.TOKEN0], totalPoolTokens, userLiquidity, false), pair.getLiquidityValue(tokens[Field.TOKEN0], totalPoolTokens, userLiquidity, false),
[Field.TOKEN1]: [Field.TOKEN1]:
exchange && pair &&
totalPoolTokens && totalPoolTokens &&
userLiquidity && userLiquidity &&
exchange.getLiquidityValue(tokens[Field.TOKEN1], totalPoolTokens, userLiquidity, false) pair.getLiquidityValue(tokens[Field.TOKEN1], totalPoolTokens, userLiquidity, false)
} }
const route: Route = exchange const route: Route = pair
? new Route([exchange], independentField !== Field.LIQUIDITY ? tokens[independentField] : tokens[Field.TOKEN1]) ? new Route([pair], independentField !== Field.LIQUIDITY ? tokens[independentField] : tokens[Field.TOKEN1])
: undefined : undefined
// update input value when user types // update input value when user types
...@@ -199,7 +199,7 @@ export default function RemoveLiquidity({ token0, token1 }) { ...@@ -199,7 +199,7 @@ export default function RemoveLiquidity({ token0, token1 }) {
onUserInput( onUserInput(
Field.LIQUIDITY, Field.LIQUIDITY,
new TokenAmount( new TokenAmount(
exchange?.liquidityToken, pair?.liquidityToken,
JSBI.divide(JSBI.multiply(userLiquidity.raw, JSBI.BigInt(newPercent)), JSBI.BigInt(100)) JSBI.divide(JSBI.multiply(userLiquidity.raw, JSBI.BigInt(newPercent)), JSBI.BigInt(100))
).toExact() ).toExact()
) )
...@@ -240,8 +240,8 @@ export default function RemoveLiquidity({ token0, token1 }) { ...@@ -240,8 +240,8 @@ export default function RemoveLiquidity({ token0, token1 }) {
} }
} }
if (independentField === Field.LIQUIDITY) { if (independentField === Field.LIQUIDITY) {
const typedValueParsed = parseUnits(typedValue, exchange?.liquidityToken.decimals).toString() const typedValueParsed = parseUnits(typedValue, pair?.liquidityToken.decimals).toString()
const formattedAmount = new TokenAmount(exchange?.liquidityToken, typedValueParsed) const formattedAmount = new TokenAmount(pair?.liquidityToken, typedValueParsed)
if (typedValueParsed !== '0') { if (typedValueParsed !== '0') {
if (JSBI.lessThanOrEqual(formattedAmount.raw, userLiquidity?.raw)) { if (JSBI.lessThanOrEqual(formattedAmount.raw, userLiquidity?.raw)) {
poolTokenAmount = typedValueParsed poolTokenAmount = typedValueParsed
...@@ -256,19 +256,19 @@ export default function RemoveLiquidity({ token0, token1 }) { ...@@ -256,19 +256,19 @@ export default function RemoveLiquidity({ token0, token1 }) {
// set parsed amounts based on live amount of liquidity // set parsed amounts based on live amount of liquidity
parsedAmounts[Field.LIQUIDITY] = parsedAmounts[Field.LIQUIDITY] =
exchange && poolTokenAmount && userLiquidity && new TokenAmount(exchange.liquidityToken, poolTokenAmount) pair && poolTokenAmount && userLiquidity && new TokenAmount(pair.liquidityToken, poolTokenAmount)
parsedAmounts[Field.TOKEN0] = parsedAmounts[Field.TOKEN0] =
totalPoolTokens && totalPoolTokens &&
exchange && pair &&
parsedAmounts[Field.LIQUIDITY] && parsedAmounts[Field.LIQUIDITY] &&
exchange.getLiquidityValue(tokens[Field.TOKEN0], totalPoolTokens, parsedAmounts[Field.LIQUIDITY], false) pair.getLiquidityValue(tokens[Field.TOKEN0], totalPoolTokens, parsedAmounts[Field.LIQUIDITY], false)
parsedAmounts[Field.TOKEN1] = parsedAmounts[Field.TOKEN1] =
totalPoolTokens && totalPoolTokens &&
exchange && pair &&
parsedAmounts[Field.LIQUIDITY] && parsedAmounts[Field.LIQUIDITY] &&
exchange.getLiquidityValue(tokens[Field.TOKEN1], totalPoolTokens, parsedAmounts[Field.LIQUIDITY], false) pair.getLiquidityValue(tokens[Field.TOKEN1], totalPoolTokens, parsedAmounts[Field.LIQUIDITY], false)
// derived percent for advanced mode // derived percent for advanced mode
const derivedPerecent = const derivedPerecent =
...@@ -358,7 +358,7 @@ export default function RemoveLiquidity({ token0, token1 }) { ...@@ -358,7 +358,7 @@ export default function RemoveLiquidity({ token0, token1 }) {
const [pendingConfirmation, setPendingConfirmation] = useState(true) // waiting for const [pendingConfirmation, setPendingConfirmation] = useState(true) // waiting for
async function onSign() { async function onSign() {
const nonce = await exchangeContract.nonces(account) const nonce = await pairContract.nonces(account)
const newDeadline: number = Math.ceil(Date.now() / 1000) + DEADLINE_FROM_NOW const newDeadline: number = Math.ceil(Date.now() / 1000) + DEADLINE_FROM_NOW
setDeadline(newDeadline) setDeadline(newDeadline)
...@@ -374,7 +374,7 @@ export default function RemoveLiquidity({ token0, token1 }) { ...@@ -374,7 +374,7 @@ export default function RemoveLiquidity({ token0, token1 }) {
name: 'Uniswap V2', name: 'Uniswap V2',
version: '1', version: '1',
chainId: chainId, chainId: chainId,
verifyingContract: exchange.liquidityToken.address verifyingContract: pair.liquidityToken.address
} }
const Permit = [ const Permit = [
...@@ -646,12 +646,11 @@ export default function RemoveLiquidity({ token0, token1 }) { ...@@ -646,12 +646,11 @@ export default function RemoveLiquidity({ token0, token1 }) {
onUserInput={onUserInput} onUserInput={onUserInput}
onMax={onMax} onMax={onMax}
atMax={atMaxAmount} atMax={atMaxAmount}
title={'Burn'}
error={poolTokenError} error={poolTokenError}
disableTokenSelect disableTokenSelect
token={exchange?.liquidityToken} token={pair?.liquidityToken}
isExchange={true} isExchange={true}
exchange={exchange} pair={pair}
/> />
<ColumnCenter> <ColumnCenter>
<ArrowDown size="16" color="#888D9B" /> <ArrowDown size="16" color="#888D9B" />
...@@ -663,7 +662,6 @@ export default function RemoveLiquidity({ token0, token1 }) { ...@@ -663,7 +662,6 @@ export default function RemoveLiquidity({ token0, token1 }) {
onMax={onMax} onMax={onMax}
atMax={atMaxAmount} atMax={atMaxAmount}
token={tokens[Field.TOKEN0]} token={tokens[Field.TOKEN0]}
title={'Withdraw'}
error={inputError} error={inputError}
disableTokenSelect disableTokenSelect
customBalance={TokensDeposited[Field.TOKEN0]} customBalance={TokensDeposited[Field.TOKEN0]}
...@@ -678,7 +676,6 @@ export default function RemoveLiquidity({ token0, token1 }) { ...@@ -678,7 +676,6 @@ export default function RemoveLiquidity({ token0, token1 }) {
onMax={onMax} onMax={onMax}
atMax={atMaxAmount} atMax={atMaxAmount}
token={tokens[Field.TOKEN1]} token={tokens[Field.TOKEN1]}
title={'Withdraw'}
error={outputError} error={outputError}
disableTokenSelect disableTokenSelect
customBalance={TokensDeposited[Field.TOKEN1]} customBalance={TokensDeposited[Field.TOKEN1]}
...@@ -689,11 +686,11 @@ export default function RemoveLiquidity({ token0, token1 }) { ...@@ -689,11 +686,11 @@ export default function RemoveLiquidity({ token0, token1 }) {
<RowBetween> <RowBetween>
Price: Price:
<div> <div>
1 {exchange?.token0.symbol} ={' '} 1 {pair?.token0.symbol} ={' '}
{independentField === Field.TOKEN0 || independentField === Field.LIQUIDITY {independentField === Field.TOKEN0 || independentField === Field.LIQUIDITY
? route?.midPrice.toSignificant(6) ? route?.midPrice.toSignificant(6)
: route?.midPrice.invert().toSignificant(6)}{' '} : route?.midPrice.invert().toSignificant(6)}{' '}
{exchange?.token1.symbol} {pair?.token1.symbol}
</div> </div>
</RowBetween> </RowBetween>
</div> </div>
...@@ -717,9 +714,9 @@ export default function RemoveLiquidity({ token0, token1 }) { ...@@ -717,9 +714,9 @@ export default function RemoveLiquidity({ token0, token1 }) {
</ButtonPrimary> </ButtonPrimary>
<FixedBottom> <FixedBottom>
<PositionCard <PositionCard
exchangeAddress={exchange?.liquidityToken.address} pairAddress={pair?.liquidityToken.address}
token0={exchange?.token0} token0={pair?.token0}
token1={exchange?.token1} token1={pair?.token1}
minimal={true} minimal={true}
/> />
</FixedBottom> </FixedBottom>
......
...@@ -14,9 +14,9 @@ import { AutoColumn } from '../../components/Column' ...@@ -14,9 +14,9 @@ import { AutoColumn } from '../../components/Column'
import { ArrowRight } from 'react-feather' import { ArrowRight } from 'react-feather'
import { ButtonPrimary } from '../../components/Button' import { ButtonPrimary } from '../../components/Button'
import { useAllPairs } from '../../contexts/Pairs'
import { useWeb3React } from '@web3-react/core' import { useWeb3React } from '@web3-react/core'
import { useAllTokens } from '../../contexts/Tokens' import { useAllTokens } from '../../contexts/Tokens'
import { useAllExchanges } from '../../contexts/Exchanges'
import { useAllBalances, useAccountLPBalances } from '../../contexts/Balances' import { useAllBalances, useAccountLPBalances } from '../../contexts/Balances'
const Positions = styled.div` const Positions = styled.div`
...@@ -35,27 +35,27 @@ function Supply({ history }) { ...@@ -35,27 +35,27 @@ function Supply({ history }) {
const allTokens = useAllTokens() const allTokens = useAllTokens()
const allBalances = useAllBalances() const allBalances = useAllBalances()
const allExchanges = useAllExchanges() const allPairs = useAllPairs()
// initiate listener for LP balances // initiate listener for LP balances
useAccountLPBalances(account) useAccountLPBalances(account)
const filteredExchangeList = Object.keys(allExchanges) const filteredExchangeList = Object.keys(allPairs)
.filter((exchangeAddress, i) => { .filter((pairAddress, i) => {
return ( return (
allBalances && allBalances &&
allBalances[account] && allBalances[account] &&
allBalances[account][exchangeAddress] && allBalances[account][pairAddress] &&
JSBI.greaterThan(allBalances[account][exchangeAddress].raw, JSBI.BigInt(0)) JSBI.greaterThan(allBalances[account][pairAddress].raw, JSBI.BigInt(0))
) )
}) })
.map((exchangeAddress, i) => { .map((pairAddress, i) => {
return ( return (
<PositionCard <PositionCard
key={i} key={i}
exchangeAddress={exchangeAddress} pairAddress={pairAddress}
token0={allTokens[allExchanges[exchangeAddress].token0]} token0={allTokens[allPairs[pairAddress].token0]}
token1={allTokens[allExchanges[exchangeAddress].token1]} token1={allTokens[allPairs[pairAddress].token1]}
/> />
) )
}) })
......
...@@ -142,8 +142,8 @@ export function getFactoryContract(networkId, library, account) { ...@@ -142,8 +142,8 @@ export function getFactoryContract(networkId, library, account) {
} }
// account is optional // account is optional
export function getExchangeContract(exchangeAddress, library, account) { export function getExchangeContract(pairAddress, library, account) {
return getContract(exchangeAddress, EXCHANGE_ABI, library, account) return getContract(pairAddress, EXCHANGE_ABI, library, account)
} }
// get token name // get token name
...@@ -198,7 +198,7 @@ export async function getTokenDecimals(tokenAddress, library) { ...@@ -198,7 +198,7 @@ export async function getTokenDecimals(tokenAddress, library) {
} }
// get the exchange address for a token from the factory // get the exchange address for a token from the factory
export async function getTokenExchangeAddressFromFactory(tokenAddress, networkId, library) { export async function getTokenpairAddressFromFactory(tokenAddress, networkId, library) {
return getFactoryContract(networkId, library).getExchange(tokenAddress) return getFactoryContract(networkId, library).getExchange(tokenAddress)
} }
......
...@@ -2385,10 +2385,10 @@ ...@@ -2385,10 +2385,10 @@
semver "^6.3.0" semver "^6.3.0"
tsutils "^3.17.1" tsutils "^3.17.1"
"@uniswap/sdk@@uniswap/sdk@2.0.0-beta.19": "@uniswap/sdk@@uniswap/sdk@2.0.0-beta.20":
version "2.0.0-beta.19" version "2.0.0-beta.20"
resolved "https://registry.yarnpkg.com/@uniswap/sdk/-/sdk-2.0.0-beta.19.tgz#1f0228a1d5451d62f209e09c48cd1d6bea5ffe01" resolved "https://registry.yarnpkg.com/@uniswap/sdk/-/sdk-2.0.0-beta.20.tgz#f541909158d053d8bf9ae8af62b2b4f83cc7068c"
integrity sha512-mqDZkeX2TU7e3yOOKHSeUryv94//mJ6dsU6dCv6FExrfOY9yi6+O5ZWpe43rVi0XFVdQGRIRhJapdWKWaGsung== integrity sha512-PuXlwGKrEd3L+eIs4oQZQ3IFnVZe/JN9U2jyV6DPjO/dmBL8mzCaqMAiAmQSEAIrBSHFTpxYwklltbY/bU7+Dg==
dependencies: dependencies:
"@ethersproject/address" "^5.0.0-beta.134" "@ethersproject/address" "^5.0.0-beta.134"
"@ethersproject/contracts" "^5.0.0-beta.143" "@ethersproject/contracts" "^5.0.0-beta.143"
......
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