Commit 9fc096d0 authored by Noah Zinsmeister's avatar Noah Zinsmeister Committed by GitHub

Finish migration (#42)

* start migration (wip)

abstract some add liquidity components

bump deploy version

* add slippage params
parent 9f5584c3
......@@ -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)
}
......
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')}
......
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'
// 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))
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'
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)
// const isFirstLiquidityProvider: boolean = false // check for v3 pair existence
// const [confirmingMigration, setConfirmingMigration] = useState<boolean>(false)
// const [pendingMigrationHash, setPendingMigrationHash] = useState<string | null>(null)
// const shareFraction: Fraction = totalSupply ? new Percent(liquidityTokenAmount.raw, totalSupply.raw) : ZERO_FRACTION
// 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 ethWorth: CurrencyAmount = exchangeETHBalance
// ? CurrencyAmount.ether(exchangeETHBalance.multiply(shareFraction).multiply(WEI_DENOM).quotient)
// : CurrencyAmount.ether(ZERO)
let priceDifferenceFraction: Fraction | undefined =
v2SpotPrice && v3SpotPrice ? v3SpotPrice.divide(v2SpotPrice).subtract(1).multiply(100) : undefined
if (priceDifferenceFraction?.lessThan(ZERO)) {
priceDifferenceFraction = priceDifferenceFraction.multiply(-1)
}
// const tokenWorth: TokenAmount = exchangeTokenBalance
// ? new TokenAmount(token, shareFraction.multiply(exchangeTokenBalance.raw).quotient)
// : new TokenAmount(token, ZERO)
const largePriceDifference = priceDifferenceFraction && !priceDifferenceFraction?.lessThan(JSBI.BigInt(4))
// const [approval, approve] = useApproveCallback(liquidityTokenAmount, V1_MIGRATOR_ADDRESS)
const [invertPrice, setInvertPrice] = useState(false)
// const v1SpotPrice =
// exchangeTokenBalance && exchangeETHBalance
// ? exchangeTokenBalance.divide(new Fraction(exchangeETHBalance.raw, WEI_DENOM))
// : null
// TODO these obviously have to not be hardcoded eventually
const lowerTick = -60000
const upperTick = 60000
const percentageToMigrate = 100
// const priceDifferenceFraction: Fraction | undefined =
// v1SpotPrice && v2SpotPrice ? v1SpotPrice.divide(v2SpotPrice).multiply('100').subtract('100') : undefined
const [confirmingMigration, setConfirmingMigration] = useState<boolean>(false)
const [pendingMigrationHash, setPendingMigrationHash] = useState<string | null>(null)
// const priceDifferenceAbs: Fraction | undefined = priceDifferenceFraction?.lessThan(ZERO)
// ? priceDifferenceFraction?.multiply('-1')
// : priceDifferenceFraction
// TODO add permit approval
const [approval, approve] = useApproveCallback(pairBalance, chainId ? V2_MIGRATOR_ADDRESSES[chainId] : undefined)
// const minAmountETH: JSBI | undefined =
// v2SpotPrice && tokenWorth
// ? tokenWorth.divide(v2SpotPrice).multiply(WEI_DENOM).multiply(ALLOWED_OUTPUT_MIN_PERCENT).quotient
// : ethWorth?.numerator
const addTransaction = useTransactionAdder()
const isMigrationPending = useIsTransactionPending(pendingMigrationHash ?? undefined)
// 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 deadline = useTransactionDeadline() // custom from users settings
const [allowedSlippage] = useUserSlippageTolerance() // custom from users
// const addTransaction = useTransactionAdder()
// const isMigrationPending = useIsTransactionPending(pendingMigrationHash ?? undefined)
const migrator = useV2MigratorContract()
const migrate = useCallback(() => {
if (!migrator || !account || !deadline) return
// const migrator = useV1MigratorContract()
// const migrate = useCallback(() => {
// if (!minAmountToken || !minAmountETH || !migrator) return
// 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)
// 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,
// })
const data = []
// addTransaction(response, {
// summary: `Migrate ${token.symbol} liquidity to V2`,
// })
// setPendingMigrationHash(response.hash)
// })
// .catch(() => {
// setConfirmingMigration(false)
// })
// }, [minAmountToken, minAmountETH, migrator, token, account, addTransaction])
// create/initialize pool if necessary
if (noLiquidity) {
data.push(
migrator.interface.encodeFunctionData('createAndInitializePoolIfNecessary', [
token0.address,
token1.address,
feeAmount,
`0x${sqrtPrice.toString(16)}`,
])
)
}
// const noLiquidityTokens = !!liquidityTokenAmount && liquidityTokenAmount.equalTo(ZERO)
const position = Position.fromAmounts({
pool: pool ?? new Pool(token0, token1, feeAmount, sqrtPrice, 0, tick, []),
tickLower: lowerTick,
tickUpper: upperTick,
amount0: token0Value.raw,
amount1: token1Value.raw,
})
// 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?
},
])
)
// const largePriceDifference = !!priceDifferenceAbs && !priceDifferenceAbs.lessThan(JSBI.BigInt(5))
setConfirmingMigration(true)
migrator
.multicall(data)
.then((response: TransactionResponse) => {
ReactGA.event({
category: 'Migrate',
action: 'V2->V3',
label: `${token0.symbol}/${token1.symbol}`,
})
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 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>
<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 }}>
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.
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>V1 Price:</TYPE.body>
<TYPE.black>
{v1SpotPrice?.toSignificant(6)} {token.symbol}/ETH
</TYPE.black>
</RowBetween>
<RowBetween>
<div />
<TYPE.body>V2 Price:</TYPE.body>
<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>
{v2SpotPrice?.toSignificant(6)} {token.symbol}/ETH
{invertPrice
? `${v2SpotPrice?.invert()?.toSignificant(6)} ${token0.symbol} / ${token1.symbol}`
: `${v2SpotPrice?.toSignificant(6)} ${token1.symbol} / ${token0.symbol}`}
</TYPE.black>
</RowBetween>
<RowBetween>
<div />
<TYPE.body>V3 Price:</TYPE.body>
<TYPE.black>
{v2SpotPrice?.invert()?.toSignificant(6)} ETH/{token.symbol}
{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">{priceDifferenceAbs?.toSignificant(4)}%</TYPE.black>
<TYPE.black color="inherit">{priceDifferenceFraction?.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}
</TYPE.black>
</RowBetween>
</AutoColumn>
</PinkCard>
)}
<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>
)
}
......
......@@ -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"
......
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