Finish migration (#42)
* start migration (wip) abstract some add liquidity components bump deploy version * add slippage params
This commit is contained in:
parent
9f5584c37d
commit
9fc096d091
@ -48,8 +48,8 @@
|
||||
"@uniswap/v2-core": "1.0.0",
|
||||
"@uniswap/v2-periphery": "^1.1.0-beta.0",
|
||||
"@uniswap/v2-sdk": "^1.0.6",
|
||||
"@uniswap/v3-core": "^1.0.0-rc.0",
|
||||
"@uniswap/v3-periphery": "^1.0.0-beta.17",
|
||||
"@uniswap/v3-core": "^1.0.0-rc.1",
|
||||
"@uniswap/v3-periphery": "^1.0.0-beta.19",
|
||||
"@uniswap/v3-sdk": "^1.0.0-alpha.11",
|
||||
"@web3-react/core": "^6.0.9",
|
||||
"@web3-react/fortmatic-connector": "^6.0.9",
|
||||
|
@ -109,7 +109,6 @@
|
||||
"poolType": "Select a fee tier based on your preferred liquidity provider fee.",
|
||||
"rangeWarning": "Your liquidity will only be active and earning fees when the rate of the pool is within this price range.",
|
||||
"chooseLiquidityAmount": "Choose an amount of tokens to open this liquidity position. If you don’t have enough tokens you can trade for them with a Swap.",
|
||||
"selectRange": "Select Liquidity Range",
|
||||
"inputTokenDynamic": "Input {{label}}",
|
||||
"selectStartingPrice": "Select Starting Price",
|
||||
"newPoolPrice": "Select the market rate for the tokens being added."
|
||||
|
@ -2,48 +2,48 @@ import { ChainId } from '@uniswap/sdk-core'
|
||||
|
||||
export const FACTORY_ADDRESSES: { [chainId in ChainId]: string } = {
|
||||
[ChainId.MAINNET]: '',
|
||||
[ChainId.ROPSTEN]: '0xb31b9A7b331eA8993bdfC67c650eDbfc9256eC62',
|
||||
[ChainId.RINKEBY]: '0xD8A6adFB40Ba3B3CdA9F985BF1fdbDc0c1d7591e',
|
||||
[ChainId.GÖRLI]: '0xb31b9A7b331eA8993bdfC67c650eDbfc9256eC62',
|
||||
[ChainId.ROPSTEN]: '0x5BbFe6FF864718cD1cE0F126be99e96239E3caDD',
|
||||
[ChainId.RINKEBY]: '0x7ba6C6345E7a73cC0D41d762C7Db9cb3DB721396',
|
||||
[ChainId.GÖRLI]: '0x5BbFe6FF864718cD1cE0F126be99e96239E3caDD',
|
||||
[ChainId.KOVAN]: '',
|
||||
}
|
||||
|
||||
export const TICK_LENS_ADDRESSES: { [chainId in ChainId]: string } = {
|
||||
[ChainId.MAINNET]: '',
|
||||
[ChainId.ROPSTEN]: '0x8E984b597F19E8D0FDd0b5bAfDb1d0ae4386455f',
|
||||
[ChainId.RINKEBY]: '0xB1c59e8Ae4B72f63a5a9CB9c25A9253096A4b126',
|
||||
[ChainId.GÖRLI]: '0x8E984b597F19E8D0FDd0b5bAfDb1d0ae4386455f',
|
||||
[ChainId.ROPSTEN]: '0x1C8beBE5596b60A84e6d737229aDd502E14276Eb',
|
||||
[ChainId.RINKEBY]: '0xd4013a706fa79487989b595Df35eF8AD1ffBb422',
|
||||
[ChainId.GÖRLI]: '0x1C8beBE5596b60A84e6d737229aDd502E14276Eb',
|
||||
[ChainId.KOVAN]: '',
|
||||
}
|
||||
|
||||
export const NONFUNGIBLE_POSITION_MANAGER_ADDRESSES: { [chainId in ChainId]: string } = {
|
||||
[ChainId.MAINNET]: '',
|
||||
[ChainId.ROPSTEN]: '0x29e4bF3bFD649b807B4C752c01023E535094F6Bc',
|
||||
[ChainId.RINKEBY]: '0xee9e30637f84Bbf929042A9118c6E20023dab833',
|
||||
[ChainId.GÖRLI]: '0x29e4bF3bFD649b807B4C752c01023E535094F6Bc',
|
||||
[ChainId.ROPSTEN]: '0x921647f0c094e2e59CDE6DEfafD77743012f52bd',
|
||||
[ChainId.RINKEBY]: '0x30Ba713F78Ad3c175a25aD767e3f423549Ac2D65',
|
||||
[ChainId.GÖRLI]: '0x921647f0c094e2e59CDE6DEfafD77743012f52bd',
|
||||
[ChainId.KOVAN]: '',
|
||||
}
|
||||
|
||||
export const NONFUNGIBLE_TOKEN_POSITION_DESCRIPTOR_ADDRESSES: { [chainId in ChainId]: string } = {
|
||||
[ChainId.MAINNET]: '',
|
||||
[ChainId.ROPSTEN]: '0xa0588c89Fe967e66533aB1A0504C30989f90156f',
|
||||
[ChainId.RINKEBY]: '0x3431b9Ed12e3204bC6f7039e1c576417B70fdD67',
|
||||
[ChainId.GÖRLI]: '0xa0588c89Fe967e66533aB1A0504C30989f90156f',
|
||||
[ChainId.ROPSTEN]: '0xD2AAa0217a203d9FaB6e5272b211Be2Aba52f385',
|
||||
[ChainId.RINKEBY]: '0xAc03019C975F5e79215FeDAB4a1DC30Af3E478F2',
|
||||
[ChainId.GÖRLI]: '0xD2AAa0217a203d9FaB6e5272b211Be2Aba52f385',
|
||||
[ChainId.KOVAN]: '',
|
||||
}
|
||||
|
||||
export const SWAP_ROUTER_ADDRESSES: { [chainId in ChainId]: string } = {
|
||||
[ChainId.MAINNET]: '',
|
||||
[ChainId.ROPSTEN]: '0x71bB3d0e63f2Fa2A5d04d54267211f4Caef7062e',
|
||||
[ChainId.RINKEBY]: '0xa0588c89Fe967e66533aB1A0504C30989f90156f',
|
||||
[ChainId.GÖRLI]: '0x71bB3d0e63f2Fa2A5d04d54267211f4Caef7062e',
|
||||
[ChainId.ROPSTEN]: '0xDD1B8aA26ac2330e39f8B291eA1E6a82A40E65C4',
|
||||
[ChainId.RINKEBY]: '0xD2AAa0217a203d9FaB6e5272b211Be2Aba52f385',
|
||||
[ChainId.GÖRLI]: '0xDD1B8aA26ac2330e39f8B291eA1E6a82A40E65C4',
|
||||
[ChainId.KOVAN]: '',
|
||||
}
|
||||
|
||||
export const V2_MIGRATOR_ADDRESSES: { [chainId in ChainId]: string } = {
|
||||
[ChainId.MAINNET]: '',
|
||||
[ChainId.ROPSTEN]: '',
|
||||
[ChainId.RINKEBY]: '0xb31b9A7b331eA8993bdfC67c650eDbfc9256eC62',
|
||||
[ChainId.GÖRLI]: '0xee9e30637f84Bbf929042A9118c6E20023dab833',
|
||||
[ChainId.ROPSTEN]: '0x30Ba713F78Ad3c175a25aD767e3f423549Ac2D65',
|
||||
[ChainId.RINKEBY]: '0x864e344eCd7f3a9A4368dEC11Be8104db5770364',
|
||||
[ChainId.GÖRLI]: '0x30Ba713F78Ad3c175a25aD767e3f423549Ac2D65',
|
||||
[ChainId.KOVAN]: '',
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import { ChainId, WETH9 } from '@uniswap/sdk-core'
|
||||
import { abi as IUniswapV2PairABI } from '@uniswap/v2-core/build/IUniswapV2Pair.json'
|
||||
import { abi as V3FactoryABI } from '@uniswap/v3-core/artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json'
|
||||
import { abi as V3PoolABI } from '@uniswap/v3-core/artifacts/contracts/UniswapV3Pool.sol/UniswapV3Pool.json'
|
||||
import { abi as V2MigratorABI } from '@uniswap/v3-periphery/artifacts/contracts/V3Migrator.sol/V3Migrator.json'
|
||||
import { abi as TickLensABI } from '@uniswap/v3-periphery/artifacts/contracts/lens/TickLens.sol/TickLens.json'
|
||||
|
||||
import ARGENT_WALLET_DETECTOR_ABI from 'abis/argent-wallet-detector.json'
|
||||
@ -29,10 +30,16 @@ import {
|
||||
} from 'constants/index'
|
||||
import { abi as NFTPositionManagerABI } from '@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json'
|
||||
import { V1_EXCHANGE_ABI, V1_FACTORY_ABI, V1_FACTORY_ADDRESSES } from 'constants/v1'
|
||||
import { FACTORY_ADDRESSES, NONFUNGIBLE_POSITION_MANAGER_ADDRESSES, TICK_LENS_ADDRESSES } from 'constants/v3'
|
||||
import {
|
||||
NONFUNGIBLE_POSITION_MANAGER_ADDRESSES,
|
||||
FACTORY_ADDRESSES,
|
||||
TICK_LENS_ADDRESSES,
|
||||
V2_MIGRATOR_ADDRESSES,
|
||||
} from 'constants/v3'
|
||||
import { useMemo } from 'react'
|
||||
import { TickLens, UniswapV3Factory, UniswapV3Pool } from 'types/v3'
|
||||
import { NonfungiblePositionManager } from 'types/v3/NonfungiblePositionManager'
|
||||
import { V3Migrator } from 'types/v3/V3Migrator'
|
||||
import { getContract } from 'utils'
|
||||
import { useActiveWeb3React } from './index'
|
||||
|
||||
@ -60,6 +67,11 @@ export function useV1MigratorContract(): Contract | null {
|
||||
return useContract(V1_MIGRATOR_ADDRESS, MIGRATOR_ABI, true)
|
||||
}
|
||||
|
||||
export function useV2MigratorContract(): V3Migrator | null {
|
||||
const { chainId } = useActiveWeb3React()
|
||||
return useContract(chainId && V2_MIGRATOR_ADDRESSES[chainId], V2MigratorABI, true) as V3Migrator | null
|
||||
}
|
||||
|
||||
export function useV1ExchangeContract(address?: string, withSignerIfPossible?: boolean): Contract | null {
|
||||
return useContract(address, V1_EXCHANGE_ABI, withSignerIfPossible)
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { TransactionResponse } from '@ethersproject/providers'
|
||||
import { Currency, TokenAmount, Token, Percent, ETHER } from '@uniswap/sdk-core'
|
||||
import React, { useCallback, useContext, useState, useMemo } from 'react'
|
||||
import { Currency, TokenAmount, Percent, ETHER } from '@uniswap/sdk-core'
|
||||
import React, { useCallback, useContext, useState } from 'react'
|
||||
import { Link2, AlertTriangle } from 'react-feather'
|
||||
import ReactGA from 'react-ga'
|
||||
import { useV3NFTPositionManagerContract } from '../../hooks/useContract'
|
||||
@ -47,6 +47,95 @@ import { FeeAmount, NonfungiblePositionManager } from '@uniswap/v3-sdk'
|
||||
import { NONFUNGIBLE_POSITION_MANAGER_ADDRESSES } from 'constants/v3'
|
||||
import JSBI from 'jsbi'
|
||||
|
||||
export function FeeSelector({
|
||||
disabled = false,
|
||||
feeAmount,
|
||||
handleFeePoolSelect,
|
||||
}: {
|
||||
disabled?: boolean
|
||||
feeAmount?: FeeAmount
|
||||
handleFeePoolSelect: (feeAmount: FeeAmount) => void
|
||||
}) {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<AutoColumn gap="16px">
|
||||
<DynamicSection gap="md" disabled={disabled}>
|
||||
<TYPE.label>{t('selectPool')}</TYPE.label>
|
||||
<RowBetween>
|
||||
<ButtonRadioChecked
|
||||
width="32%"
|
||||
active={feeAmount === FeeAmount.LOW}
|
||||
onClick={() => handleFeePoolSelect(FeeAmount.LOW)}
|
||||
>
|
||||
<AutoColumn gap="sm" justify="flex-start">
|
||||
<TYPE.label>0.05% {t('fee')}</TYPE.label>
|
||||
<TYPE.main fontWeight={400} fontSize="12px" textAlign="left">
|
||||
Optimized for stable assets.
|
||||
</TYPE.main>
|
||||
</AutoColumn>
|
||||
</ButtonRadioChecked>
|
||||
<ButtonRadioChecked
|
||||
width="32%"
|
||||
active={feeAmount === FeeAmount.MEDIUM}
|
||||
onClick={() => handleFeePoolSelect(FeeAmount.MEDIUM)}
|
||||
>
|
||||
<AutoColumn gap="sm" justify="flex-start">
|
||||
<TYPE.label>0.3% {t('fee')}</TYPE.label>
|
||||
<TYPE.main fontWeight={400} fontSize="12px" textAlign="left">
|
||||
The classic Uniswap pool fee.
|
||||
</TYPE.main>
|
||||
</AutoColumn>
|
||||
</ButtonRadioChecked>
|
||||
<ButtonRadioChecked
|
||||
width="32%"
|
||||
active={feeAmount === FeeAmount.HIGH}
|
||||
onClick={() => handleFeePoolSelect(FeeAmount.HIGH)}
|
||||
>
|
||||
<AutoColumn gap="sm" justify="flex-start">
|
||||
<TYPE.label>1% {t('fee')}</TYPE.label>
|
||||
<TYPE.main fontWeight={400} fontSize="12px" textAlign="left">
|
||||
Best for volatile assets.
|
||||
</TYPE.main>
|
||||
</AutoColumn>
|
||||
</ButtonRadioChecked>
|
||||
</RowBetween>
|
||||
</DynamicSection>
|
||||
</AutoColumn>
|
||||
)
|
||||
}
|
||||
|
||||
// the order of displayed base currencies from left to right is always in sort order
|
||||
// currencyA is treated as the preferred base currency
|
||||
export function RateToggle({
|
||||
currencyA,
|
||||
currencyB,
|
||||
handleRateToggle,
|
||||
}: {
|
||||
currencyA: Currency
|
||||
currencyB: Currency
|
||||
handleRateToggle: () => void
|
||||
}) {
|
||||
const { t } = useTranslation()
|
||||
const { chainId } = useActiveWeb3React()
|
||||
|
||||
const tokenA = wrappedCurrency(currencyA, chainId)
|
||||
const tokenB = wrappedCurrency(currencyB, chainId)
|
||||
|
||||
const isSorted = tokenA && tokenB && tokenA.sortsBefore(tokenB)
|
||||
|
||||
return tokenA && tokenB ? (
|
||||
<ToggleWrapper width="fit-content">
|
||||
<ToggleElement isActive={isSorted} fontSize="12px" onClick={handleRateToggle}>
|
||||
{isSorted ? currencyA.symbol : currencyB.symbol} {t('rate')}
|
||||
</ToggleElement>
|
||||
<ToggleElement isActive={!isSorted} fontSize="12px" onClick={handleRateToggle}>
|
||||
{isSorted ? currencyB.symbol : currencyA.symbol} {t('rate')}
|
||||
</ToggleElement>
|
||||
</ToggleWrapper>
|
||||
) : null
|
||||
}
|
||||
|
||||
export default function AddLiquidity({
|
||||
match: {
|
||||
params: { currencyIdA, currencyIdB, feeAmount: feeAmountFromUrl },
|
||||
@ -285,19 +374,6 @@ export default function AddLiquidity({
|
||||
const { [Bound.LOWER]: tickLower, [Bound.UPPER]: tickUpper } = ticks
|
||||
const { [Bound.LOWER]: priceLower, [Bound.UPPER]: priceUpper } = pricesAtTicks
|
||||
|
||||
// used sort sorted toggle
|
||||
const tokenA = wrappedCurrency(currencyA ?? undefined, chainId)
|
||||
const tokenB = wrappedCurrency(currencyB ?? undefined, chainId)
|
||||
const sortedTokens: Token[] | undefined = useMemo(
|
||||
() =>
|
||||
tokenA && tokenB && !tokenA.equals(tokenB)
|
||||
? tokenA.sortsBefore(tokenB)
|
||||
? [tokenA, tokenB]
|
||||
: [tokenB, tokenA]
|
||||
: undefined,
|
||||
[tokenA, tokenB]
|
||||
)
|
||||
|
||||
const handleRateToggle = useCallback(() => {
|
||||
if (currencyA && currencyB) {
|
||||
const currencyIdA = currencyId(currencyA)
|
||||
@ -322,19 +398,6 @@ export default function AddLiquidity({
|
||||
onUpperRangeInput,
|
||||
])
|
||||
|
||||
const RateToggle = () => {
|
||||
return sortedTokens && currencyB && currencyA ? (
|
||||
<ToggleWrapper width="fit-content">
|
||||
<ToggleElement isActive={tokenA === sortedTokens[0]} fontSize="12px" onClick={handleRateToggle}>
|
||||
{tokenA === sortedTokens[0] ? currencyB.symbol : currencyA?.symbol} {t('rate')}
|
||||
</ToggleElement>
|
||||
<ToggleElement isActive={tokenB === sortedTokens[0]} fontSize="12px" onClick={handleRateToggle}>
|
||||
{tokenB === sortedTokens[0] ? currencyB.symbol : currencyA?.symbol} {t('rate')}
|
||||
</ToggleElement>
|
||||
</ToggleWrapper>
|
||||
) : null
|
||||
}
|
||||
|
||||
return (
|
||||
<ScrollablePage>
|
||||
<ScrollableContent>
|
||||
@ -415,52 +478,11 @@ export default function AddLiquidity({
|
||||
</RowBetween>
|
||||
</AutoColumn>
|
||||
|
||||
<AutoColumn gap="16px">
|
||||
<DynamicSection gap="md" disabled={!currencyB || !currencyA}>
|
||||
<TYPE.label>{t('selectPool')}</TYPE.label>
|
||||
{/* <TYPE.main fontWeight={400} fontSize="14px">
|
||||
{t('poolType')}
|
||||
</TYPE.main> */}
|
||||
<RowBetween>
|
||||
<ButtonRadioChecked
|
||||
width="32%"
|
||||
active={feeAmount === FeeAmount.LOW}
|
||||
onClick={() => handleFeePoolSelect(FeeAmount.LOW)}
|
||||
>
|
||||
<AutoColumn gap="sm" justify="flex-start">
|
||||
<TYPE.label>0.05% {t('fee')}</TYPE.label>
|
||||
<TYPE.main fontWeight={400} fontSize="12px" textAlign="left">
|
||||
Optimized for stable assets.
|
||||
</TYPE.main>
|
||||
</AutoColumn>
|
||||
</ButtonRadioChecked>
|
||||
<ButtonRadioChecked
|
||||
width="32%"
|
||||
active={feeAmount === FeeAmount.MEDIUM}
|
||||
onClick={() => handleFeePoolSelect(FeeAmount.MEDIUM)}
|
||||
>
|
||||
<AutoColumn gap="sm" justify="flex-start">
|
||||
<TYPE.label>0.3% {t('fee')}</TYPE.label>
|
||||
<TYPE.main fontWeight={400} fontSize="12px" textAlign="left">
|
||||
The classic Uniswap pool fee.
|
||||
</TYPE.main>
|
||||
</AutoColumn>
|
||||
</ButtonRadioChecked>
|
||||
<ButtonRadioChecked
|
||||
width="32%"
|
||||
active={feeAmount === FeeAmount.HIGH}
|
||||
onClick={() => handleFeePoolSelect(FeeAmount.HIGH)}
|
||||
>
|
||||
<AutoColumn gap="sm" justify="flex-start">
|
||||
<TYPE.label>1% {t('fee')}</TYPE.label>
|
||||
<TYPE.main fontWeight={400} fontSize="12px" textAlign="left">
|
||||
Best for volatile assets.
|
||||
</TYPE.main>
|
||||
</AutoColumn>
|
||||
</ButtonRadioChecked>
|
||||
</RowBetween>
|
||||
</DynamicSection>
|
||||
</AutoColumn>
|
||||
<FeeSelector
|
||||
disabled={!currencyB || !currencyA}
|
||||
feeAmount={feeAmount}
|
||||
handleFeePoolSelect={handleFeePoolSelect}
|
||||
/>
|
||||
|
||||
{noLiquidity && (
|
||||
<DynamicSection disabled={!currencyA || !currencyB}>
|
||||
@ -470,7 +492,9 @@ export default function AddLiquidity({
|
||||
</BlueCard>
|
||||
<RowBetween>
|
||||
<TYPE.label>{t('selectStartingPrice')}</TYPE.label>
|
||||
{tokenA && tokenB && <RateToggle />}
|
||||
{currencyA && currencyB ? (
|
||||
<RateToggle currencyA={currencyA} currencyB={currencyB} handleRateToggle={handleRateToggle} />
|
||||
) : null}
|
||||
</RowBetween>
|
||||
{/* <TYPE.main fontWeight={400} fontSize="14px">
|
||||
{t('newPoolPrice')}
|
||||
@ -499,7 +523,9 @@ export default function AddLiquidity({
|
||||
<DynamicSection gap="md" disabled={!feeAmount || invalidPool || (noLiquidity && !startPriceTypedValue)}>
|
||||
<RowBetween>
|
||||
<TYPE.label>{t('selectLiquidityRange')}</TYPE.label>
|
||||
{tokenA && tokenB && !noLiquidity && <RateToggle />}
|
||||
{currencyA && currencyB && !noLiquidity && (
|
||||
<RateToggle currencyA={currencyA} currencyB={currencyB} handleRateToggle={handleRateToggle} />
|
||||
)}
|
||||
</RowBetween>
|
||||
{/* <TYPE.main fontWeight={400} fontSize="14px">
|
||||
{t('rangeWarning')}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { useMemo } from 'react'
|
||||
import { Currency, CurrencyAmount, Price, Token, TokenAmount, WETH9 } from '@uniswap/sdk-core'
|
||||
import React, { useCallback, useMemo, useState } from 'react'
|
||||
import { Currency, CurrencyAmount, Fraction, Price, Token, TokenAmount, WETH9 } from '@uniswap/sdk-core'
|
||||
import { JSBI } from '@uniswap/v2-sdk'
|
||||
import { Redirect, RouteComponentProps } from 'react-router'
|
||||
import { Text } from 'rebass'
|
||||
@ -11,7 +11,7 @@ import { AutoRow, RowBetween, RowFixed } from '../../components/Row'
|
||||
import { useTotalSupply } from '../../data/TotalSupply'
|
||||
import { useActiveWeb3React } from '../../hooks'
|
||||
import { useToken } from '../../hooks/Tokens'
|
||||
import { usePairContract } from '../../hooks/useContract'
|
||||
import { usePairContract, useV2MigratorContract } from '../../hooks/useContract'
|
||||
import { NEVER_RELOAD, useSingleCallResult } from '../../state/multicall/hooks'
|
||||
import { useTokenBalance } from '../../state/wallet/hooks'
|
||||
import { BackArrow, ExternalLink, TYPE } from '../../theme'
|
||||
@ -19,14 +19,20 @@ import { getEtherscanLink, isAddress } from '../../utils'
|
||||
import { BodyWrapper } from '../AppBody'
|
||||
import { EmptyState } from '../MigrateV1/EmptyState'
|
||||
import { V2_MIGRATOR_ADDRESSES } from 'constants/v3'
|
||||
import { PoolState, usePool } from 'data/Pools'
|
||||
import { FeeAmount, Pool, Position, priceToClosestTick, TickMath } from '@uniswap/v3-sdk'
|
||||
import { FeeSelector, RateToggle } from 'pages/AddLiquidity'
|
||||
import { LightCard, PinkCard, YellowCard } from 'components/Card'
|
||||
import { ApprovalState, useApproveCallback } from 'hooks/useApproveCallback'
|
||||
import { Dots } from 'components/swap/styleds'
|
||||
import { ButtonConfirmed } from 'components/Button'
|
||||
import useTransactionDeadline from 'hooks/useTransactionDeadline'
|
||||
import { useUserSlippageTolerance } from 'state/user/hooks'
|
||||
import ReactGA from 'react-ga'
|
||||
import { TransactionResponse } from '@ethersproject/providers'
|
||||
import { useIsTransactionPending, useTransactionAdder } from 'state/transactions/hooks'
|
||||
|
||||
// TODO the whole file
|
||||
|
||||
// const WEI_DENOM = JSBI.exponentiate(JSBI.BigInt(10), JSBI.BigInt(18))
|
||||
// const ZERO = JSBI.BigInt(0)
|
||||
// const ONE = JSBI.BigInt(1)
|
||||
// const ZERO_FRACTION = new Fraction(ZERO, ONE)
|
||||
// const ALLOWED_OUTPUT_MIN_PERCENT = new Percent(JSBI.BigInt(10000 - INITIAL_ALLOWED_SLIPPAGE), JSBI.BigInt(10000))
|
||||
const ZERO = JSBI.BigInt(0)
|
||||
|
||||
export function V2LiquidityInfo({
|
||||
token,
|
||||
@ -94,7 +100,7 @@ function V2PairMigration({
|
||||
token0: Token
|
||||
token1: Token
|
||||
}) {
|
||||
const { chainId } = useActiveWeb3React()
|
||||
const { chainId, account } = useActiveWeb3React()
|
||||
|
||||
// this is just getLiquidityValue with the fee off, but for the passed pair
|
||||
const token0Value = useMemo(
|
||||
@ -106,90 +112,144 @@ function V2PairMigration({
|
||||
[token1, pairBalance, reserve1, totalSupply]
|
||||
)
|
||||
|
||||
const v2SpotPrice = new Price(token0, token1, reserve0.raw, reserve1.raw)
|
||||
// set up v3 pool
|
||||
const [feeAmount, setFeeAmount] = useState(FeeAmount.MEDIUM)
|
||||
const [poolState, pool] = usePool(token0, token1, feeAmount)
|
||||
const noLiquidity = poolState === PoolState.NOT_EXISTS
|
||||
|
||||
console.log(token0Value, token1Value, v2SpotPrice)
|
||||
// get spot prices + price difference
|
||||
const v2SpotPrice = useMemo(() => new Price(token0, token1, reserve0.raw, reserve1.raw), [
|
||||
token0,
|
||||
token1,
|
||||
reserve0,
|
||||
reserve1,
|
||||
])
|
||||
const v3SpotPrice = poolState === PoolState.EXISTS ? pool?.token0Price : undefined
|
||||
|
||||
// const isFirstLiquidityProvider: boolean = false // check for v3 pair existence
|
||||
let priceDifferenceFraction: Fraction | undefined =
|
||||
v2SpotPrice && v3SpotPrice ? v3SpotPrice.divide(v2SpotPrice).subtract(1).multiply(100) : undefined
|
||||
if (priceDifferenceFraction?.lessThan(ZERO)) {
|
||||
priceDifferenceFraction = priceDifferenceFraction.multiply(-1)
|
||||
}
|
||||
|
||||
// const [confirmingMigration, setConfirmingMigration] = useState<boolean>(false)
|
||||
// const [pendingMigrationHash, setPendingMigrationHash] = useState<string | null>(null)
|
||||
const largePriceDifference = priceDifferenceFraction && !priceDifferenceFraction?.lessThan(JSBI.BigInt(4))
|
||||
|
||||
// const shareFraction: Fraction = totalSupply ? new Percent(liquidityTokenAmount.raw, totalSupply.raw) : ZERO_FRACTION
|
||||
const [invertPrice, setInvertPrice] = useState(false)
|
||||
|
||||
// const ethWorth: CurrencyAmount = exchangeETHBalance
|
||||
// ? CurrencyAmount.ether(exchangeETHBalance.multiply(shareFraction).multiply(WEI_DENOM).quotient)
|
||||
// : CurrencyAmount.ether(ZERO)
|
||||
// TODO these obviously have to not be hardcoded eventually
|
||||
const lowerTick = -60000
|
||||
const upperTick = 60000
|
||||
const percentageToMigrate = 100
|
||||
|
||||
// const tokenWorth: TokenAmount = exchangeTokenBalance
|
||||
// ? new TokenAmount(token, shareFraction.multiply(exchangeTokenBalance.raw).quotient)
|
||||
// : new TokenAmount(token, ZERO)
|
||||
const [confirmingMigration, setConfirmingMigration] = useState<boolean>(false)
|
||||
const [pendingMigrationHash, setPendingMigrationHash] = useState<string | null>(null)
|
||||
|
||||
// const [approval, approve] = useApproveCallback(liquidityTokenAmount, V1_MIGRATOR_ADDRESS)
|
||||
// TODO add permit approval
|
||||
const [approval, approve] = useApproveCallback(pairBalance, chainId ? V2_MIGRATOR_ADDRESSES[chainId] : undefined)
|
||||
|
||||
// const v1SpotPrice =
|
||||
// exchangeTokenBalance && exchangeETHBalance
|
||||
// ? exchangeTokenBalance.divide(new Fraction(exchangeETHBalance.raw, WEI_DENOM))
|
||||
// : null
|
||||
const addTransaction = useTransactionAdder()
|
||||
const isMigrationPending = useIsTransactionPending(pendingMigrationHash ?? undefined)
|
||||
|
||||
// const priceDifferenceFraction: Fraction | undefined =
|
||||
// v1SpotPrice && v2SpotPrice ? v1SpotPrice.divide(v2SpotPrice).multiply('100').subtract('100') : undefined
|
||||
const deadline = useTransactionDeadline() // custom from users settings
|
||||
const [allowedSlippage] = useUserSlippageTolerance() // custom from users
|
||||
|
||||
// const priceDifferenceAbs: Fraction | undefined = priceDifferenceFraction?.lessThan(ZERO)
|
||||
// ? priceDifferenceFraction?.multiply('-1')
|
||||
// : priceDifferenceFraction
|
||||
const migrator = useV2MigratorContract()
|
||||
const migrate = useCallback(() => {
|
||||
if (!migrator || !account || !deadline) return
|
||||
|
||||
// const minAmountETH: JSBI | undefined =
|
||||
// v2SpotPrice && tokenWorth
|
||||
// ? tokenWorth.divide(v2SpotPrice).multiply(WEI_DENOM).multiply(ALLOWED_OUTPUT_MIN_PERCENT).quotient
|
||||
// : ethWorth?.numerator
|
||||
// the v3 tick is either the tickCurrent, or the tick closest to the v2 spot price
|
||||
const tick = pool?.tickCurrent ?? priceToClosestTick(v2SpotPrice)
|
||||
// the price is either the current v3 price, or the price at the tick
|
||||
const sqrtPrice = pool?.sqrtRatioX96 ?? TickMath.getSqrtRatioAtTick(tick)
|
||||
|
||||
// const minAmountToken: JSBI | undefined =
|
||||
// v2SpotPrice && ethWorth
|
||||
// ? ethWorth
|
||||
// .multiply(v2SpotPrice)
|
||||
// .multiply(JSBI.exponentiate(JSBI.BigInt(10), JSBI.BigInt(token.decimals)))
|
||||
// .multiply(ALLOWED_OUTPUT_MIN_PERCENT).quotient
|
||||
// : tokenWorth?.numerator
|
||||
const data = []
|
||||
|
||||
// const addTransaction = useTransactionAdder()
|
||||
// const isMigrationPending = useIsTransactionPending(pendingMigrationHash ?? undefined)
|
||||
// create/initialize pool if necessary
|
||||
if (noLiquidity) {
|
||||
data.push(
|
||||
migrator.interface.encodeFunctionData('createAndInitializePoolIfNecessary', [
|
||||
token0.address,
|
||||
token1.address,
|
||||
feeAmount,
|
||||
`0x${sqrtPrice.toString(16)}`,
|
||||
])
|
||||
)
|
||||
}
|
||||
|
||||
// const migrator = useV1MigratorContract()
|
||||
// const migrate = useCallback(() => {
|
||||
// if (!minAmountToken || !minAmountETH || !migrator) return
|
||||
const position = Position.fromAmounts({
|
||||
pool: pool ?? new Pool(token0, token1, feeAmount, sqrtPrice, 0, tick, []),
|
||||
tickLower: lowerTick,
|
||||
tickUpper: upperTick,
|
||||
amount0: token0Value.raw,
|
||||
amount1: token1Value.raw,
|
||||
})
|
||||
|
||||
// setConfirmingMigration(true)
|
||||
// migrator
|
||||
// .migrate(
|
||||
// token.address,
|
||||
// minAmountToken.toString(),
|
||||
// minAmountETH.toString(),
|
||||
// account,
|
||||
// Math.floor(new Date().getTime() / 1000) + DEFAULT_DEADLINE_FROM_NOW
|
||||
// )
|
||||
// .then((response: TransactionResponse) => {
|
||||
// ReactGA.event({
|
||||
// category: 'Migrate',
|
||||
// action: 'V1->V2',
|
||||
// label: token?.symbol,
|
||||
// })
|
||||
// TODO could save gas by not doing this in multicall
|
||||
data.push(
|
||||
migrator.interface.encodeFunctionData('migrate', [
|
||||
{
|
||||
pair: pairBalance.token.address,
|
||||
liquidityToMigrate: `0x${pairBalance.raw.toString(16)}`,
|
||||
percentageToMigrate,
|
||||
token0: token0.address,
|
||||
token1: token1.address,
|
||||
fee: feeAmount,
|
||||
tickLower: lowerTick,
|
||||
tickUpper: upperTick,
|
||||
amount0Min: `0x${JSBI.divide(
|
||||
JSBI.multiply(position.amount0.raw, JSBI.BigInt(allowedSlippage)),
|
||||
JSBI.BigInt(10000)
|
||||
).toString(16)}`,
|
||||
amount1Min: `0x${JSBI.divide(
|
||||
JSBI.multiply(position.amount1.raw, JSBI.BigInt(allowedSlippage)),
|
||||
JSBI.BigInt(10000)
|
||||
).toString(16)}`,
|
||||
recipient: account,
|
||||
deadline,
|
||||
refundAsETH: true, // TODO might want to change this?
|
||||
},
|
||||
])
|
||||
)
|
||||
|
||||
// addTransaction(response, {
|
||||
// summary: `Migrate ${token.symbol} liquidity to V2`,
|
||||
// })
|
||||
// setPendingMigrationHash(response.hash)
|
||||
// })
|
||||
// .catch(() => {
|
||||
// setConfirmingMigration(false)
|
||||
// })
|
||||
// }, [minAmountToken, minAmountETH, migrator, token, account, addTransaction])
|
||||
setConfirmingMigration(true)
|
||||
migrator
|
||||
.multicall(data)
|
||||
.then((response: TransactionResponse) => {
|
||||
ReactGA.event({
|
||||
category: 'Migrate',
|
||||
action: 'V2->V3',
|
||||
label: `${token0.symbol}/${token1.symbol}`,
|
||||
})
|
||||
|
||||
// const noLiquidityTokens = !!liquidityTokenAmount && liquidityTokenAmount.equalTo(ZERO)
|
||||
addTransaction(response, {
|
||||
summary: `Migrate ${token0.symbol}/${token1.symbol} liquidity to V3`,
|
||||
})
|
||||
setPendingMigrationHash(response.hash)
|
||||
})
|
||||
.catch(() => {
|
||||
setConfirmingMigration(false)
|
||||
})
|
||||
}, [
|
||||
migrator,
|
||||
noLiquidity,
|
||||
token0,
|
||||
token1,
|
||||
feeAmount,
|
||||
v2SpotPrice,
|
||||
pairBalance,
|
||||
token0Value,
|
||||
token1Value,
|
||||
percentageToMigrate,
|
||||
lowerTick,
|
||||
allowedSlippage,
|
||||
pool,
|
||||
upperTick,
|
||||
account,
|
||||
deadline,
|
||||
addTransaction,
|
||||
])
|
||||
|
||||
// const largePriceDifference = !!priceDifferenceAbs && !priceDifferenceAbs.lessThan(JSBI.BigInt(5))
|
||||
|
||||
// const isSuccessfullyMigrated = !!pendingMigrationHash && noLiquidityTokens
|
||||
const isSuccessfullyMigrated = !!pendingMigrationHash && JSBI.equal(pairBalance.raw, ZERO)
|
||||
|
||||
return (
|
||||
<AutoColumn gap="20px">
|
||||
@ -204,78 +264,76 @@ function V2PairMigration({
|
||||
.
|
||||
</TYPE.body>
|
||||
|
||||
{/* {!isFirstLiquidityProvider && largePriceDifference ? (
|
||||
<YellowCard>
|
||||
<TYPE.body style={{ marginBottom: 8, fontWeight: 400 }}>
|
||||
It{"'"}s best to deposit liquidity into Uniswap V2 at a price you believe is correct. If the V2 price seems
|
||||
incorrect, you can either make a swap to move the price or wait for someone else to do so.
|
||||
</TYPE.body>
|
||||
<AutoColumn gap="8px">
|
||||
<RowBetween>
|
||||
<TYPE.body>V1 Price:</TYPE.body>
|
||||
<TYPE.black>
|
||||
{v1SpotPrice?.toSignificant(6)} {token.symbol}/ETH
|
||||
</TYPE.black>
|
||||
</RowBetween>
|
||||
<RowBetween>
|
||||
<div />
|
||||
<TYPE.black>
|
||||
{v1SpotPrice?.invert()?.toSignificant(6)} ETH/{token.symbol}
|
||||
</TYPE.black>
|
||||
</RowBetween>
|
||||
<FeeSelector feeAmount={feeAmount} handleFeePoolSelect={setFeeAmount} />
|
||||
|
||||
<div style={{ justifySelf: 'end' }}>
|
||||
<RateToggle
|
||||
currencyA={invertPrice ? token1 : token0}
|
||||
currencyB={invertPrice ? token0 : token1}
|
||||
handleRateToggle={() => setInvertPrice((invertPrice) => !invertPrice)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{noLiquidity && (
|
||||
<PinkCard>
|
||||
<TYPE.body style={{ marginBottom: 8, fontWeight: 400 }}>
|
||||
You are the first liquidity provider for this Uniswap V3 pool. Your liquidity will be migrated at the
|
||||
current V2 price. Your transaction cost will include the gas to create the pool.
|
||||
</TYPE.body>
|
||||
|
||||
<AutoColumn gap="8px">
|
||||
<RowBetween>
|
||||
<TYPE.body>V2 Price:</TYPE.body>
|
||||
<TYPE.black>
|
||||
{v2SpotPrice?.toSignificant(6)} {token.symbol}/ETH
|
||||
</TYPE.black>
|
||||
</RowBetween>
|
||||
<RowBetween>
|
||||
<div />
|
||||
<TYPE.black>
|
||||
{v2SpotPrice?.invert()?.toSignificant(6)} ETH/{token.symbol}
|
||||
</TYPE.black>
|
||||
</RowBetween>
|
||||
|
||||
<RowBetween>
|
||||
<TYPE.body color="inherit">Price Difference:</TYPE.body>
|
||||
<TYPE.black color="inherit">{priceDifferenceAbs?.toSignificant(4)}%</TYPE.black>
|
||||
</RowBetween>
|
||||
</AutoColumn>
|
||||
</YellowCard>
|
||||
) : null}
|
||||
|
||||
{isFirstLiquidityProvider && (
|
||||
<PinkCard>
|
||||
<TYPE.body style={{ marginBottom: 8, fontWeight: 400 }}>
|
||||
You are the first liquidity provider for this pair on Uniswap V2. Your liquidity will be migrated at the
|
||||
current V1 price. Your transaction cost also includes the gas to create the pool.
|
||||
</TYPE.body>
|
||||
|
||||
<AutoColumn gap="8px">
|
||||
<RowBetween>
|
||||
<TYPE.body>V1 Price:</TYPE.body>
|
||||
<TYPE.black>
|
||||
{v1SpotPrice?.toSignificant(6)} {token.symbol}/ETH
|
||||
</TYPE.black>
|
||||
</RowBetween>
|
||||
<RowBetween>
|
||||
<div />
|
||||
<TYPE.black>
|
||||
{v1SpotPrice?.invert()?.toSignificant(6)} ETH/{token.symbol}
|
||||
{invertPrice
|
||||
? `${v2SpotPrice?.invert()?.toSignificant(6)} ${token0.symbol} / ${token1.symbol}`
|
||||
: `${v2SpotPrice?.toSignificant(6)} ${token1.symbol} / ${token0.symbol}`}
|
||||
</TYPE.black>
|
||||
</RowBetween>
|
||||
</AutoColumn>
|
||||
</PinkCard>
|
||||
)}
|
||||
|
||||
{largePriceDifference && (
|
||||
<YellowCard>
|
||||
<TYPE.body style={{ marginBottom: 8, fontWeight: 400 }}>
|
||||
You should only deposit liquidity into Uniswap V3 at a price you believe is correct. If the price seems
|
||||
incorrect, you can either make a swap to move the price or wait for someone else to do so.
|
||||
</TYPE.body>
|
||||
<AutoColumn gap="8px">
|
||||
<RowBetween>
|
||||
<TYPE.body>V2 Price:</TYPE.body>
|
||||
<TYPE.black>
|
||||
{invertPrice
|
||||
? `${v2SpotPrice?.invert()?.toSignificant(6)} ${token0.symbol} / ${token1.symbol}`
|
||||
: `${v2SpotPrice?.toSignificant(6)} ${token1.symbol} / ${token0.symbol}`}
|
||||
</TYPE.black>
|
||||
</RowBetween>
|
||||
|
||||
<RowBetween>
|
||||
<TYPE.body>V3 Price:</TYPE.body>
|
||||
<TYPE.black>
|
||||
{invertPrice
|
||||
? `${v3SpotPrice?.invert()?.toSignificant(6)} ${token0.symbol} / ${token1.symbol}`
|
||||
: `${v3SpotPrice?.toSignificant(6)} ${token1.symbol} / ${token0.symbol}`}
|
||||
</TYPE.black>
|
||||
</RowBetween>
|
||||
|
||||
<RowBetween>
|
||||
<TYPE.body color="inherit">Price Difference:</TYPE.body>
|
||||
<TYPE.black color="inherit">{priceDifferenceFraction?.toSignificant(4)}%</TYPE.black>
|
||||
</RowBetween>
|
||||
</AutoColumn>
|
||||
</YellowCard>
|
||||
)}
|
||||
|
||||
<LightCard>
|
||||
<V2LiquidityInfo
|
||||
{/* <V2LiquidityInfo
|
||||
token={token}
|
||||
liquidityTokenAmount={liquidityTokenAmount}
|
||||
tokenWorth={tokenWorth}
|
||||
ethWorth={ethWorth}
|
||||
/>
|
||||
/> */}
|
||||
|
||||
<div style={{ display: 'flex', marginTop: '1rem' }}>
|
||||
<AutoColumn gap="12px" style={{ flex: '1', marginRight: 12 }}>
|
||||
@ -297,22 +355,25 @@ function V2PairMigration({
|
||||
<ButtonConfirmed
|
||||
confirmed={isSuccessfullyMigrated}
|
||||
disabled={
|
||||
isSuccessfullyMigrated ||
|
||||
noLiquidityTokens ||
|
||||
isMigrationPending ||
|
||||
approval !== ApprovalState.APPROVED ||
|
||||
confirmingMigration
|
||||
confirmingMigration ||
|
||||
isMigrationPending ||
|
||||
isSuccessfullyMigrated
|
||||
}
|
||||
onClick={migrate}
|
||||
>
|
||||
{isSuccessfullyMigrated ? 'Success' : isMigrationPending ? <Dots>Migrating</Dots> : 'Migrate'}
|
||||
{isSuccessfullyMigrated ? 'Success!' : isMigrationPending ? <Dots>Migrating</Dots> : 'Migrate'}
|
||||
</ButtonConfirmed>
|
||||
</AutoColumn>
|
||||
</div>
|
||||
</LightCard>
|
||||
<TYPE.darkGray style={{ textAlign: 'center' }}>
|
||||
{`Your Uniswap V1 ${token.symbol}/ETH liquidity will become Uniswap V2 ${token.symbol}/ETH liquidity.`}
|
||||
</TYPE.darkGray> */}
|
||||
{`Your Uniswap V2 ${invertPrice ? token0?.symbol : token1?.symbol} / ${
|
||||
invertPrice ? token1?.symbol : token0?.symbol
|
||||
} liquidity tokens will become a Uniswap V3 ${invertPrice ? token0?.symbol : token1?.symbol} / ${
|
||||
invertPrice ? token1?.symbol : token0?.symbol
|
||||
} NFT.`}
|
||||
</TYPE.darkGray>
|
||||
</AutoColumn>
|
||||
)
|
||||
}
|
||||
|
12
yarn.lock
12
yarn.lock
@ -4134,7 +4134,7 @@
|
||||
tiny-invariant "^1.1.0"
|
||||
tiny-warning "^1.0.3"
|
||||
|
||||
"@uniswap/v3-core@1.0.0-rc.1", "@uniswap/v3-core@^1.0.0-rc.0":
|
||||
"@uniswap/v3-core@1.0.0-rc.1", "@uniswap/v3-core@^1.0.0-rc.1":
|
||||
version "1.0.0-rc.1"
|
||||
resolved "https://registry.yarnpkg.com/@uniswap/v3-core/-/v3-core-1.0.0-rc.1.tgz#f2bbc483451364a951fba06eb2d978c6e8bdd58f"
|
||||
integrity sha512-4ET2H0a8p7nVBGFWfio9SHc+RA6UIXEvlTRIJNsDwjQvfs8Jq9lfJ+eSOUTGmiB8Vp8V5dWarLDBU/rDE159pQ==
|
||||
@ -4149,6 +4149,16 @@
|
||||
"@uniswap/v2-core" "1.0.1"
|
||||
"@uniswap/v3-core" "1.0.0-rc.1"
|
||||
|
||||
"@uniswap/v3-periphery@^1.0.0-beta.19":
|
||||
version "1.0.0-beta.19"
|
||||
resolved "https://registry.yarnpkg.com/@uniswap/v3-periphery/-/v3-periphery-1.0.0-beta.19.tgz#d9af90b12657049674cd2f26ae1c61b6cc393261"
|
||||
integrity sha512-ZQX5KN/89OB7UjrmGOSB7QZIEbgW+R0uaVM5NdlK63Ji0rZjmddeoYS8oNk7i5BU3WR+xJY5DgfiDSmn1W6Sww==
|
||||
dependencies:
|
||||
"@openzeppelin/contracts" "3.4.1-solc-0.7-2"
|
||||
"@uniswap/lib" "^4.0.1-alpha"
|
||||
"@uniswap/v2-core" "1.0.1"
|
||||
"@uniswap/v3-core" "1.0.0-rc.1"
|
||||
|
||||
"@uniswap/v3-sdk@^1.0.0-alpha.11":
|
||||
version "1.0.0-alpha.11"
|
||||
resolved "https://registry.yarnpkg.com/@uniswap/v3-sdk/-/v3-sdk-1.0.0-alpha.11.tgz#184ed5ee8322b27f35aa830ad5e217b5dda6bd67"
|
||||
|
Loading…
Reference in New Issue
Block a user