Commit 236c3030 authored by ianlapham's avatar ianlapham

stable state for swaps, add, and remove eth (no remove token token yet)

parent 753e5f34
This diff is collapsed.
import React, { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { ethers } from 'ethers'
import styled from 'styled-components'
import { darken } from 'polished'
import '@reach/tooltip/styles.css'
import { ethers } from 'ethers'
import { darken } from 'polished'
import { WETH } from '@uniswap/sdk'
import { Text } from 'rebass'
import { ReactComponent as DropDown } from '../../assets/images/dropdown.svg'
import TokenLogo from '../TokenLogo'
import DoubleLogo from '../DoubleLogo'
import SearchModal from '../SearchModal'
import { Input as NumericalInput } from '../NumericalInput'
import { Text } from 'rebass'
import { RowBetween } from '../Row'
import { ReactComponent as DropDown } from '../../assets/images/dropdown.svg'
import { Input as NumericalInput } from '../NumericalInput'
import { useWeb3React } from '../../hooks'
import { useTransactionAdder, usePendingApproval } from '../../contexts/Transactions'
import { useToken, useAllTokens } from '../../contexts/Tokens'
import { useTranslation } from 'react-i18next'
import { useTokenContract } from '../../hooks'
import { calculateGasMargin } from '../../utils'
import { useAddressBalance } from '../../contexts/Balances'
import { useTransactionAdder, usePendingApproval } from '../../contexts/Transactions'
const GAS_MARGIN = ethers.utils.bigNumberify(1000)
......@@ -26,9 +27,9 @@ const SubCurrencySelect = styled.button`
padding: 4px 50px 4px 15px;
margin-right: -40px;
line-height: 0;
height: 2rem;
align-items: center;
border-radius: 2.5rem;
height: 2rem;
outline: none;
cursor: pointer;
user-select: none;
......@@ -41,15 +42,16 @@ const InputRow = styled.div`
${({ theme }) => theme.flexRowNoWrap}
align-items: center;
padding: 0.25rem 0.85rem 0.75rem;
padding: 0.75rem 0.85rem 0.75rem;
`
const CurrencySelect = styled.button`
align-items: center;
height: 2.2rem;
font-size: 20px;
background-color: ${({ selected, theme }) => (selected ? theme.buttonBackgroundPlain : theme.zumthorBlue)};
color: ${({ selected, theme }) => (selected ? theme.textColor : theme.royalBlue)};
height: 2rem;
border: 1px solid
${({ selected, theme, disableTokenSelect }) =>
disableTokenSelect ? theme.buttonBackgroundPlain : selected ? theme.buttonOutlinePlain : theme.royalBlue};
......@@ -111,7 +113,7 @@ const LabelRow = styled.div`
color: ${({ theme }) => theme.doveGray};
font-size: 0.75rem;
line-height: 1rem;
padding: 0.75rem 1rem;
padding: 0.75rem 1rem 0;
span:hover {
cursor: pointer;
color: ${({ theme }) => darken(0.2, theme.doveGray)};
......@@ -159,49 +161,44 @@ export default function CurrencyInputPanel({
value,
field,
onUserInput,
selectedTokenAddress,
onTokenSelection,
title,
onMax,
atMax,
error
// disableUnlock,
// disableTokenSelect,
// urlAddedTokens
error,
urlAddedTokens = [], // used
token = null,
showUnlock = false, // used to show unlock if approval needed
disableUnlock = false,
disableTokenSelect = false,
hideBalance = false,
isExchange = false,
exchange = null, // used for double token logo
customBalance = null // used for LP balances instead of token balance
}) {
const { account } = useWeb3React()
const { account, chainId } = useWeb3React()
const { t } = useTranslation()
const disableUnlock = false
const disableTokenSelect = false
const urlAddedTokens = []
const errorMessage = error
const [modalIsOpen, setModalIsOpen] = useState(false)
const tokenContract = useTokenContract(selectedTokenAddress)
const { exchangeAddress: selectedTokenExchangeAddress } = useToken(selectedTokenAddress)
const pendingApproval = usePendingApproval(selectedTokenAddress)
const addTransaction = useTransactionAdder()
const allTokens = useAllTokens()
const token = useToken(selectedTokenAddress)
const [modalOpen, setModalOpen] = useState(false)
const [showMax, setShowMax] = useState(false)
// this one causes the infinite loop
const userTokenBalance = useAddressBalance(account, token)
const [showUnlock] = useState(false)
const tokenContract = useTokenContract(token?.address)
const pendingApproval = usePendingApproval(token?.address)
const [showMax, setShowMax] = useState(false)
const routerAddress = '0xd9210Ff5A0780E083BB40e30d005d93a2DcFA4EF'
function renderUnlockButton() {
if (disableUnlock || !showUnlock || selectedTokenAddress === 'ETH' || !selectedTokenAddress) {
if (
disableUnlock ||
!showUnlock ||
token?.address === 'ETH' ||
token?.address === WETH[chainId].address ||
!token?.address
) {
return null
} else {
if (!pendingApproval) {
......@@ -211,25 +208,21 @@ export default function CurrencyInputPanel({
let estimatedGas
let useUserBalance = false
estimatedGas = await tokenContract.estimate
.approve(selectedTokenExchangeAddress, ethers.constants.MaxUint256)
.approve(routerAddress, ethers.constants.MaxUint256)
.catch(e => {
console.log('Error setting max token approval.')
})
if (!estimatedGas) {
// general fallback for tokens who restrict approval amounts
estimatedGas = await tokenContract.estimate.approve(selectedTokenExchangeAddress, userTokenBalance)
estimatedGas = await tokenContract.estimate.approve(routerAddress, userTokenBalance)
useUserBalance = true
}
tokenContract
.approve(
selectedTokenExchangeAddress,
useUserBalance ? userTokenBalance : ethers.constants.MaxUint256,
{
.approve(routerAddress, useUserBalance ? userTokenBalance : ethers.constants.MaxUint256, {
gasLimit: calculateGasMargin(estimatedGas, GAS_MARGIN)
}
)
})
.then(response => {
addTransaction(response, { approval: selectedTokenAddress })
addTransaction(response, { approval: token?.address })
})
}}
>
......@@ -244,16 +237,20 @@ export default function CurrencyInputPanel({
return (
<InputPanel>
<Container error={!!errorMessage}>
<Container error={!!error}>
{!hideBalance && (
<LabelRow>
<RowBetween>
<Text>{title}</Text>
<ErrorSpan data-tip={'Enter max'} error={!!errorMessage} onClick={() => {}}></ErrorSpan>
<ErrorSpan data-tip={'Enter max'} error={!!error} onClick={() => {}}></ErrorSpan>
<ClickableText onClick={onMax}>
<Text>Balance: {userTokenBalance?.toFixed(2)}</Text>
<Text>
Balance: {customBalance ? customBalance.toSignificant(4) : userTokenBalance?.toSignificant(4)}
</Text>
</ClickableText>
</RowBetween>
</LabelRow>
)}
<InputRow>
<NumericalInput
field={field}
......@@ -263,34 +260,40 @@ export default function CurrencyInputPanel({
setShowMax(true)
}}
/>
{!!selectedTokenAddress && !atMax && showMax && <StyledBalanceMax onClick={onMax}>MAX</StyledBalanceMax>}
{!!token?.address && !atMax && showMax && <StyledBalanceMax onClick={onMax}>MAX</StyledBalanceMax>}
{renderUnlockButton()}
<CurrencySelect
selected={!!selectedTokenAddress}
selected={!!token?.address}
onClick={() => {
if (!disableTokenSelect) {
setModalIsOpen(true)
setModalOpen(true)
}
}}
disableTokenSelect={disableTokenSelect}
>
<Aligner>
{selectedTokenAddress ? <TokenLogo address={selectedTokenAddress} size={'24px'} /> : null}
{
{isExchange ? (
<DoubleLogo a0={exchange?.token0.address} a1={exchange?.token1.address} margin={true} />
) : token?.address ? (
<TokenLogo address={token?.address} size={'24px'} />
) : null}
{isExchange ? (
<StyledTokenName>
{(allTokens[selectedTokenAddress] && allTokens[selectedTokenAddress].symbol) || t('selectToken')}
{exchange?.token0.symbol}:{exchange?.token1.symbol}
</StyledTokenName>
}
{!disableTokenSelect && <StyledDropDown selected={!!selectedTokenAddress} />}
) : (
<StyledTokenName>{(token && token.symbol) || t('selectToken')}</StyledTokenName>
)}
{!disableTokenSelect && <StyledDropDown selected={!!token?.address} />}
</Aligner>
</CurrencySelect>
</InputRow>
</Container>
{!disableTokenSelect && (
<SearchModal
isOpen={modalIsOpen}
isOpen={modalOpen}
onDismiss={() => {
setModalIsOpen(false)
setModalOpen(false)
}}
filterType="tokens"
urlAddedTokens={urlAddedTokens}
......
This diff is collapsed.
This diff is collapsed.
......@@ -95,7 +95,14 @@ const HiddenCloseButton = styled.button`
border: none;
`
export default function Modal({ isOpen, onDismiss, minHeight = false, maxHeight = 50, initialFocusRef, children }) {
export default function Modal({
isOpen,
onDismiss,
minHeight = false,
maxHeight = 50,
initialFocusRef = null,
children
}) {
const transitions = useTransition(isOpen, null, {
config: { duration: 200 },
from: { opacity: 0 },
......
......@@ -130,16 +130,17 @@ function NavigationTabs({ location: { pathname }, history }) {
useBodyKeyDown('ArrowLeft', navigateLeft)
const adding = pathname.match('/add')
const removing = pathname.match('/remove')
return (
<>
{adding ? (
{adding || removing ? (
<Tabs>
<RowBetween style={{ padding: '1rem' }}>
<HistoryLink to="/supply">
<ArrowLink />
</HistoryLink>
<ActiveText>Add Liquidity</ActiveText>
<ActiveText>{adding ? 'Add' : 'Remove'} Liquidity</ActiveText>
<QuestionHelper text={'helper text'} />
</RowBetween>
</Tabs>
......@@ -152,7 +153,6 @@ function NavigationTabs({ location: { pathname }, history }) {
))}
</Tabs>
)}
{showBetaMessage && (
<BetaMessage onClick={dismissBetaMessage}>
<span role="img" aria-label="warning">
......
......@@ -94,10 +94,13 @@ const PaddedColumn = styled(AutoColumn)`
padding-bottom: 12px;
`
const MenuItem = styled(RowBetween)`
const PaddedItem = styled(RowBetween)`
padding: 4px 24px;
width: calc(100% - 48px);
height: 56px;
`
const MenuItem = styled(PaddedItem)`
cursor: pointer;
:hover {
......@@ -107,12 +110,18 @@ const MenuItem = styled(RowBetween)`
function SearchModal({ history, isOpen, onDismiss, onTokenSelect, field, urlAddedTokens, filterType }) {
const { t } = useTranslation()
const { account, chainId } = useWeb3React()
const [searchQuery, setSearchQuery] = useState('')
const { exchangeAddress } = useToken(searchQuery)
const allTokens = useAllTokens()
// get all exchanges
const allExchanges = useAllExchanges()
const exchange = useToken(searchQuery)
const { account, chainId } = useWeb3React()
const exchangeAddress = exchange && exchange.exchangeAddress
// get all tokens
const allTokens = useAllTokens()
// all balances for both account and exchanges
let allBalances = useAllBalances()
......@@ -138,11 +147,7 @@ function SearchModal({ history, isOpen, onDismiss, onTokenSelect, field, urlAdde
.map(k => {
let balance
// only update if we have data
if (k === 'ETH' && allBalances[account] && allBalances[account][k] && allBalances[account][k].value) {
balance = allBalances[account][k].value
} else if (allBalances[account] && allBalances[account][k] && allBalances[account][k].value) {
balance = (allBalances[account][k].value, allTokens[k].decimals)
}
balance = allBalances?.[account]?.[k]
return {
name: allTokens[k].name,
symbol: allTokens[k].symbol,
......@@ -195,9 +200,6 @@ function SearchModal({ history, isOpen, onDismiss, onTokenSelect, field, urlAdde
onDismiss()
}
// get all exchanges
const allExchanges = useAllExchanges()
// amount of tokens to display at once
const [tokensShown, setTokensShown] = useState(0)
const [pairsShown, setPairsShown] = useState(0)
......@@ -218,15 +220,14 @@ function SearchModal({ history, isOpen, onDismiss, onTokenSelect, field, urlAdde
const filteredPairList = useMemo(() => {
// check if the search is an address
const isAddress = searchQuery.slice(0, 2) === '0x'
return Object.keys(allExchanges).filter(exchangeAddress => {
const exchange = allExchanges[exchangeAddress]
return Object.keys(allExchanges).filter(token0Address => {
return Object.keys(allExchanges[token0Address]).map(token1Address => {
if (searchQuery === '') {
return true
}
const token0 = allTokens[token0Address]
const token1 = allTokens[token1Address]
const token0 = allTokens[exchange.token0]
const token1 = allTokens[exchange.token1]
const regexMatches = Object.keys(token0).map(field => {
if (
......@@ -244,7 +245,6 @@ function SearchModal({ history, isOpen, onDismiss, onTokenSelect, field, urlAdde
return regexMatches.some(m => m)
})
})
}, [allExchanges, allTokens, searchQuery])
// update the amount shown as filtered list changes
......@@ -256,14 +256,20 @@ function SearchModal({ history, isOpen, onDismiss, onTokenSelect, field, urlAdde
}, [filteredPairList])
function renderPairsList() {
if (filteredPairList?.length === 0) {
return (
<PaddedColumn justify="center">
<Text>No Pools Found</Text>
</PaddedColumn>
)
}
return (
filteredPairList &&
filteredPairList.map((token0Address, i) => {
return Object.keys(allExchanges[token0Address]).map(token1Address => {
const token0 = allTokens[token0Address]
const token1 = allTokens[token1Address]
filteredPairList.map((exchangeAddress, i) => {
const token0 = allTokens[allExchanges[exchangeAddress].token0]
const token1 = allTokens[allExchanges[exchangeAddress].token1]
const exchangeAddress = allExchanges[token0Address][token1Address]
const balance = allBalances?.[account]?.[exchangeAddress]?.toSignificant(6)
return (
......@@ -284,7 +290,6 @@ function SearchModal({ history, isOpen, onDismiss, onTokenSelect, field, urlAdde
</MenuItem>
)
})
})
)
}
......@@ -326,7 +331,7 @@ function SearchModal({ history, isOpen, onDismiss, onTokenSelect, field, urlAdde
</RowFixed>
<AutoColumn gap="4px" justify="end">
{balance ? (
<Text>{balance && (balance > 0 || balance === '<0.0001') ? balance : '-'}</Text>
<Text>{balance ? balance.toSignificant(6) : '-'}</Text>
) : account ? (
<SpinnerWrapper src={Circle} alt="loader" />
) : (
......@@ -389,6 +394,7 @@ function SearchModal({ history, isOpen, onDismiss, onTokenSelect, field, urlAdde
</RowBetween>
</PaddedColumn>
<div style={{ width: '100%', height: '1px', backgroundColor: '#E1E1E1' }} />
<TokenList>{filterType === 'tokens' ? renderTokenList() : renderPairsList()}</TokenList>
</TokenModal>
</Modal>
......
import React, { useState } from 'react'
import styled from 'styled-components'
import { isAddress } from '../../utils'
import { useWeb3React } from '../../hooks'
import { WETH } from '@uniswap/sdk'
import { ReactComponent as EthereumLogo } from '../../assets/images/ethereum-logo.svg'
......@@ -21,8 +23,11 @@ const Emoji = styled.span`
display: flex;
align-items: center;
justify-content: center;
font-size: ${({ size }) => size};
width: ${({ size }) => size};
height: ${({ size }) => size};
margin-bottom: -2px;
margin-right: ${({ sizeraw, margin }) => margin && (sizeraw / 2 + 10).toString() + 'px'};
`
const StyledEthereumLogo = styled(EthereumLogo)`
......@@ -32,6 +37,17 @@ const StyledEthereumLogo = styled(EthereumLogo)`
export default function TokenLogo({ address, size = '1rem', ...rest }) {
const [error, setError] = useState(false)
const { chainId } = useWeb3React()
// hard code change to show ETH instead of WETH in UI
if (address === WETH[chainId].address) {
address = 'ETH'
}
// remove this just for testing
if (address === isAddress('0xc7AD46e0b8a400Bb3C915120d284AafbA8fc4735')) {
address = '0x6b175474e89094c44da98b954eedeac495271d0f'
}
let path = ''
if (address === 'ETH') {
......
......@@ -104,7 +104,6 @@ const FancyButton = styled.button`
color: ${({ theme }) => theme.textColor};
align-items: center;
min-width: 55px;
height: 2rem;
border-radius: 36px;
font-size: 12px;
border: 1px solid ${({ theme }) => theme.mercuryGray};
......@@ -219,7 +218,6 @@ const BottomError = styled.div`
`
const OptionCustom = styled(FancyButton)`
height: 2rem;
position: relative;
width: 120px;
margin-top: 6px;
......
This diff is collapsed.
This diff is collapsed.
......@@ -7,11 +7,25 @@ export const FACTORY_ADDRESSES = {
42: '0xD3E51Ef092B2845f10401a0159B2B96e8B6c3D30'
}
export const ROUTER_ADDRESSES = {
1: '',
3: '',
4: '0xd9210Ff5A0780E083BB40e30d005d93a2DcFA4EF',
42: ''
}
export const SUPPORTED_THEMES = {
DARK: 'DARK',
LIGHT: 'LIGHT'
}
export enum TRANSACTION_TYPE {
SWAP,
SEND,
ADD,
REMOVE
}
const MAINNET_WALLETS = {
INJECTED: {
connector: injected,
......
import React, { createContext, useContext, useReducer, useMemo, useCallback, useEffect } from 'react'
import { Token, TokenAmount } from '@uniswap/sdk'
import { Token, TokenAmount, WETH } from '@uniswap/sdk'
import { useWeb3React } from '../hooks'
import { safeAccess, isAddress, getTokenAllowance } from '../utils'
......@@ -60,12 +60,13 @@ export function useAddressAllowance(address: string, token: Token, spenderAddres
const globalBlockNumber = useBlockNumber()
const [state, { update }] = useAllowancesContext()
const { value, blockNumber } = safeAccess(state, [chainId, address, token.address, spenderAddress]) || {}
const { value, blockNumber } = safeAccess(state, [chainId, address, token?.address, spenderAddress]) || {}
useEffect(() => {
if (
isAddress(address) &&
isAddress(token.address) &&
isAddress(token?.address) &&
isAddress(token?.address) !== WETH[chainId].address &&
isAddress(spenderAddress) &&
(value === undefined || blockNumber !== globalBlockNumber) &&
(chainId || chainId === 0) &&
......@@ -73,15 +74,15 @@ export function useAddressAllowance(address: string, token: Token, spenderAddres
) {
let stale = false
getTokenAllowance(address, token.address, spenderAddress, library)
getTokenAllowance(address, token?.address, spenderAddress, library)
.then(value => {
if (!stale) {
update(chainId, address, token.address, spenderAddress, value, globalBlockNumber)
update(chainId, address, token?.address, spenderAddress, value, globalBlockNumber)
}
})
.catch(() => {
if (!stale) {
update(chainId, address, token.address, spenderAddress, null, globalBlockNumber)
update(chainId, address, token?.address, spenderAddress, null, globalBlockNumber)
}
})
......@@ -89,7 +90,7 @@ export function useAddressAllowance(address: string, token: Token, spenderAddres
stale = true
}
}
}, [address, token.address, spenderAddress, value, blockNumber, globalBlockNumber, chainId, library, update])
}, [address, token, spenderAddress, value, blockNumber, globalBlockNumber, chainId, library, update])
const newTokenAmount: TokenAmount = value ? new TokenAmount(token, value) : null
return newTokenAmount
......
import React, { createContext, useContext, useReducer, useRef, useMemo, useCallback, useEffect, ReactNode } from 'react'
import { TokenAmount, Token, JSBI } from '@uniswap/sdk'
import { TokenAmount, Token, JSBI, WETH } from '@uniswap/sdk'
import { useWeb3React, useDebounce } from '../hooks'
import { getEtherBalance, getTokenBalance, isAddress } from '../utils'
......@@ -13,10 +13,6 @@ const LONG_BLOCK_TIMEOUT = (60 * 15) / 15 // in seconds, represented as a block
const EXCHANGES_BLOCK_TIMEOUT = (60 * 5) / 15 // in seconds, represented as a block number delta
const TRACK_LP_BLANCES = 'TRACK_LP_BLANCES'
const UPDATABLE_KEYS = [TRACK_LP_BLANCES]
interface BalancesState {
[chainId: number]: {
[address: string]: {
......@@ -42,8 +38,7 @@ enum Action {
STOP_LISTENING,
UPDATE,
BATCH_UPDATE_ACCOUNT,
BATCH_UPDATE_EXCHANGES,
UPDATE_KEY
BATCH_UPDATE_EXCHANGES
}
function reducer(state: BalancesState, { type, payload }: { type: Action; payload: any }) {
......@@ -147,17 +142,6 @@ function reducer(state: BalancesState, { type, payload }: { type: Action; payloa
}
}
}
case Action.UPDATE_KEY: {
const { key, value } = payload
if (!UPDATABLE_KEYS.some(k => k === key)) {
throw Error(`Unexpected key in LocalStorageContext reducer: '${key}'.`)
} else {
return {
...state,
[key]: value
}
}
}
default: {
throw Error(`Unexpected action type in BalancesContext reducer: '${type}'.`)
}
......@@ -196,15 +180,11 @@ export default function Provider({ children }: { children: ReactNode }) {
})
}, [])
const updateKey = useCallback((key, value) => {
dispatch({ type: Action.UPDATE_KEY, payload: { key, value } })
}, [])
return (
<BalancesContext.Provider
value={useMemo(
() => [state, { startListening, stopListening, update, batchUpdateAccount, batchUpdateExchanges, updateKey }],
[state, startListening, stopListening, update, batchUpdateAccount, batchUpdateExchanges, updateKey]
() => [state, { startListening, stopListening, update, batchUpdateAccount, batchUpdateExchanges }],
[state, startListening, stopListening, update, batchUpdateAccount, batchUpdateExchanges]
)}
>
{children}
......@@ -235,15 +215,21 @@ export function Updater() {
// generic balances fetcher abstracting away difference between fetching ETH + token balances
const fetchBalance = useCallback(
(address: string, tokenAddress: string) =>
(tokenAddress === 'ETH' ? getEtherBalance(address, library) : getTokenBalance(tokenAddress, address, library))
(address: string, tokenAddress: string) => {
return (tokenAddress === 'ETH'
? getEtherBalance(address, library)
: address === account && tokenAddress === WETH[chainId].address
? getEtherBalance(address, library)
: getTokenBalance(tokenAddress, address, library)
)
.then(value => {
return value.toString()
})
.catch(() => {
return null
}),
[library]
})
},
[account, chainId, library]
)
// ensure that all balances with >=1 listeners are updated every block
......@@ -338,22 +324,7 @@ export function Updater() {
}, [chainId, account, blockNumber, allTokens, fetchBalance, batchUpdateAccount])
// ensure token balances for all exchanges
const allExchangeDetails = useAllExchanges()
// format so we can index by exchange and only update specifc values
const allExchanges = useMemo(() => {
const formattedExchanges = {}
Object.keys(allExchangeDetails).map(token0Address => {
return Object.keys(allExchangeDetails[token0Address]).map(token1Address => {
const exchangeAddress = allExchangeDetails[token0Address][token1Address]
return (formattedExchanges[exchangeAddress] = {
token0: token0Address,
token1: token1Address
})
})
})
return formattedExchanges
}, [allExchangeDetails])
const allExchanges = useAllExchanges()
useEffect(() => {
if (typeof chainId === 'number' && typeof blockNumber === 'number') {
......@@ -443,6 +414,7 @@ export function useAllBalances(): Array<TokenAmount> {
let newBalances = {}
Object.keys(state[chainId]).map(address => {
return Object.keys(state[chainId][address]).map(tokenAddress => {
if (state?.[chainId][address][tokenAddress].value) {
return (newBalances[chainId] = {
...newBalances[chainId],
[address]: {
......@@ -460,6 +432,7 @@ export function useAllBalances(): Array<TokenAmount> {
)
}
})
}
})
})
return newBalances
......@@ -476,24 +449,43 @@ export function useAddressBalance(address: string, token: Token): TokenAmount |
const { chainId } = useWeb3React()
const [state, { startListening, stopListening }] = useBalancesContext()
const allTokens = useAllTokens()
/**
* @todo
* when catching for token, causes infinite rerender
* when the token is an exchange liquidity token
*/
useEffect(() => {
if (typeof chainId === 'number' && isAddress(address) && isAddress(token.address)) {
if (typeof chainId === 'number' && isAddress(address) && token && token.address && isAddress(token.address)) {
startListening(chainId, address, token.address)
return () => {
stopListening(chainId, address, token.address)
}
}
}, [chainId, address, token, startListening, stopListening])
const value = typeof chainId === 'number' ? state?.[chainId]?.[address]?.[token.address]?.value : undefined
}, [chainId, address, startListening, stopListening])
const formattedValue = value && new TokenAmount(allTokens?.[token.address], value)
const value = typeof chainId === 'number' ? state?.[chainId]?.[address]?.[token?.address]?.value : undefined
const formattedValue = value && token && new TokenAmount(token, value)
return useMemo(() => formattedValue, [formattedValue])
}
export function useAccountLPBalances(account: string) {
const { chainId } = useWeb3React()
const [, { startListening, stopListening }] = useBalancesContext()
const allExchanges = useAllExchanges()
useEffect(() => {
Object.keys(allExchanges).map(exchangeAddress => {
if (typeof chainId === 'number' && isAddress(account)) {
startListening(chainId, account, exchangeAddress)
return () => {
stopListening(chainId, account, exchangeAddress)
}
}
})
}, [account, allExchanges, chainId, startListening, stopListening])
}
export function useExchangeReserves(tokenAddress: string) {
return []
}
import React, { createContext, useContext, useReducer, useMemo, useCallback, useEffect } from 'react'
import { ChainId, WETH, Token, Exchange } from '@uniswap/sdk'
import { INITIAL_TOKENS_CONTEXT, useToken } from './Tokens'
import { INITIAL_TOKENS_CONTEXT } from './Tokens'
import { useAddressBalance } from './Balances'
import { useWeb3React } from '../hooks'
......@@ -11,6 +11,10 @@ const ALL_EXCHANGES: [Token, Token][] = [
[
INITIAL_TOKENS_CONTEXT[ChainId.RINKEBY][WETH[ChainId.RINKEBY].address],
INITIAL_TOKENS_CONTEXT[ChainId.RINKEBY]['0xc7AD46e0b8a400Bb3C915120d284AafbA8fc4735']
],
[
INITIAL_TOKENS_CONTEXT[ChainId.RINKEBY]['0xc7AD46e0b8a400Bb3C915120d284AafbA8fc4735'],
INITIAL_TOKENS_CONTEXT[ChainId.RINKEBY]['0x8ab15C890E5C03B5F240f2D146e3DF54bEf3Df44']
]
]
......@@ -82,9 +86,9 @@ export function useExchangeAddress(tokenA?: Token, tokenB?: Token): string | und
const { chainId } = useWeb3React()
const [state, { update }] = useExchangesContext()
const tokens: [Token, Token] = tokenA.sortsBefore(tokenB) ? [tokenA, tokenB] : [tokenB, tokenA]
const tokens: [Token, Token] = tokenA && tokenB && tokenA.sortsBefore(tokenB) ? [tokenA, tokenB] : [tokenB, tokenA]
const address = state?.[chainId]?.[tokens[0].address]?.[tokens[1].address]
const address = state?.[chainId]?.[tokens[0]?.address]?.[tokens[1]?.address]
useEffect(() => {
if (address === undefined && tokenA && tokenB) {
......@@ -111,7 +115,26 @@ export function useAllExchanges() {
const { chainId } = useWeb3React()
const [state] = useExchangesContext()
const allExchangeDetails = state?.[chainId]
const allExchanges = useMemo(() => {
if (!allExchangeDetails) {
return {}
}
const formattedExchanges = {}
Object.keys(allExchangeDetails).map(token0Address => {
return Object.keys(allExchangeDetails[token0Address]).map(token1Address => {
const exchangeAddress = allExchangeDetails[token0Address][token1Address]
return (formattedExchanges[exchangeAddress] = {
token0: token0Address,
token1: token1Address
})
})
})
return formattedExchanges
}, [allExchangeDetails])
return useMemo(() => {
return state?.[chainId] || {}
}, [state, chainId])
return allExchanges || {}
}, [allExchanges])
}
......@@ -7,7 +7,8 @@ const UPDATE = 'UPDATE'
export const ALL_TOKENS = [
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')
]
// only meant to be used in exchanges.ts!
......@@ -67,10 +68,11 @@ export function useToken(tokenAddress: string): Token {
const [state, { update }] = useTokensContext()
const allTokensInNetwork = state?.[chainId] || {}
const token = safeAccess(allTokensInNetwork, [tokenAddress]) || {}
const token = safeAccess(allTokensInNetwork, [tokenAddress])
useEffect(() => {
if (
token &&
isAddress(tokenAddress) &&
(token === undefined || token.name === undefined || token.symbol === undefined || token.decimals === undefined) &&
(chainId || chainId === 0) &&
......@@ -95,6 +97,14 @@ export function useToken(tokenAddress: string): Token {
}
}, [tokenAddress, token, chainId, library, update])
// hard coded change in UI to display WETH as ETH
if (token && token.name === 'WETH') {
token.name = 'ETH'
}
if (token && token.symbol === 'WETH') {
token.symbol = 'ETH'
}
return token
}
......
......@@ -122,6 +122,25 @@ export default function App() {
}
}}
/>
<Route
exact
strict
path={'/remove/:tokens'}
component={({ match }) => {
const tokens = match.params.tokens.split('-')
let t0
let t1
if (tokens) {
t0 = tokens[0] === 'ETH' ? 'ETH' : isAddress(tokens[0])
t1 = tokens[1] === 'ETH' ? 'ETH' : isAddress(tokens[1])
}
if (t0 && t1) {
return <Remove params={params} token0={t0} token1={t1} />
} else {
return <Redirect to={{ pathname: '/supply' }} />
}
}}
/>
<Route exaxct path={'/remove'} component={() => <Remove params={params} />} />
</Switch>
</Suspense>
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -2288,10 +2288,10 @@
semver "^6.3.0"
tsutils "^3.17.1"
"@uniswap/sdk@next":
version "2.0.0-beta.15"
resolved "https://registry.yarnpkg.com/@uniswap/sdk/-/sdk-2.0.0-beta.15.tgz#66487b8402fbc5b083c3744a890e64fb4024409c"
integrity sha512-Vj4r0EBr1eHaOV7OfwqVUjkbNsB93xRfJuCpEx2+OitDLWkM+arkSnw1jcixPZ7Dt+GTPXflgXGv3rB4s+ODog==
"@uniswap/sdk@@uniswap/sdk@2.0.0-beta.17":
version "2.0.0-beta.17"
resolved "https://registry.yarnpkg.com/@uniswap/sdk/-/sdk-2.0.0-beta.17.tgz#8f24be0375d5f8137eae75afe75b2356c75bb793"
integrity sha512-Nd3S/VE51z4jsNs9G9hkslUkS862dpslnU86lXEJi7mbbbPIagh31iR0s/uBPnrBFGiktucgvzRn6WJJIvojWA==
dependencies:
"@ethersproject/address" "^5.0.0-beta.134"
"@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