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', () => {
it('redirects', () => {
cy.visit('/remove/0xc778417E063141139Fce010982780140Aa0cD5Ab-0xF9bA5210F91D0474bd1e1DcDAeC4C58E359AaD85')
cy.visit('/remove/v2/0xc778417E063141139Fce010982780140Aa0cD5Ab-0xF9bA5210F91D0474bd1e1DcDAeC4C58E359AaD85')
cy.url().should(
'contain',
'/remove/0xc778417E063141139Fce010982780140Aa0cD5Ab/0xF9bA5210F91D0474bd1e1DcDAeC4C58E359AaD85'
'/remove/v2/0xc778417E063141139Fce010982780140Aa0cD5Ab/0xF9bA5210F91D0474bd1e1DcDAeC4C58E359AaD85'
)
})
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-tokenb-symbol').should('contain.text', 'MKR')
})
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-tokenb-symbol').should('contain.text', 'ETH')
})
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-tokenb-symbol').should('contain.text', 'MKR')
})
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-tokenb-symbol').should('contain.text', 'WETH')
})
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-tokenb-symbol').should('contain.text', 'MKR')
})
......
......@@ -70,11 +70,11 @@ export function SwapPoolTabs({ active }: { active: 'swap' | 'pool' }) {
)
}
export function FindPoolTabs() {
export function FindPoolTabs({ origin }: { origin: string }) {
return (
<Tabs>
<RowBetween style={{ padding: '1rem 1rem 0 1rem' }}>
<HistoryLink to="/pool">
<HistoryLink to={origin}>
<StyledArrowLeft />
</HistoryLink>
<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
borderRadius="8px"
as={Link}
width="48%"
to={`/remove/${currencyId(currency0)}/${currencyId(currency1)}`}
to={`/remove/v2/${currencyId(currency0)}/${currencyId(currency1)}`}
>
Remove
</ButtonPrimary>
......
......@@ -47,7 +47,6 @@ export const COMMON_CONTRACT_NAMES: { [address: string]: string } = {
[TIMELOCK_ADDRESS]: 'Timelock',
}
// TODO: specify merkle distributor for mainnet
export const MERKLE_DISTRIBUTOR_ADDRESS: { [chainId in ChainId]?: string } = {
[ChainId.MAINNET]: '0x090D4613473dEE047c3f2706764f49E0821D256e',
}
......@@ -217,4 +216,4 @@ export const BLOCKED_ADDRESSES: string[] = [
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 } = {
[ChainId.MAINNET]: '',
[ChainId.ROPSTEN]: '',
[ChainId.RINKEBY]: '',
[ChainId.GÖRLI]: '0x2e52A6ed50aeD4396BdC5889ACB9D04F6804D150',
[ChainId.GÖRLI]: '0xb31b9A7b331eA8993bdfC67c650eDbfc9256eC62',
[ChainId.KOVAN]: '',
}
......@@ -12,7 +12,7 @@ export const TICK_LENS_ADDRESSES: { [chainId in ChainId]: string } = {
[ChainId.MAINNET]: '',
[ChainId.ROPSTEN]: '',
[ChainId.RINKEBY]: '',
[ChainId.GÖRLI]: '0x637df729C49f229B328445AB64573B726F6814dC',
[ChainId.GÖRLI]: '0x8E984b597F19E8D0FDd0b5bAfDb1d0ae4386455f',
[ChainId.KOVAN]: '',
}
......@@ -20,7 +20,7 @@ export const NONFUNGIBLE_POSITION_MANAGER_ADDRESSES: { [chainId in ChainId]: str
[ChainId.MAINNET]: '',
[ChainId.ROPSTEN]: '',
[ChainId.RINKEBY]: '',
[ChainId.GÖRLI]: '0x514A3562Bbf313B262A4d2377B559CDe75FAC3C9',
[ChainId.GÖRLI]: '0x29e4bF3bFD649b807B4C752c01023E535094F6Bc',
[ChainId.KOVAN]: '',
}
......@@ -28,7 +28,7 @@ export const NONFUNGIBLE_TOKEN_POSITION_DESCRIPTOR_ADDRESSES: { [chainId in Chai
[ChainId.MAINNET]: '',
[ChainId.ROPSTEN]: '',
[ChainId.RINKEBY]: '',
[ChainId.GÖRLI]: '0x2a3DB14c12674986f6F52deaD1d5ee0919715E8A',
[ChainId.GÖRLI]: '0xa0588c89Fe967e66533aB1A0504C30989f90156f',
[ChainId.KOVAN]: '',
}
......@@ -36,6 +36,14 @@ export const SWAP_ROUTER_ADDRESSES: { [chainId in ChainId]: string } = {
[ChainId.MAINNET]: '',
[ChainId.ROPSTEN]: '',
[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]: '',
}
......@@ -15,7 +15,7 @@ import { useUserSingleHopOnly } from 'state/user/hooks'
function useAllCommonPairs(currencyA?: Currency, currencyB?: Currency): Pair[] {
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
? [wrappedCurrency(currencyA, chainId), wrappedCurrency(currencyB, chainId)]
......
......@@ -22,7 +22,7 @@ import {
ARGENT_WALLET_DETECTOR_MAINNET_ADDRESS,
GOVERNANCE_ADDRESS,
MERKLE_DISTRIBUTOR_ADDRESS,
MIGRATOR_ADDRESS,
V1_MIGRATOR_ADDRESS,
UNI,
} from 'constants/index'
import { MULTICALL_ABI, MULTICALL_NETWORKS } from 'constants/multicall'
......@@ -54,8 +54,8 @@ export function useV1FactoryContract(): Contract | null {
return useContract(chainId && V1_FACTORY_ADDRESSES[chainId], V1_FACTORY_ABI, false)
}
export function useV2MigratorContract(): Contract | null {
return useContract(MIGRATOR_ADDRESS, MIGRATOR_ABI, true)
export function useV1MigratorContract(): Contract | null {
return useContract(V1_MIGRATOR_ADDRESS, MIGRATOR_ABI, true)
}
export function useV1ExchangeContract(address?: string, withSignerIfPossible?: boolean): Contract | null {
......
......@@ -23,10 +23,12 @@ import MigrateV1 from './MigrateV1'
import MigrateV1Exchange from './MigrateV1/MigrateV1Exchange'
import RemoveV1Exchange from './MigrateV1/RemoveV1Exchange'
import MigrateV2 from './MigrateV2'
import MigrateV2Pair from './MigrateV2/MigrateV2Pair'
import Pool from './Pool'
import PoolV2 from './Pool/v2'
import PoolFinder from './PoolFinder'
import RemoveLiquidity from './RemoveLiquidity'
import RemoveLiquidityV3 from './RemoveLiquidity/V3'
import { RedirectOldRemoveLiquidityPathStructure } from './RemoveLiquidity/redirects'
import Swap from './Swap'
import { OpenClaimAddressModalAndRedirectToSwap, RedirectPathToSwapOnly, RedirectToSwap } from './Swap/redirects'
......@@ -93,15 +95,19 @@ export default function App() {
<TopLevelModals />
<Web3ReactManager>
<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="/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="/swap/:outputCurrency" component={RedirectToSwap} />
<Route exact strict path="/swap" component={Swap} />
<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="/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 path="/add" component={AddLiquidity} />
<Route exact path="/add/:currencyIdA" component={RedirectOldAddLiquidityPathStructure} />
......@@ -110,13 +116,15 @@ export default function App() {
<Route exact path="/create/:currencyIdA" component={RedirectOldAddLiquidityPathStructure} />
<Route exact path="/create/:currencyIdA/:currencyIdB" component={RedirectDuplicateTokenIds} />
<Route exact strict path="/remove/v1/:address" component={RemoveV1Exchange} />
<Route exact strict path="/remove/:tokens" component={RedirectOldRemoveLiquidityPathStructure} />
<Route exact strict path="/remove/:currencyIdA/:currencyIdB" component={RemoveLiquidity} />
<Route exact strict path="/remove/v2/:tokens" component={RedirectOldRemoveLiquidityPathStructure} />
<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/:address" component={MigrateV1Exchange} />
<Route exact strict path="/migrate/v2" component={MigrateV2} />
<Route exact strict path="/uni/:currencyIdA/:currencyIdB" component={Manage} />
<Route exact strict path="/vote/:id" component={VotePage} />
<Route exact strict path="/migrate/v2/:address" component={MigrateV2Pair} />
<Route component={RedirectPathToSwapOnly} />
</Switch>
</Web3ReactManager>
......
......@@ -14,13 +14,13 @@ import FormattedCurrencyAmount from '../../components/FormattedCurrencyAmount'
import QuestionHelper from '../../components/QuestionHelper'
import { AutoRow, RowBetween, RowFixed } from '../../components/Row'
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 { useTotalSupply } from '../../data/TotalSupply'
import { useActiveWeb3React } from '../../hooks'
import { useToken } from '../../hooks/Tokens'
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 { useIsTransactionPending, useTransactionAdder } from '../../state/transactions/hooks'
import { useETHBalances, useTokenBalance } from '../../state/wallet/hooks'
......@@ -110,7 +110,7 @@ function V1PairMigration({ liquidityTokenAmount, token }: { liquidityTokenAmount
? new TokenAmount(token, shareFraction.multiply(exchangeTokenBalance.raw).quotient)
: new TokenAmount(token, ZERO)
const [approval, approve] = useApproveCallback(liquidityTokenAmount, MIGRATOR_ADDRESS)
const [approval, approve] = useApproveCallback(liquidityTokenAmount, V1_MIGRATOR_ADDRESS)
const v1SpotPrice =
exchangeTokenBalance && exchangeETHBalance
......@@ -140,7 +140,7 @@ function V1PairMigration({ liquidityTokenAmount, token }: { liquidityTokenAmount
const addTransaction = useTransactionAdder()
const isMigrationPending = useIsTransactionPending(pendingMigrationHash ?? undefined)
const migrator = useV2MigratorContract()
const migrator = useV1MigratorContract()
const migrate = useCallback(() => {
if (!minAmountToken || !minAmountETH || !migrator) return
......@@ -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
trustless thanks to the{' '}
{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>
</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 { 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() {
return <BodyWrapper style={{ padding: 24 }}>migrate v2 liquidity to v3</BodyWrapper>
// TODO there's a bug in loading where "No V2 Liquidity found" flashes
// 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'
import { Dots } from '../Pool/styleds'
import { BlueCard } from '../../components/Card'
import { TYPE } from '../../theme'
import { useLocation } from 'react-router'
enum Fields {
TOKEN0 = 0,
TOKEN1 = 1,
}
function useQuery() {
return new URLSearchParams(useLocation().search)
}
export default function PoolFinder() {
const query = useQuery()
const { account } = useActiveWeb3React()
const [showSearch, setShowSearch] = useState<boolean>(false)
......@@ -81,7 +88,7 @@ export default function PoolFinder() {
return (
<AppBody>
<FindPoolTabs />
<FindPoolTabs origin={query.get('origin') ?? '/pool'} />
<AutoColumn style={{ padding: '1rem' }} gap="md">
<BlueCard>
<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({
const handleSelectCurrencyA = useCallback(
(currency: Currency) => {
if (currencyIdB && currencyId(currency) === currencyIdB) {
history.push(`/remove/${currencyId(currency)}/${currencyIdA}`)
history.push(`/remove/v2/${currencyId(currency)}/${currencyIdA}`)
} else {
history.push(`/remove/${currencyId(currency)}/${currencyIdB}`)
history.push(`/remove/v2/${currencyId(currency)}/${currencyIdB}`)
}
},
[currencyIdA, currencyIdB, history]
......@@ -449,9 +449,9 @@ export default function RemoveLiquidity({
const handleSelectCurrencyB = useCallback(
(currency: Currency) => {
if (currencyIdA && currencyId(currency) === currencyIdA) {
history.push(`/remove/${currencyIdB}/${currencyId(currency)}`)
history.push(`/remove/v2/${currencyIdB}/${currencyId(currency)}`)
} else {
history.push(`/remove/${currencyIdA}/${currencyId(currency)}`)
history.push(`/remove/v2/${currencyIdA}/${currencyId(currency)}`)
}
},
[currencyIdA, currencyIdB, history]
......@@ -573,7 +573,7 @@ export default function RemoveLiquidity({
<RowBetween style={{ justifyContent: 'flex-end' }}>
{oneCurrencyIsETH ? (
<StyledInternalLink
to={`/remove/${currencyA === ETHER ? WETH9[chainId].address : currencyIdA}/${
to={`/remove/v2/${currencyA === ETHER ? WETH9[chainId].address : currencyIdA}/${
currencyB === ETHER ? WETH9[chainId].address : currencyIdB
}`}
>
......@@ -581,7 +581,7 @@ export default function RemoveLiquidity({
</StyledInternalLink>
) : oneCurrencyIsWETH ? (
<StyledInternalLink
to={`/remove/${
to={`/remove/v2/${
currencyA && currencyEquals(currencyA, WETH9[chainId]) ? 'ETH' : currencyIdA
}/${currencyB && currencyEquals(currencyB, WETH9[chainId]) ? 'ETH' : currencyIdB}`}
>
......
......@@ -9,9 +9,9 @@ export function RedirectOldRemoveLiquidityPathStructure({
},
}: RouteComponentProps<{ tokens: string }>) {
if (!OLD_PATH_STRUCTURE.test(tokens)) {
return <Redirect to="/pool" />
return <Redirect to="/pool/v2" />
}
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'
import { calculateGasMargin } from '../../utils'
import { TransactionResponse } from '@ethersproject/providers'
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'
interface ProposalDetail {
......@@ -49,14 +49,16 @@ export function useProposalCount(): number | undefined {
* Need proposal events to get description data emitted from
* new proposal event.
*/
const eventParser = new ethers.utils.Interface(GOV_ABI)
export function useDataFromEventLogs() {
const { library } = useActiveWeb3React()
const [formattedEvents, setFormattedEvents] = useState<any>()
const govContract = useGovernanceContract()
// create filter for these specific events
const filter = { ...govContract?.filters?.['ProposalCreated'](), fromBlock: 0, toBlock: 'latest' }
const eventParser = new ethers.utils.Interface(GOV_ABI)
const filter = useMemo(() => ({ ...govContract?.filters?.['ProposalCreated'](), fromBlock: 0, toBlock: 'latest' }), [
govContract,
])
useEffect(() => {
async function fetchData() {
......@@ -88,7 +90,7 @@ export function useDataFromEventLogs() {
if (!formattedEvents) {
fetchData()
}
}, [eventParser, filter, library, formattedEvents])
}, [filter, library, formattedEvents])
return formattedEvents
}
......
......@@ -13,7 +13,6 @@ export const STAKING_GENESIS = 1600387200
export const REWARDS_DURATION_DAYS = 60
// TODO add staking rewards addresses here
export const STAKING_REWARDS_INFO: {
[chainId in ChainId]?: {
tokens: [Token, Token]
......
import { useEffect } from 'react'
import { useEffect, useMemo } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { useActiveWeb3React } from '../../hooks'
import { useAddPopup, useBlockNumber } from '../application/hooks'
......@@ -37,7 +37,7 @@ export default function Updater(): null {
const dispatch = useDispatch<AppDispatch>()
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
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