Commit c3f65e3a authored by Noah Zinsmeister's avatar Noah Zinsmeister Committed by GitHub

migration v2 (#38)

* wip

* add some v2 paths

* start to refactor migrate page

update deploy addresses

* fix tests

* stub out v3 remove

* silence some lint warnings
parent 306aaa3a
describe('Remove Liquidity', () => { describe('Remove Liquidity', () => {
it('redirects', () => { it('redirects', () => {
cy.visit('/remove/0xc778417E063141139Fce010982780140Aa0cD5Ab-0xF9bA5210F91D0474bd1e1DcDAeC4C58E359AaD85') cy.visit('/remove/v2/0xc778417E063141139Fce010982780140Aa0cD5Ab-0xF9bA5210F91D0474bd1e1DcDAeC4C58E359AaD85')
cy.url().should( cy.url().should(
'contain', 'contain',
'/remove/0xc778417E063141139Fce010982780140Aa0cD5Ab/0xF9bA5210F91D0474bd1e1DcDAeC4C58E359AaD85' '/remove/v2/0xc778417E063141139Fce010982780140Aa0cD5Ab/0xF9bA5210F91D0474bd1e1DcDAeC4C58E359AaD85'
) )
}) })
it('eth remove', () => { it('eth remove', () => {
cy.visit('/remove/ETH/0xF9bA5210F91D0474bd1e1DcDAeC4C58E359AaD85') cy.visit('/remove/v2/ETH/0xF9bA5210F91D0474bd1e1DcDAeC4C58E359AaD85')
cy.get('#remove-liquidity-tokena-symbol').should('contain.text', 'ETH') cy.get('#remove-liquidity-tokena-symbol').should('contain.text', 'ETH')
cy.get('#remove-liquidity-tokenb-symbol').should('contain.text', 'MKR') cy.get('#remove-liquidity-tokenb-symbol').should('contain.text', 'MKR')
}) })
it('eth remove swap order', () => { it('eth remove swap order', () => {
cy.visit('/remove/0xF9bA5210F91D0474bd1e1DcDAeC4C58E359AaD85/ETH') cy.visit('/remove/v2/0xF9bA5210F91D0474bd1e1DcDAeC4C58E359AaD85/ETH')
cy.get('#remove-liquidity-tokena-symbol').should('contain.text', 'MKR') cy.get('#remove-liquidity-tokena-symbol').should('contain.text', 'MKR')
cy.get('#remove-liquidity-tokenb-symbol').should('contain.text', 'ETH') cy.get('#remove-liquidity-tokenb-symbol').should('contain.text', 'ETH')
}) })
it('loads the two correct tokens', () => { it('loads the two correct tokens', () => {
cy.visit('/remove/0xc778417E063141139Fce010982780140Aa0cD5Ab-0xF9bA5210F91D0474bd1e1DcDAeC4C58E359AaD85') cy.visit('/remove/v2/0xc778417E063141139Fce010982780140Aa0cD5Ab-0xF9bA5210F91D0474bd1e1DcDAeC4C58E359AaD85')
cy.get('#remove-liquidity-tokena-symbol').should('contain.text', 'WETH') cy.get('#remove-liquidity-tokena-symbol').should('contain.text', 'WETH')
cy.get('#remove-liquidity-tokenb-symbol').should('contain.text', 'MKR') cy.get('#remove-liquidity-tokenb-symbol').should('contain.text', 'MKR')
}) })
it('does not crash if ETH is duplicated', () => { it('does not crash if ETH is duplicated', () => {
cy.visit('/remove/0xc778417E063141139Fce010982780140Aa0cD5Ab-0xc778417E063141139Fce010982780140Aa0cD5Ab') cy.visit('/remove/v2/0xc778417E063141139Fce010982780140Aa0cD5Ab-0xc778417E063141139Fce010982780140Aa0cD5Ab')
cy.get('#remove-liquidity-tokena-symbol').should('contain.text', 'WETH') cy.get('#remove-liquidity-tokena-symbol').should('contain.text', 'WETH')
cy.get('#remove-liquidity-tokenb-symbol').should('contain.text', 'WETH') cy.get('#remove-liquidity-tokenb-symbol').should('contain.text', 'WETH')
}) })
it('token not in storage is loaded', () => { it('token not in storage is loaded', () => {
cy.visit('/remove/0xb290b2f9f8f108d03ff2af3ac5c8de6de31cdf6d-0xF9bA5210F91D0474bd1e1DcDAeC4C58E359AaD85') cy.visit('/remove/v2/0xb290b2f9f8f108d03ff2af3ac5c8de6de31cdf6d-0xF9bA5210F91D0474bd1e1DcDAeC4C58E359AaD85')
cy.get('#remove-liquidity-tokena-symbol').should('contain.text', 'SKL') cy.get('#remove-liquidity-tokena-symbol').should('contain.text', 'SKL')
cy.get('#remove-liquidity-tokenb-symbol').should('contain.text', 'MKR') cy.get('#remove-liquidity-tokenb-symbol').should('contain.text', 'MKR')
}) })
......
...@@ -70,11 +70,11 @@ export function SwapPoolTabs({ active }: { active: 'swap' | 'pool' }) { ...@@ -70,11 +70,11 @@ export function SwapPoolTabs({ active }: { active: 'swap' | 'pool' }) {
) )
} }
export function FindPoolTabs() { export function FindPoolTabs({ origin }: { origin: string }) {
return ( return (
<Tabs> <Tabs>
<RowBetween style={{ padding: '1rem 1rem 0 1rem' }}> <RowBetween style={{ padding: '1rem 1rem 0 1rem' }}>
<HistoryLink to="/pool"> <HistoryLink to={origin}>
<StyledArrowLeft /> <StyledArrowLeft />
</HistoryLink> </HistoryLink>
<ActiveText>Import Pool</ActiveText> <ActiveText>Import Pool</ActiveText>
......
import React, { useState } from 'react'
import { Percent, TokenAmount } from '@uniswap/sdk-core'
import { JSBI, Pair } from '@uniswap/v2-sdk'
import { ChevronDown, ChevronUp } from 'react-feather'
import { Link } from 'react-router-dom'
import { Text } from 'rebass'
import styled from 'styled-components'
import { useTotalSupply } from '../../data/TotalSupply'
import { useActiveWeb3React } from '../../hooks'
import { useTokenBalance } from '../../state/wallet/hooks'
import { currencyId } from '../../utils/currencyId'
import { unwrappedToken } from '../../utils/wrappedCurrency'
import { ButtonPrimary, ButtonSecondary, ButtonEmpty } from '../Button'
import { transparentize } from 'polished'
import { CardNoise } from '../earn/styled'
import { useColor } from '../../hooks/useColor'
import { LightCard } from '../Card'
import { AutoColumn } from '../Column'
import CurrencyLogo from '../CurrencyLogo'
import DoubleCurrencyLogo from '../DoubleLogo'
import { RowBetween, RowFixed, AutoRow } from '../Row'
import { Dots } from '../swap/styleds'
import { BIG_INT_ZERO } from '../../constants'
import { FixedHeightRow } from '.'
const StyledPositionCard = styled(LightCard)<{ bgColor: any }>`
border: none;
background: ${({ theme, bgColor }) =>
`radial-gradient(91.85% 100% at 1.84% 0%, ${transparentize(0.8, bgColor)} 0%, ${theme.bg3} 100%) `};
position: relative;
overflow: hidden;
`
interface PositionCardProps {
pair: Pair
showUnwrapped?: boolean
border?: string
stakedBalance?: TokenAmount // optional balance to indicate that liquidity is deposited in mining pool
}
export default function V2PositionCard({ pair, border, stakedBalance }: PositionCardProps) {
const { account } = useActiveWeb3React()
const currency0 = unwrappedToken(pair.token0)
const currency1 = unwrappedToken(pair.token1)
const [showMore, setShowMore] = useState(false)
const userDefaultPoolBalance = useTokenBalance(account ?? undefined, pair.liquidityToken)
const totalPoolTokens = useTotalSupply(pair.liquidityToken)
// if staked balance balance provided, add to standard liquidity amount
const userPoolBalance = stakedBalance ? userDefaultPoolBalance?.add(stakedBalance) : userDefaultPoolBalance
const poolTokenPercentage =
!!userPoolBalance && !!totalPoolTokens && JSBI.greaterThanOrEqual(totalPoolTokens.raw, userPoolBalance.raw)
? new Percent(userPoolBalance.raw, totalPoolTokens.raw)
: undefined
const [token0Deposited, token1Deposited] =
!!pair &&
!!totalPoolTokens &&
!!userPoolBalance &&
// this condition is a short-circuit in the case where useTokenBalance updates sooner than useTotalSupply
JSBI.greaterThanOrEqual(totalPoolTokens.raw, userPoolBalance.raw)
? [
pair.getLiquidityValue(pair.token0, totalPoolTokens, userPoolBalance, false),
pair.getLiquidityValue(pair.token1, totalPoolTokens, userPoolBalance, false),
]
: [undefined, undefined]
const backgroundColor = useColor(pair?.token0)
return (
<StyledPositionCard border={border} bgColor={backgroundColor}>
<CardNoise />
<AutoColumn gap="12px">
<FixedHeightRow>
<AutoRow gap="8px">
<DoubleCurrencyLogo currency0={currency0} currency1={currency1} size={20} />
<Text fontWeight={500} fontSize={20}>
{!currency0 || !currency1 ? <Dots>Loading</Dots> : `${currency0.symbol}/${currency1.symbol}`}
</Text>
</AutoRow>
<RowFixed gap="8px">
<ButtonEmpty
padding="6px 8px"
borderRadius="12px"
width="fit-content"
onClick={() => setShowMore(!showMore)}
>
{showMore ? (
<>
Manage
<ChevronUp size="20" style={{ marginLeft: '10px' }} />
</>
) : (
<>
Manage
<ChevronDown size="20" style={{ marginLeft: '10px' }} />
</>
)}
</ButtonEmpty>
</RowFixed>
</FixedHeightRow>
{showMore && (
<AutoColumn gap="8px">
<FixedHeightRow>
<Text fontSize={16} fontWeight={500}>
Your total pool tokens:
</Text>
<Text fontSize={16} fontWeight={500}>
{userPoolBalance ? userPoolBalance.toSignificant(4) : '-'}
</Text>
</FixedHeightRow>
{stakedBalance && (
<FixedHeightRow>
<Text fontSize={16} fontWeight={500}>
Pool tokens in rewards pool:
</Text>
<Text fontSize={16} fontWeight={500}>
{stakedBalance.toSignificant(4)}
</Text>
</FixedHeightRow>
)}
<FixedHeightRow>
<RowFixed>
<Text fontSize={16} fontWeight={500}>
Pooled {currency0.symbol}:
</Text>
</RowFixed>
{token0Deposited ? (
<RowFixed>
<Text fontSize={16} fontWeight={500} marginLeft={'6px'}>
{token0Deposited?.toSignificant(6)}
</Text>
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={currency0} />
</RowFixed>
) : (
'-'
)}
</FixedHeightRow>
<FixedHeightRow>
<RowFixed>
<Text fontSize={16} fontWeight={500}>
Pooled {currency1.symbol}:
</Text>
</RowFixed>
{token1Deposited ? (
<RowFixed>
<Text fontSize={16} fontWeight={500} marginLeft={'6px'}>
{token1Deposited?.toSignificant(6)}
</Text>
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={currency1} />
</RowFixed>
) : (
'-'
)}
</FixedHeightRow>
<FixedHeightRow>
<Text fontSize={16} fontWeight={500}>
Your pool share:
</Text>
<Text fontSize={16} fontWeight={500}>
{poolTokenPercentage
? (poolTokenPercentage.toFixed(2) === '0.00' ? '<0.01' : poolTokenPercentage.toFixed(2)) + '%'
: '-'}
</Text>
</FixedHeightRow>
{userDefaultPoolBalance && JSBI.greaterThan(userDefaultPoolBalance.raw, BIG_INT_ZERO) && (
<RowBetween marginTop="10px">
<ButtonPrimary
padding="8px"
borderRadius="8px"
as={Link}
to={`/migrate/v2/${pair.liquidityToken.address}`}
width="64%"
>
Migrate
</ButtonPrimary>
<ButtonSecondary
padding="8px"
borderRadius="8px"
as={Link}
width="32%"
to={`/remove/v2/${currencyId(currency0)}/${currencyId(currency1)}`}
>
Remove
</ButtonSecondary>
</RowBetween>
)}
</AutoColumn>
)}
</AutoColumn>
</StyledPositionCard>
)
}
...@@ -317,7 +317,7 @@ export default function FullPositionCard({ pair, border, stakedBalance }: Positi ...@@ -317,7 +317,7 @@ export default function FullPositionCard({ pair, border, stakedBalance }: Positi
borderRadius="8px" borderRadius="8px"
as={Link} as={Link}
width="48%" width="48%"
to={`/remove/${currencyId(currency0)}/${currencyId(currency1)}`} to={`/remove/v2/${currencyId(currency0)}/${currencyId(currency1)}`}
> >
Remove Remove
</ButtonPrimary> </ButtonPrimary>
......
...@@ -47,7 +47,6 @@ export const COMMON_CONTRACT_NAMES: { [address: string]: string } = { ...@@ -47,7 +47,6 @@ export const COMMON_CONTRACT_NAMES: { [address: string]: string } = {
[TIMELOCK_ADDRESS]: 'Timelock', [TIMELOCK_ADDRESS]: 'Timelock',
} }
// TODO: specify merkle distributor for mainnet
export const MERKLE_DISTRIBUTOR_ADDRESS: { [chainId in ChainId]?: string } = { export const MERKLE_DISTRIBUTOR_ADDRESS: { [chainId in ChainId]?: string } = {
[ChainId.MAINNET]: '0x090D4613473dEE047c3f2706764f49E0821D256e', [ChainId.MAINNET]: '0x090D4613473dEE047c3f2706764f49E0821D256e',
} }
...@@ -217,4 +216,4 @@ export const BLOCKED_ADDRESSES: string[] = [ ...@@ -217,4 +216,4 @@ export const BLOCKED_ADDRESSES: string[] = [
export const ARGENT_WALLET_DETECTOR_MAINNET_ADDRESS = '0xeca4B0bDBf7c55E9b7925919d03CbF8Dc82537E8' export const ARGENT_WALLET_DETECTOR_MAINNET_ADDRESS = '0xeca4B0bDBf7c55E9b7925919d03CbF8Dc82537E8'
export const MIGRATOR_ADDRESS = '0x16D4F26C15f3658ec65B1126ff27DD3dF2a2996b' export const V1_MIGRATOR_ADDRESS = '0x16D4F26C15f3658ec65B1126ff27DD3dF2a2996b'
...@@ -4,7 +4,7 @@ export const FACTORY_ADDRESSES: { [chainId in ChainId]: string } = { ...@@ -4,7 +4,7 @@ export const FACTORY_ADDRESSES: { [chainId in ChainId]: string } = {
[ChainId.MAINNET]: '', [ChainId.MAINNET]: '',
[ChainId.ROPSTEN]: '', [ChainId.ROPSTEN]: '',
[ChainId.RINKEBY]: '', [ChainId.RINKEBY]: '',
[ChainId.GÖRLI]: '0x2e52A6ed50aeD4396BdC5889ACB9D04F6804D150', [ChainId.GÖRLI]: '0xb31b9A7b331eA8993bdfC67c650eDbfc9256eC62',
[ChainId.KOVAN]: '', [ChainId.KOVAN]: '',
} }
...@@ -12,7 +12,7 @@ export const TICK_LENS_ADDRESSES: { [chainId in ChainId]: string } = { ...@@ -12,7 +12,7 @@ export const TICK_LENS_ADDRESSES: { [chainId in ChainId]: string } = {
[ChainId.MAINNET]: '', [ChainId.MAINNET]: '',
[ChainId.ROPSTEN]: '', [ChainId.ROPSTEN]: '',
[ChainId.RINKEBY]: '', [ChainId.RINKEBY]: '',
[ChainId.GÖRLI]: '0x637df729C49f229B328445AB64573B726F6814dC', [ChainId.GÖRLI]: '0x8E984b597F19E8D0FDd0b5bAfDb1d0ae4386455f',
[ChainId.KOVAN]: '', [ChainId.KOVAN]: '',
} }
...@@ -20,7 +20,7 @@ export const NONFUNGIBLE_POSITION_MANAGER_ADDRESSES: { [chainId in ChainId]: str ...@@ -20,7 +20,7 @@ export const NONFUNGIBLE_POSITION_MANAGER_ADDRESSES: { [chainId in ChainId]: str
[ChainId.MAINNET]: '', [ChainId.MAINNET]: '',
[ChainId.ROPSTEN]: '', [ChainId.ROPSTEN]: '',
[ChainId.RINKEBY]: '', [ChainId.RINKEBY]: '',
[ChainId.GÖRLI]: '0x514A3562Bbf313B262A4d2377B559CDe75FAC3C9', [ChainId.GÖRLI]: '0x29e4bF3bFD649b807B4C752c01023E535094F6Bc',
[ChainId.KOVAN]: '', [ChainId.KOVAN]: '',
} }
...@@ -28,7 +28,7 @@ export const NONFUNGIBLE_TOKEN_POSITION_DESCRIPTOR_ADDRESSES: { [chainId in Chai ...@@ -28,7 +28,7 @@ export const NONFUNGIBLE_TOKEN_POSITION_DESCRIPTOR_ADDRESSES: { [chainId in Chai
[ChainId.MAINNET]: '', [ChainId.MAINNET]: '',
[ChainId.ROPSTEN]: '', [ChainId.ROPSTEN]: '',
[ChainId.RINKEBY]: '', [ChainId.RINKEBY]: '',
[ChainId.GÖRLI]: '0x2a3DB14c12674986f6F52deaD1d5ee0919715E8A', [ChainId.GÖRLI]: '0xa0588c89Fe967e66533aB1A0504C30989f90156f',
[ChainId.KOVAN]: '', [ChainId.KOVAN]: '',
} }
...@@ -36,6 +36,14 @@ export const SWAP_ROUTER_ADDRESSES: { [chainId in ChainId]: string } = { ...@@ -36,6 +36,14 @@ export const SWAP_ROUTER_ADDRESSES: { [chainId in ChainId]: string } = {
[ChainId.MAINNET]: '', [ChainId.MAINNET]: '',
[ChainId.ROPSTEN]: '', [ChainId.ROPSTEN]: '',
[ChainId.RINKEBY]: '', [ChainId.RINKEBY]: '',
[ChainId.GÖRLI]: '0x86e14633F8ab81FD49aEF388172A43A7C8731664', [ChainId.GÖRLI]: '0x71bB3d0e63f2Fa2A5d04d54267211f4Caef7062e',
[ChainId.KOVAN]: '',
}
export const V2_MIGRATOR_ADDRESSES: { [chainId in ChainId]: string } = {
[ChainId.MAINNET]: '',
[ChainId.ROPSTEN]: '',
[ChainId.RINKEBY]: '',
[ChainId.GÖRLI]: '0xee9e30637f84Bbf929042A9118c6E20023dab833',
[ChainId.KOVAN]: '', [ChainId.KOVAN]: '',
} }
...@@ -15,7 +15,7 @@ import { useUserSingleHopOnly } from 'state/user/hooks' ...@@ -15,7 +15,7 @@ import { useUserSingleHopOnly } from 'state/user/hooks'
function useAllCommonPairs(currencyA?: Currency, currencyB?: Currency): Pair[] { function useAllCommonPairs(currencyA?: Currency, currencyB?: Currency): Pair[] {
const { chainId } = useActiveWeb3React() const { chainId } = useActiveWeb3React()
const bases: Token[] = chainId ? BASES_TO_CHECK_TRADES_AGAINST[chainId] : [] const bases: Token[] = useMemo(() => (chainId ? BASES_TO_CHECK_TRADES_AGAINST[chainId] : []), [chainId])
const [tokenA, tokenB] = chainId const [tokenA, tokenB] = chainId
? [wrappedCurrency(currencyA, chainId), wrappedCurrency(currencyB, chainId)] ? [wrappedCurrency(currencyA, chainId), wrappedCurrency(currencyB, chainId)]
......
...@@ -22,7 +22,7 @@ import { ...@@ -22,7 +22,7 @@ import {
ARGENT_WALLET_DETECTOR_MAINNET_ADDRESS, ARGENT_WALLET_DETECTOR_MAINNET_ADDRESS,
GOVERNANCE_ADDRESS, GOVERNANCE_ADDRESS,
MERKLE_DISTRIBUTOR_ADDRESS, MERKLE_DISTRIBUTOR_ADDRESS,
MIGRATOR_ADDRESS, V1_MIGRATOR_ADDRESS,
UNI, UNI,
} from 'constants/index' } from 'constants/index'
import { MULTICALL_ABI, MULTICALL_NETWORKS } from 'constants/multicall' import { MULTICALL_ABI, MULTICALL_NETWORKS } from 'constants/multicall'
...@@ -54,8 +54,8 @@ export function useV1FactoryContract(): Contract | null { ...@@ -54,8 +54,8 @@ export function useV1FactoryContract(): Contract | null {
return useContract(chainId && V1_FACTORY_ADDRESSES[chainId], V1_FACTORY_ABI, false) return useContract(chainId && V1_FACTORY_ADDRESSES[chainId], V1_FACTORY_ABI, false)
} }
export function useV2MigratorContract(): Contract | null { export function useV1MigratorContract(): Contract | null {
return useContract(MIGRATOR_ADDRESS, MIGRATOR_ABI, true) return useContract(V1_MIGRATOR_ADDRESS, MIGRATOR_ABI, true)
} }
export function useV1ExchangeContract(address?: string, withSignerIfPossible?: boolean): Contract | null { export function useV1ExchangeContract(address?: string, withSignerIfPossible?: boolean): Contract | null {
......
...@@ -23,10 +23,12 @@ import MigrateV1 from './MigrateV1' ...@@ -23,10 +23,12 @@ import MigrateV1 from './MigrateV1'
import MigrateV1Exchange from './MigrateV1/MigrateV1Exchange' import MigrateV1Exchange from './MigrateV1/MigrateV1Exchange'
import RemoveV1Exchange from './MigrateV1/RemoveV1Exchange' import RemoveV1Exchange from './MigrateV1/RemoveV1Exchange'
import MigrateV2 from './MigrateV2' import MigrateV2 from './MigrateV2'
import MigrateV2Pair from './MigrateV2/MigrateV2Pair'
import Pool from './Pool' import Pool from './Pool'
import PoolV2 from './Pool/v2' import PoolV2 from './Pool/v2'
import PoolFinder from './PoolFinder' import PoolFinder from './PoolFinder'
import RemoveLiquidity from './RemoveLiquidity' import RemoveLiquidity from './RemoveLiquidity'
import RemoveLiquidityV3 from './RemoveLiquidity/V3'
import { RedirectOldRemoveLiquidityPathStructure } from './RemoveLiquidity/redirects' import { RedirectOldRemoveLiquidityPathStructure } from './RemoveLiquidity/redirects'
import Swap from './Swap' import Swap from './Swap'
import { OpenClaimAddressModalAndRedirectToSwap, RedirectPathToSwapOnly, RedirectToSwap } from './Swap/redirects' import { OpenClaimAddressModalAndRedirectToSwap, RedirectPathToSwapOnly, RedirectToSwap } from './Swap/redirects'
...@@ -93,15 +95,19 @@ export default function App() { ...@@ -93,15 +95,19 @@ export default function App() {
<TopLevelModals /> <TopLevelModals />
<Web3ReactManager> <Web3ReactManager>
<Switch> <Switch>
<Route exact strict path="/swap" component={Swap} /> <Route exact strict path="/vote" component={Vote} />
<Route exact strict path="/vote/:id" component={VotePage} />
<Route exact strict path="/claim" component={OpenClaimAddressModalAndRedirectToSwap} /> <Route exact strict path="/claim" component={OpenClaimAddressModalAndRedirectToSwap} />
<Route exact strict path="/swap/:outputCurrency" component={RedirectToSwap} /> <Route exact strict path="/uni" component={Earn} />
<Route exact strict path="/uni/:currencyIdA/:currencyIdB" component={Manage} />
<Route exact strict path="/send" component={RedirectPathToSwapOnly} /> <Route exact strict path="/send" component={RedirectPathToSwapOnly} />
<Route exact strict path="/swap/:outputCurrency" component={RedirectToSwap} />
<Route exact strict path="/swap" component={Swap} />
<Route exact strict path="/find" component={PoolFinder} /> <Route exact strict path="/find" component={PoolFinder} />
<Route exact strict path="/pool/v2" component={PoolV2} />
<Route exact strict path="/pool" component={Pool} /> <Route exact strict path="/pool" component={Pool} />
<Route exact strict path="/v2/pool" component={PoolV2} />
<Route exact strict path="/uni" component={Earn} />
<Route exact strict path="/vote" component={Vote} />
<Route exact strict path="/create" component={RedirectToAddLiquidity} /> <Route exact strict path="/create" component={RedirectToAddLiquidity} />
<Route exact path="/add" component={AddLiquidity} /> <Route exact path="/add" component={AddLiquidity} />
<Route exact path="/add/:currencyIdA" component={RedirectOldAddLiquidityPathStructure} /> <Route exact path="/add/:currencyIdA" component={RedirectOldAddLiquidityPathStructure} />
...@@ -110,13 +116,15 @@ export default function App() { ...@@ -110,13 +116,15 @@ export default function App() {
<Route exact path="/create/:currencyIdA" component={RedirectOldAddLiquidityPathStructure} /> <Route exact path="/create/:currencyIdA" component={RedirectOldAddLiquidityPathStructure} />
<Route exact path="/create/:currencyIdA/:currencyIdB" component={RedirectDuplicateTokenIds} /> <Route exact path="/create/:currencyIdA/:currencyIdB" component={RedirectDuplicateTokenIds} />
<Route exact strict path="/remove/v1/:address" component={RemoveV1Exchange} /> <Route exact strict path="/remove/v1/:address" component={RemoveV1Exchange} />
<Route exact strict path="/remove/:tokens" component={RedirectOldRemoveLiquidityPathStructure} /> <Route exact strict path="/remove/v2/:tokens" component={RedirectOldRemoveLiquidityPathStructure} />
<Route exact strict path="/remove/:currencyIdA/:currencyIdB" component={RemoveLiquidity} /> <Route exact strict path="/remove/v2/:currencyIdA/:currencyIdB" component={RemoveLiquidity} />
<Route exact strict path="/remove/:currencyIdA/:currencyIdB/:fee" component={RemoveLiquidityV3} />
<Route exact strict path="/migrate/v1" component={MigrateV1} /> <Route exact strict path="/migrate/v1" component={MigrateV1} />
<Route exact strict path="/migrate/v1/:address" component={MigrateV1Exchange} /> <Route exact strict path="/migrate/v1/:address" component={MigrateV1Exchange} />
<Route exact strict path="/migrate/v2" component={MigrateV2} /> <Route exact strict path="/migrate/v2" component={MigrateV2} />
<Route exact strict path="/uni/:currencyIdA/:currencyIdB" component={Manage} /> <Route exact strict path="/migrate/v2/:address" component={MigrateV2Pair} />
<Route exact strict path="/vote/:id" component={VotePage} />
<Route component={RedirectPathToSwapOnly} /> <Route component={RedirectPathToSwapOnly} />
</Switch> </Switch>
</Web3ReactManager> </Web3ReactManager>
......
...@@ -14,13 +14,13 @@ import FormattedCurrencyAmount from '../../components/FormattedCurrencyAmount' ...@@ -14,13 +14,13 @@ import FormattedCurrencyAmount from '../../components/FormattedCurrencyAmount'
import QuestionHelper from '../../components/QuestionHelper' import QuestionHelper from '../../components/QuestionHelper'
import { AutoRow, RowBetween, RowFixed } from '../../components/Row' import { AutoRow, RowBetween, RowFixed } from '../../components/Row'
import { Dots } from '../../components/swap/styleds' import { Dots } from '../../components/swap/styleds'
import { DEFAULT_DEADLINE_FROM_NOW, INITIAL_ALLOWED_SLIPPAGE, MIGRATOR_ADDRESS } from 'constants/index' import { DEFAULT_DEADLINE_FROM_NOW, INITIAL_ALLOWED_SLIPPAGE, V1_MIGRATOR_ADDRESS } from 'constants/index'
import { PairState, usePair } from '../../data/Reserves' import { PairState, usePair } from '../../data/Reserves'
import { useTotalSupply } from '../../data/TotalSupply' import { useTotalSupply } from '../../data/TotalSupply'
import { useActiveWeb3React } from '../../hooks' import { useActiveWeb3React } from '../../hooks'
import { useToken } from '../../hooks/Tokens' import { useToken } from '../../hooks/Tokens'
import { ApprovalState, useApproveCallback } from '../../hooks/useApproveCallback' import { ApprovalState, useApproveCallback } from '../../hooks/useApproveCallback'
import { useV1ExchangeContract, useV2MigratorContract } from '../../hooks/useContract' import { useV1ExchangeContract, useV1MigratorContract } from '../../hooks/useContract'
import { NEVER_RELOAD, useSingleCallResult } from '../../state/multicall/hooks' import { NEVER_RELOAD, useSingleCallResult } from '../../state/multicall/hooks'
import { useIsTransactionPending, useTransactionAdder } from '../../state/transactions/hooks' import { useIsTransactionPending, useTransactionAdder } from '../../state/transactions/hooks'
import { useETHBalances, useTokenBalance } from '../../state/wallet/hooks' import { useETHBalances, useTokenBalance } from '../../state/wallet/hooks'
...@@ -110,7 +110,7 @@ function V1PairMigration({ liquidityTokenAmount, token }: { liquidityTokenAmount ...@@ -110,7 +110,7 @@ function V1PairMigration({ liquidityTokenAmount, token }: { liquidityTokenAmount
? new TokenAmount(token, shareFraction.multiply(exchangeTokenBalance.raw).quotient) ? new TokenAmount(token, shareFraction.multiply(exchangeTokenBalance.raw).quotient)
: new TokenAmount(token, ZERO) : new TokenAmount(token, ZERO)
const [approval, approve] = useApproveCallback(liquidityTokenAmount, MIGRATOR_ADDRESS) const [approval, approve] = useApproveCallback(liquidityTokenAmount, V1_MIGRATOR_ADDRESS)
const v1SpotPrice = const v1SpotPrice =
exchangeTokenBalance && exchangeETHBalance exchangeTokenBalance && exchangeETHBalance
...@@ -140,7 +140,7 @@ function V1PairMigration({ liquidityTokenAmount, token }: { liquidityTokenAmount ...@@ -140,7 +140,7 @@ function V1PairMigration({ liquidityTokenAmount, token }: { liquidityTokenAmount
const addTransaction = useTransactionAdder() const addTransaction = useTransactionAdder()
const isMigrationPending = useIsTransactionPending(pendingMigrationHash ?? undefined) const isMigrationPending = useIsTransactionPending(pendingMigrationHash ?? undefined)
const migrator = useV2MigratorContract() const migrator = useV1MigratorContract()
const migrate = useCallback(() => { const migrate = useCallback(() => {
if (!minAmountToken || !minAmountETH || !migrator) return if (!minAmountToken || !minAmountETH || !migrator) return
...@@ -182,7 +182,7 @@ function V1PairMigration({ liquidityTokenAmount, token }: { liquidityTokenAmount ...@@ -182,7 +182,7 @@ function V1PairMigration({ liquidityTokenAmount, token }: { liquidityTokenAmount
This tool will safely migrate your V1 liquidity to V2 with minimal price risk. The process is completely This tool will safely migrate your V1 liquidity to V2 with minimal price risk. The process is completely
trustless thanks to the{' '} trustless thanks to the{' '}
{chainId && ( {chainId && (
<ExternalLink href={getEtherscanLink(chainId, MIGRATOR_ADDRESS, 'address')}> <ExternalLink href={getEtherscanLink(chainId, V1_MIGRATOR_ADDRESS, 'address')}>
<TYPE.blue display="inline">Uniswap migration contract↗</TYPE.blue> <TYPE.blue display="inline">Uniswap migration contract↗</TYPE.blue>
</ExternalLink> </ExternalLink>
)} )}
......
This diff is collapsed.
import React from 'react' import React, { useContext, useMemo } from 'react'
import { Pair } from '@uniswap/v2-sdk'
import { ThemeContext } from 'styled-components'
import { AutoColumn } from '../../components/Column'
import { AutoRow } from '../../components/Row'
import { Text } from 'rebass'
import { useActiveWeb3React } from '../../hooks'
import { useTokenBalancesWithLoadingIndicator } from '../../state/wallet/hooks'
import { BackArrow, StyledInternalLink, TYPE } from '../../theme'
import { LightCard } from '../../components/Card'
import { BodyWrapper } from '../AppBody' import { BodyWrapper } from '../AppBody'
import { EmptyState } from '../MigrateV1/EmptyState'
import QuestionHelper from '../../components/QuestionHelper'
import { Dots } from '../../components/swap/styleds'
import { toV2LiquidityToken, useTrackedTokenPairs } from '../../state/user/hooks'
import { usePairs } from 'data/Reserves'
import MigrateV2PositionCard from 'components/PositionCard/V2'
export default function MigrateV1() { // TODO there's a bug in loading where "No V2 Liquidity found" flashes
return <BodyWrapper style={{ padding: 24 }}>migrate v2 liquidity to v3</BodyWrapper> // TODO add support for more pairs
export default function MigrateV2() {
const theme = useContext(ThemeContext)
const { account } = useActiveWeb3React()
// fetch the user's balances of all tracked V2 LP tokens
const trackedTokenPairs = useTrackedTokenPairs()
const tokenPairsWithLiquidityTokens = useMemo(
() => trackedTokenPairs.map((tokens) => ({ liquidityToken: toV2LiquidityToken(tokens), tokens })),
[trackedTokenPairs]
)
const liquidityTokens = useMemo(() => tokenPairsWithLiquidityTokens.map((tpwlt) => tpwlt.liquidityToken), [
tokenPairsWithLiquidityTokens,
])
const [v2PairsBalances, fetchingV2PairBalances] = useTokenBalancesWithLoadingIndicator(
account ?? undefined,
liquidityTokens
)
// fetch the reserves for all V2 pools in which the user has a balance
const liquidityTokensWithBalances = useMemo(
() =>
tokenPairsWithLiquidityTokens.filter(({ liquidityToken }) =>
v2PairsBalances[liquidityToken.address]?.greaterThan('0')
),
[tokenPairsWithLiquidityTokens, v2PairsBalances]
)
const v2Pairs = usePairs(liquidityTokensWithBalances.map(({ tokens }) => tokens))
const v2IsLoading =
fetchingV2PairBalances || v2Pairs?.length < liquidityTokensWithBalances.length || v2Pairs?.some((V2Pair) => !V2Pair)
const allV2PairsWithLiquidity = v2Pairs.map(([, pair]) => pair).filter((v2Pair): v2Pair is Pair => Boolean(v2Pair))
return (
<BodyWrapper style={{ padding: 24 }}>
<AutoColumn gap="16px">
<AutoRow style={{ alignItems: 'center', justifyContent: 'space-between' }} gap="8px">
<BackArrow to="/pool" />
<TYPE.mediumHeader>Migrate V2 Liquidity</TYPE.mediumHeader>
<div>
<QuestionHelper text="Migrate your liquidity tokens from Uniswap V2 to Uniswap V3." />
</div>
</AutoRow>
<TYPE.body style={{ marginBottom: 8, fontWeight: 400 }}>
For each pool shown below, click migrate to remove your liquidity from Uniswap V2 and deposit it into Uniswap
V3.
</TYPE.body>
{!account ? (
<LightCard padding="40px">
<TYPE.body color={theme.text3} textAlign="center">
Connect to a wallet to view your V2 liquidity.
</TYPE.body>
</LightCard>
) : v2IsLoading ? (
<LightCard padding="40px">
<TYPE.body color={theme.text3} textAlign="center">
<Dots>Loading</Dots>
</TYPE.body>
</LightCard>
) : allV2PairsWithLiquidity?.length > 0 ? (
<>
{allV2PairsWithLiquidity.map((pair) => (
<MigrateV2PositionCard key={pair.liquidityToken.address} pair={pair} />
))}
</>
) : (
<EmptyState message="No V2 Liquidity found." />
)}
<AutoColumn justify={'center'} gap="md">
<Text textAlign="center" fontSize={14} style={{ padding: '.5rem 0 .5rem 0' }}>
{"Don't see a pool you joined?"}{' '}
<StyledInternalLink id="import-pool-link" to={'/find?origin=/migrate/v2'}>
{'Import it.'}
</StyledInternalLink>
</Text>
</AutoColumn>
</AutoColumn>
</BodyWrapper>
)
} }
...@@ -21,13 +21,20 @@ import AppBody from '../AppBody' ...@@ -21,13 +21,20 @@ import AppBody from '../AppBody'
import { Dots } from '../Pool/styleds' import { Dots } from '../Pool/styleds'
import { BlueCard } from '../../components/Card' import { BlueCard } from '../../components/Card'
import { TYPE } from '../../theme' import { TYPE } from '../../theme'
import { useLocation } from 'react-router'
enum Fields { enum Fields {
TOKEN0 = 0, TOKEN0 = 0,
TOKEN1 = 1, TOKEN1 = 1,
} }
function useQuery() {
return new URLSearchParams(useLocation().search)
}
export default function PoolFinder() { export default function PoolFinder() {
const query = useQuery()
const { account } = useActiveWeb3React() const { account } = useActiveWeb3React()
const [showSearch, setShowSearch] = useState<boolean>(false) const [showSearch, setShowSearch] = useState<boolean>(false)
...@@ -81,7 +88,7 @@ export default function PoolFinder() { ...@@ -81,7 +88,7 @@ export default function PoolFinder() {
return ( return (
<AppBody> <AppBody>
<FindPoolTabs /> <FindPoolTabs origin={query.get('origin') ?? '/pool'} />
<AutoColumn style={{ padding: '1rem' }} gap="md"> <AutoColumn style={{ padding: '1rem' }} gap="md">
<BlueCard> <BlueCard>
<AutoColumn gap="10px"> <AutoColumn gap="10px">
......
import React from 'react'
import { RouteComponentProps } from 'react-router'
import AppBody from '../AppBody'
// TODO
export default function RemoveLiquidityV3({
match: {
params: { currencyIdA, currencyIdB, fee },
},
}: RouteComponentProps<{ currencyIdA: string; currencyIdB: string; fee: string }>) {
return <AppBody>TODO</AppBody>
}
...@@ -439,9 +439,9 @@ export default function RemoveLiquidity({ ...@@ -439,9 +439,9 @@ export default function RemoveLiquidity({
const handleSelectCurrencyA = useCallback( const handleSelectCurrencyA = useCallback(
(currency: Currency) => { (currency: Currency) => {
if (currencyIdB && currencyId(currency) === currencyIdB) { if (currencyIdB && currencyId(currency) === currencyIdB) {
history.push(`/remove/${currencyId(currency)}/${currencyIdA}`) history.push(`/remove/v2/${currencyId(currency)}/${currencyIdA}`)
} else { } else {
history.push(`/remove/${currencyId(currency)}/${currencyIdB}`) history.push(`/remove/v2/${currencyId(currency)}/${currencyIdB}`)
} }
}, },
[currencyIdA, currencyIdB, history] [currencyIdA, currencyIdB, history]
...@@ -449,9 +449,9 @@ export default function RemoveLiquidity({ ...@@ -449,9 +449,9 @@ export default function RemoveLiquidity({
const handleSelectCurrencyB = useCallback( const handleSelectCurrencyB = useCallback(
(currency: Currency) => { (currency: Currency) => {
if (currencyIdA && currencyId(currency) === currencyIdA) { if (currencyIdA && currencyId(currency) === currencyIdA) {
history.push(`/remove/${currencyIdB}/${currencyId(currency)}`) history.push(`/remove/v2/${currencyIdB}/${currencyId(currency)}`)
} else { } else {
history.push(`/remove/${currencyIdA}/${currencyId(currency)}`) history.push(`/remove/v2/${currencyIdA}/${currencyId(currency)}`)
} }
}, },
[currencyIdA, currencyIdB, history] [currencyIdA, currencyIdB, history]
...@@ -573,7 +573,7 @@ export default function RemoveLiquidity({ ...@@ -573,7 +573,7 @@ export default function RemoveLiquidity({
<RowBetween style={{ justifyContent: 'flex-end' }}> <RowBetween style={{ justifyContent: 'flex-end' }}>
{oneCurrencyIsETH ? ( {oneCurrencyIsETH ? (
<StyledInternalLink <StyledInternalLink
to={`/remove/${currencyA === ETHER ? WETH9[chainId].address : currencyIdA}/${ to={`/remove/v2/${currencyA === ETHER ? WETH9[chainId].address : currencyIdA}/${
currencyB === ETHER ? WETH9[chainId].address : currencyIdB currencyB === ETHER ? WETH9[chainId].address : currencyIdB
}`} }`}
> >
...@@ -581,7 +581,7 @@ export default function RemoveLiquidity({ ...@@ -581,7 +581,7 @@ export default function RemoveLiquidity({
</StyledInternalLink> </StyledInternalLink>
) : oneCurrencyIsWETH ? ( ) : oneCurrencyIsWETH ? (
<StyledInternalLink <StyledInternalLink
to={`/remove/${ to={`/remove/v2/${
currencyA && currencyEquals(currencyA, WETH9[chainId]) ? 'ETH' : currencyIdA currencyA && currencyEquals(currencyA, WETH9[chainId]) ? 'ETH' : currencyIdA
}/${currencyB && currencyEquals(currencyB, WETH9[chainId]) ? 'ETH' : currencyIdB}`} }/${currencyB && currencyEquals(currencyB, WETH9[chainId]) ? 'ETH' : currencyIdB}`}
> >
......
...@@ -9,9 +9,9 @@ export function RedirectOldRemoveLiquidityPathStructure({ ...@@ -9,9 +9,9 @@ export function RedirectOldRemoveLiquidityPathStructure({
}, },
}: RouteComponentProps<{ tokens: string }>) { }: RouteComponentProps<{ tokens: string }>) {
if (!OLD_PATH_STRUCTURE.test(tokens)) { if (!OLD_PATH_STRUCTURE.test(tokens)) {
return <Redirect to="/pool" /> return <Redirect to="/pool/v2" />
} }
const [currency0, currency1] = tokens.split('-') const [currency0, currency1] = tokens.split('-')
return <Redirect to={`/remove/${currency0}/${currency1}`} /> return <Redirect to={`/remove/v2/${currency0}/${currency1}`} />
} }
...@@ -8,7 +8,7 @@ import { ethers, utils } from 'ethers' ...@@ -8,7 +8,7 @@ import { ethers, utils } from 'ethers'
import { calculateGasMargin } from '../../utils' import { calculateGasMargin } from '../../utils'
import { TransactionResponse } from '@ethersproject/providers' import { TransactionResponse } from '@ethersproject/providers'
import { useTransactionAdder } from '../transactions/hooks' import { useTransactionAdder } from '../transactions/hooks'
import { useState, useEffect, useCallback } from 'react' import { useState, useEffect, useCallback, useMemo } from 'react'
import { abi as GOV_ABI } from '@uniswap/governance/build/GovernorAlpha.json' import { abi as GOV_ABI } from '@uniswap/governance/build/GovernorAlpha.json'
interface ProposalDetail { interface ProposalDetail {
...@@ -49,14 +49,16 @@ export function useProposalCount(): number | undefined { ...@@ -49,14 +49,16 @@ export function useProposalCount(): number | undefined {
* Need proposal events to get description data emitted from * Need proposal events to get description data emitted from
* new proposal event. * new proposal event.
*/ */
const eventParser = new ethers.utils.Interface(GOV_ABI)
export function useDataFromEventLogs() { export function useDataFromEventLogs() {
const { library } = useActiveWeb3React() const { library } = useActiveWeb3React()
const [formattedEvents, setFormattedEvents] = useState<any>() const [formattedEvents, setFormattedEvents] = useState<any>()
const govContract = useGovernanceContract() const govContract = useGovernanceContract()
// create filter for these specific events // create filter for these specific events
const filter = { ...govContract?.filters?.['ProposalCreated'](), fromBlock: 0, toBlock: 'latest' } const filter = useMemo(() => ({ ...govContract?.filters?.['ProposalCreated'](), fromBlock: 0, toBlock: 'latest' }), [
const eventParser = new ethers.utils.Interface(GOV_ABI) govContract,
])
useEffect(() => { useEffect(() => {
async function fetchData() { async function fetchData() {
...@@ -88,7 +90,7 @@ export function useDataFromEventLogs() { ...@@ -88,7 +90,7 @@ export function useDataFromEventLogs() {
if (!formattedEvents) { if (!formattedEvents) {
fetchData() fetchData()
} }
}, [eventParser, filter, library, formattedEvents]) }, [filter, library, formattedEvents])
return formattedEvents return formattedEvents
} }
......
...@@ -13,7 +13,6 @@ export const STAKING_GENESIS = 1600387200 ...@@ -13,7 +13,6 @@ export const STAKING_GENESIS = 1600387200
export const REWARDS_DURATION_DAYS = 60 export const REWARDS_DURATION_DAYS = 60
// TODO add staking rewards addresses here
export const STAKING_REWARDS_INFO: { export const STAKING_REWARDS_INFO: {
[chainId in ChainId]?: { [chainId in ChainId]?: {
tokens: [Token, Token] tokens: [Token, Token]
......
import { useEffect } from 'react' import { useEffect, useMemo } from 'react'
import { useDispatch, useSelector } from 'react-redux' import { useDispatch, useSelector } from 'react-redux'
import { useActiveWeb3React } from '../../hooks' import { useActiveWeb3React } from '../../hooks'
import { useAddPopup, useBlockNumber } from '../application/hooks' import { useAddPopup, useBlockNumber } from '../application/hooks'
...@@ -37,7 +37,7 @@ export default function Updater(): null { ...@@ -37,7 +37,7 @@ export default function Updater(): null {
const dispatch = useDispatch<AppDispatch>() const dispatch = useDispatch<AppDispatch>()
const state = useSelector<AppState, AppState['transactions']>((state) => state.transactions) const state = useSelector<AppState, AppState['transactions']>((state) => state.transactions)
const transactions = chainId ? state[chainId] ?? {} : {} const transactions = useMemo(() => (chainId ? state[chainId] ?? {} : {}), [chainId, state])
// show popup on confirm // show popup on confirm
const addPopup = useAddPopup() const addPopup = useAddPopup()
......
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