Commit f00adc75 authored by Noah Zinsmeister's avatar Noah Zinsmeister

refactor range selection and use in migrate

improve migrate
parent 63907b7b
import { TransactionResponse } from '@ethersproject/providers' import { TransactionResponse } from '@ethersproject/providers'
import { Currency, TokenAmount, Percent, ETHER } from '@uniswap/sdk-core' import { Currency, TokenAmount, Percent, ETHER, Price } from '@uniswap/sdk-core'
import React, { useCallback, useContext, useState } from 'react' import React, { useCallback, useContext, useState } from 'react'
import { Link2, AlertTriangle } from 'react-feather' import { Link2, AlertTriangle } from 'react-feather'
import ReactGA from 'react-ga' import ReactGA from 'react-ga'
...@@ -105,6 +105,48 @@ export function FeeSelector({ ...@@ -105,6 +105,48 @@ export function FeeSelector({
) )
} }
// currencyA is the base token
export function RangeSelector({
priceLower,
priceUpper,
onLowerRangeInput,
onUpperRangeInput,
currencyA,
currencyB,
}: {
priceLower?: Price
priceUpper?: Price
onLowerRangeInput: (typedValue: string) => void
onUpperRangeInput: (typedValue: string) => void
currencyA?: Currency | null
currencyB?: Currency | null
}) {
return (
<RowBetween>
<StepCounter
value={priceLower?.toSignificant(5) ?? ''}
onUserInput={onLowerRangeInput}
width="48%"
label={
priceLower && currencyA && currencyB
? `${priceLower.toSignificant(4)} ${currencyB.symbol} / 1 ${currencyA.symbol}`
: '-'
}
/>
<StepCounter
value={priceUpper?.toSignificant(5) ?? ''}
onUserInput={onUpperRangeInput}
width="48%"
label={
priceUpper && currencyA && currencyB
? `${priceUpper.toSignificant(4)} ${currencyB?.symbol} / 1 ${currencyA?.symbol}`
: '-'
}
/>
</RowBetween>
)
}
// the order of displayed base currencies from left to right is always in sort order // the order of displayed base currencies from left to right is always in sort order
// currencyA is treated as the preferred base currency // currencyA is treated as the preferred base currency
export function RateToggle({ export function RateToggle({
...@@ -538,28 +580,15 @@ export default function AddLiquidity({ ...@@ -538,28 +580,15 @@ export default function AddLiquidity({
</TYPE.main> </TYPE.main>
</RowBetween> </RowBetween>
)} )}
<RowBetween>
<StepCounter <RangeSelector
value={priceLower?.toSignificant(5) ?? ''} priceLower={priceLower}
onUserInput={onLowerRangeInput} priceUpper={priceUpper}
width="48%" onLowerRangeInput={onLowerRangeInput}
label={ onUpperRangeInput={onUpperRangeInput}
priceLower && currencyA && currencyB currencyA={currencyA}
? '1 ' + currencyA?.symbol + ' / ' + priceLower?.toSignificant(4) + ' ' + currencyB?.symbol currencyB={currencyB}
: '-' />
}
/>
<StepCounter
value={priceUpper?.toSignificant(5) ?? ''}
onUserInput={onUpperRangeInput}
width="48%"
label={
priceUpper && currencyA && currencyB
? '1 ' + currencyA?.symbol + ' / ' + priceUpper?.toSignificant(4) + ' ' + currencyB?.symbol
: '-'
}
/>
</RowBetween>
{outOfRange ? ( {outOfRange ? (
<YellowCard padding="8px 12px" borderRadius="12px"> <YellowCard padding="8px 12px" borderRadius="12px">
......
...@@ -275,9 +275,9 @@ export default function AddLiquidity({ ...@@ -275,9 +275,9 @@ export default function AddLiquidity({
(currencyA: Currency) => { (currencyA: Currency) => {
const newCurrencyIdA = currencyId(currencyA) const newCurrencyIdA = currencyId(currencyA)
if (newCurrencyIdA === currencyIdB) { if (newCurrencyIdA === currencyIdB) {
history.push(`/add/${currencyIdB}/${currencyIdA}`) history.push(`/add/v2/${currencyIdB}/${currencyIdA}`)
} else { } else {
history.push(`/add/${newCurrencyIdA}/${currencyIdB}`) history.push(`/add/v2/${newCurrencyIdA}/${currencyIdB}`)
} }
}, },
[currencyIdB, history, currencyIdA] [currencyIdB, history, currencyIdA]
...@@ -287,12 +287,12 @@ export default function AddLiquidity({ ...@@ -287,12 +287,12 @@ export default function AddLiquidity({
const newCurrencyIdB = currencyId(currencyB) const newCurrencyIdB = currencyId(currencyB)
if (currencyIdA === newCurrencyIdB) { if (currencyIdA === newCurrencyIdB) {
if (currencyIdB) { if (currencyIdB) {
history.push(`/add/${currencyIdB}/${newCurrencyIdB}`) history.push(`/add/v2/${currencyIdB}/${newCurrencyIdB}`)
} else { } else {
history.push(`/add/${newCurrencyIdB}`) history.push(`/add/v2/${newCurrencyIdB}`)
} }
} else { } else {
history.push(`/add/${currencyIdA ? currencyIdA : 'ETH'}/${newCurrencyIdB}`) history.push(`/add/v2/${currencyIdA ? currencyIdA : 'ETH'}/${newCurrencyIdB}`)
} }
}, },
[currencyIdA, history, currencyIdB] [currencyIdA, history, currencyIdB]
......
import React, { useCallback, useMemo, useState } from 'react' import React, { useCallback, useMemo, useState } from 'react'
import { Currency, CurrencyAmount, Fraction, Price, Token, TokenAmount, WETH9 } from '@uniswap/sdk-core' import { Fraction, Price, Token, TokenAmount, WETH9 } from '@uniswap/sdk-core'
import { JSBI } from '@uniswap/v2-sdk' import { JSBI } from '@uniswap/v2-sdk'
import { Redirect, RouteComponentProps } from 'react-router' import { Redirect, RouteComponentProps } from 'react-router'
import { Text } from 'rebass' import { Text } from 'rebass'
...@@ -21,7 +21,7 @@ import { EmptyState } from '../MigrateV1/EmptyState' ...@@ -21,7 +21,7 @@ import { EmptyState } from '../MigrateV1/EmptyState'
import { V2_MIGRATOR_ADDRESSES } from 'constants/v3' import { V2_MIGRATOR_ADDRESSES } from 'constants/v3'
import { PoolState, usePool } from 'data/Pools' import { PoolState, usePool } from 'data/Pools'
import { FeeAmount, Pool, Position, priceToClosestTick, TickMath } from '@uniswap/v3-sdk' import { FeeAmount, Pool, Position, priceToClosestTick, TickMath } from '@uniswap/v3-sdk'
import { FeeSelector, RateToggle } from 'pages/AddLiquidity' import { FeeSelector, RangeSelector, RateToggle } from 'pages/AddLiquidity'
import { LightCard, PinkCard, YellowCard } from 'components/Card' import { LightCard, PinkCard, YellowCard } from 'components/Card'
import { ApprovalState, useApproveCallback } from 'hooks/useApproveCallback' import { ApprovalState, useApproveCallback } from 'hooks/useApproveCallback'
import { Dots } from 'components/swap/styleds' import { Dots } from 'components/swap/styleds'
...@@ -31,60 +31,45 @@ import { useUserSlippageTolerance } from 'state/user/hooks' ...@@ -31,60 +31,45 @@ import { useUserSlippageTolerance } from 'state/user/hooks'
import ReactGA from 'react-ga' import ReactGA from 'react-ga'
import { TransactionResponse } from '@ethersproject/providers' import { TransactionResponse } from '@ethersproject/providers'
import { useIsTransactionPending, useTransactionAdder } from 'state/transactions/hooks' import { useIsTransactionPending, useTransactionAdder } from 'state/transactions/hooks'
import { useDerivedMintInfo, useMintActionHandlers } from 'state/mint/hooks'
import { Bound } from 'state/mint/actions'
import { useTranslation } from 'react-i18next'
import { ChevronDown } from 'react-feather'
const ZERO = JSBI.BigInt(0) const ZERO = JSBI.BigInt(0)
export function V2LiquidityInfo({ function LiquidityInfo({ token0Amount, token1Amount }: { token0Amount: TokenAmount; token1Amount: TokenAmount }) {
token,
liquidityTokenAmount,
tokenWorth,
ethWorth,
}: {
token: Token
liquidityTokenAmount: TokenAmount
tokenWorth: TokenAmount
ethWorth: CurrencyAmount
}) {
const { chainId } = useActiveWeb3React()
return ( return (
<> <>
<AutoRow style={{ justifyContent: 'flex-start', width: 'fit-content' }}>
<CurrencyLogo size="24px" currency={token} />
<div style={{ marginLeft: '.75rem' }}>
<TYPE.mediumHeader>
{<FormattedCurrencyAmount currencyAmount={liquidityTokenAmount} />}{' '}
{chainId && token.equals(WETH9[chainId]) ? 'WETH' : token.symbol}/ETH
</TYPE.mediumHeader>
</div>
</AutoRow>
<RowBetween my="1rem"> <RowBetween my="1rem">
<Text fontSize={16} fontWeight={500}> <Text fontSize={16} fontWeight={500}>
Pooled {chainId && token.equals(WETH9[chainId]) ? 'WETH' : token.symbol}: Pooled {token0Amount.token.symbol}:
</Text> </Text>
<RowFixed> <RowFixed>
<Text fontSize={16} fontWeight={500} marginLeft={'6px'}> <Text fontSize={16} fontWeight={500} marginLeft={'6px'}>
{tokenWorth.toSignificant(4)} {token0Amount.toSignificant(4)}
</Text> </Text>
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={token} /> <CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={token0Amount.token} />
</RowFixed> </RowFixed>
</RowBetween> </RowBetween>
<RowBetween mb="1rem"> <RowBetween mb="1rem">
<Text fontSize={16} fontWeight={500}> <Text fontSize={16} fontWeight={500}>
Pooled ETH: Pooled {token1Amount.token.symbol}:
</Text> </Text>
<RowFixed> <RowFixed>
<Text fontSize={16} fontWeight={500} marginLeft={'6px'}> <Text fontSize={16} fontWeight={500} marginLeft={'6px'}>
<FormattedCurrencyAmount currencyAmount={ethWorth} /> <FormattedCurrencyAmount currencyAmount={token1Amount} />
</Text> </Text>
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={Currency.ETHER} /> <CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={token1Amount.token} />
</RowFixed> </RowFixed>
</RowBetween> </RowBetween>
</> </>
) )
} }
// hard-code this for now
const percentageToMigrate = 100
function V2PairMigration({ function V2PairMigration({
pairBalance, pairBalance,
totalSupply, totalSupply,
...@@ -100,8 +85,12 @@ function V2PairMigration({ ...@@ -100,8 +85,12 @@ function V2PairMigration({
token0: Token token0: Token
token1: Token token1: Token
}) { }) {
const { t } = useTranslation()
const { chainId, account } = useActiveWeb3React() const { chainId, account } = useActiveWeb3React()
const deadline = useTransactionDeadline() // custom from users settings
const [allowedSlippage] = useUserSlippageTolerance() // custom from users
// this is just getLiquidityValue with the fee off, but for the passed pair // this is just getLiquidityValue with the fee off, but for the passed pair
const token0Value = useMemo( const token0Value = useMemo(
() => new TokenAmount(token0, JSBI.divide(JSBI.multiply(pairBalance.raw, reserve0.raw), totalSupply.raw)), () => new TokenAmount(token0, JSBI.divide(JSBI.multiply(pairBalance.raw, reserve0.raw), totalSupply.raw)),
...@@ -136,10 +125,61 @@ function V2PairMigration({ ...@@ -136,10 +125,61 @@ function V2PairMigration({
const [invertPrice, setInvertPrice] = useState(false) const [invertPrice, setInvertPrice] = useState(false)
// TODO these obviously have to not be hardcoded eventually // the following is a small hack to get access to price range data/input handlers
const lowerTick = -60000 const { ticks, pricesAtTicks } = useDerivedMintInfo(
const upperTick = 60000 invertPrice ? token1 : token0,
const percentageToMigrate = 100 invertPrice ? token0 : token1,
feeAmount
)
// get value and prices at ticks
const { [Bound.LOWER]: tickLower, [Bound.UPPER]: tickUpper } = ticks
const { [Bound.LOWER]: priceLower, [Bound.UPPER]: priceUpper } = pricesAtTicks
const { onLowerRangeInput, onUpperRangeInput } = useMintActionHandlers(noLiquidity)
// the v3 tick is either the pool's 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 position =
typeof tickLower === 'number' && typeof tickUpper === 'number'
? Position.fromAmounts({
pool: pool ?? new Pool(token0, token1, feeAmount, sqrtPrice, 0, tick, []),
tickLower: invertPrice ? tickUpper : tickLower,
tickUpper: invertPrice ? tickLower : tickUpper,
amount0: token0Value.raw,
amount1: token1Value.raw,
})
: undefined
const v3Amount0Min = useMemo(
() =>
position &&
new TokenAmount(
token0,
JSBI.divide(JSBI.multiply(position.amount0.raw, JSBI.BigInt(10000 - allowedSlippage)), JSBI.BigInt(10000))
),
[token0, position, allowedSlippage]
)
const v3Amount1Min = useMemo(
() =>
position &&
new TokenAmount(
token1,
JSBI.divide(JSBI.multiply(position.amount1.raw, JSBI.BigInt(10000 - allowedSlippage)), JSBI.BigInt(10000))
),
[token1, position, allowedSlippage]
)
const refund0 = useMemo(
() => v3Amount0Min && new TokenAmount(token0, JSBI.subtract(token0Value.raw, v3Amount0Min.raw)),
[token0Value, v3Amount0Min, token0]
)
const refund1 = useMemo(
() => v3Amount1Min && new TokenAmount(token1, JSBI.subtract(token1Value.raw, v3Amount1Min.raw)),
[token1Value, v3Amount1Min, token1]
)
const [confirmingMigration, setConfirmingMigration] = useState<boolean>(false) const [confirmingMigration, setConfirmingMigration] = useState<boolean>(false)
const [pendingMigrationHash, setPendingMigrationHash] = useState<string | null>(null) const [pendingMigrationHash, setPendingMigrationHash] = useState<string | null>(null)
...@@ -150,17 +190,18 @@ function V2PairMigration({ ...@@ -150,17 +190,18 @@ function V2PairMigration({
const addTransaction = useTransactionAdder() const addTransaction = useTransactionAdder()
const isMigrationPending = useIsTransactionPending(pendingMigrationHash ?? undefined) const isMigrationPending = useIsTransactionPending(pendingMigrationHash ?? undefined)
const deadline = useTransactionDeadline() // custom from users settings
const [allowedSlippage] = useUserSlippageTolerance() // custom from users
const migrator = useV2MigratorContract() const migrator = useV2MigratorContract()
const migrate = useCallback(() => { const migrate = useCallback(() => {
if (!migrator || !account || !deadline) return if (
!migrator ||
// the v3 tick is either the tickCurrent, or the tick closest to the v2 spot price !account ||
const tick = pool?.tickCurrent ?? priceToClosestTick(v2SpotPrice) !deadline ||
// the price is either the current v3 price, or the price at the tick typeof tickLower !== 'number' ||
const sqrtPrice = pool?.sqrtRatioX96 ?? TickMath.getSqrtRatioAtTick(tick) typeof tickUpper !== 'number' ||
!v3Amount0Min ||
!v3Amount1Min
)
return
const data = [] const data = []
...@@ -176,14 +217,6 @@ function V2PairMigration({ ...@@ -176,14 +217,6 @@ function V2PairMigration({
) )
} }
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 // TODO could save gas by not doing this in multicall
data.push( data.push(
migrator.interface.encodeFunctionData('migrate', [ migrator.interface.encodeFunctionData('migrate', [
...@@ -194,19 +227,13 @@ function V2PairMigration({ ...@@ -194,19 +227,13 @@ function V2PairMigration({
token0: token0.address, token0: token0.address,
token1: token1.address, token1: token1.address,
fee: feeAmount, fee: feeAmount,
tickLower: lowerTick, tickLower: invertPrice ? tickUpper : tickLower,
tickUpper: upperTick, tickUpper: invertPrice ? tickLower : tickUpper,
amount0Min: `0x${JSBI.divide( amount0Min: `0x${v3Amount0Min.raw.toString(16)}`,
JSBI.multiply(position.amount0.raw, JSBI.BigInt(allowedSlippage)), amount1Min: `0x${v3Amount1Min.raw.toString(16)}`,
JSBI.BigInt(10000)
).toString(16)}`,
amount1Min: `0x${JSBI.divide(
JSBI.multiply(position.amount1.raw, JSBI.BigInt(allowedSlippage)),
JSBI.BigInt(10000)
).toString(16)}`,
recipient: account, recipient: account,
deadline, deadline,
refundAsETH: true, // TODO might want to change this? refundAsETH: true, // hard-code this for now
}, },
]) ])
) )
...@@ -235,15 +262,13 @@ function V2PairMigration({ ...@@ -235,15 +262,13 @@ function V2PairMigration({
token0, token0,
token1, token1,
feeAmount, feeAmount,
v2SpotPrice,
pairBalance, pairBalance,
token0Value, invertPrice,
token1Value, tickLower,
percentageToMigrate, tickUpper,
lowerTick, sqrtPrice,
allowedSlippage, v3Amount0Min,
pool, v3Amount1Min,
upperTick,
account, account,
deadline, deadline,
addTransaction, addTransaction,
...@@ -254,8 +279,7 @@ function V2PairMigration({ ...@@ -254,8 +279,7 @@ function V2PairMigration({
return ( return (
<AutoColumn gap="20px"> <AutoColumn gap="20px">
<TYPE.body my={9} style={{ fontWeight: 400 }}> <TYPE.body my={9} style={{ fontWeight: 400 }}>
This tool will safely migrate your V2 liquidity to V3 with minimal price risk. The process is completely This tool will safely migrate your V2 liquidity to V3. The process is completely trustless thanks to the{' '}
trustless thanks to the{' '}
{chainId && ( {chainId && (
<ExternalLink href={getEtherscanLink(chainId, V2_MIGRATOR_ADDRESSES[chainId], 'address')}> <ExternalLink href={getEtherscanLink(chainId, V2_MIGRATOR_ADDRESSES[chainId], 'address')}>
<TYPE.blue display="inline">Uniswap migration contract↗</TYPE.blue> <TYPE.blue display="inline">Uniswap migration contract↗</TYPE.blue>
...@@ -264,14 +288,12 @@ function V2PairMigration({ ...@@ -264,14 +288,12 @@ function V2PairMigration({
. .
</TYPE.body> </TYPE.body>
<FeeSelector feeAmount={feeAmount} handleFeePoolSelect={setFeeAmount} /> <LightCard>
<LiquidityInfo token0Amount={token0Value} token1Amount={token1Value} />
</LightCard>
<div style={{ justifySelf: 'end' }}> <div style={{ display: 'flex', justifyContent: 'center' }}>
<RateToggle <ChevronDown size={24} />
currencyA={invertPrice ? token1 : token0}
currencyB={invertPrice ? token0 : token1}
handleRateToggle={() => setInvertPrice((invertPrice) => !invertPrice)}
/>
</div> </div>
{noLiquidity && ( {noLiquidity && (
...@@ -327,13 +349,34 @@ function V2PairMigration({ ...@@ -327,13 +349,34 @@ function V2PairMigration({
</YellowCard> </YellowCard>
)} )}
<FeeSelector feeAmount={feeAmount} handleFeePoolSelect={setFeeAmount} />
<RowBetween>
<TYPE.label>{t('selectLiquidityRange')}</TYPE.label>
<RateToggle
currencyA={invertPrice ? token1 : token0}
currencyB={invertPrice ? token0 : token1}
handleRateToggle={() => {
onLowerRangeInput('')
onUpperRangeInput('')
setInvertPrice((invertPrice) => !invertPrice)
}}
/>
</RowBetween>
<RangeSelector
priceLower={priceLower}
priceUpper={priceUpper}
onLowerRangeInput={onLowerRangeInput}
onUpperRangeInput={onUpperRangeInput}
currencyA={invertPrice ? token1 : token0}
currencyB={invertPrice ? token0 : token1}
/>
<LightCard> <LightCard>
{/* <V2LiquidityInfo {v3Amount0Min && v3Amount1Min ? (
token={token} <LiquidityInfo token0Amount={v3Amount0Min} token1Amount={v3Amount1Min} />
liquidityTokenAmount={liquidityTokenAmount} ) : null}
tokenWorth={tokenWorth}
ethWorth={ethWorth}
/> */}
<div style={{ display: 'flex', marginTop: '1rem' }}> <div style={{ display: 'flex', marginTop: '1rem' }}>
<AutoColumn gap="12px" style={{ flex: '1', marginRight: 12 }}> <AutoColumn gap="12px" style={{ flex: '1', marginRight: 12 }}>
...@@ -355,6 +398,8 @@ function V2PairMigration({ ...@@ -355,6 +398,8 @@ function V2PairMigration({
<ButtonConfirmed <ButtonConfirmed
confirmed={isSuccessfullyMigrated} confirmed={isSuccessfullyMigrated}
disabled={ disabled={
!v3Amount0Min ||
!v3Amount1Min ||
approval !== ApprovalState.APPROVED || approval !== ApprovalState.APPROVED ||
confirmingMigration || confirmingMigration ||
isMigrationPending || isMigrationPending ||
...@@ -366,6 +411,16 @@ function V2PairMigration({ ...@@ -366,6 +411,16 @@ function V2PairMigration({
</ButtonConfirmed> </ButtonConfirmed>
</AutoColumn> </AutoColumn>
</div> </div>
{chainId && refund0 && refund1 ? (
<div style={{ marginTop: '1rem' }}>
<TYPE.darkGray style={{ textAlign: 'center' }}>
{refund0.toSignificant(4)} {token0.equals(WETH9[chainId]) ? 'ETH' : token0.symbol} and{' '}
{refund1.toSignificant(4)} {token1.equals(WETH9[chainId]) ? 'ETH' : token1.symbol} will be refunded to
your wallet.
</TYPE.darkGray>
</div>
) : null}
</LightCard> </LightCard>
<TYPE.darkGray style={{ textAlign: 'center' }}> <TYPE.darkGray style={{ textAlign: 'center' }}>
{`Your Uniswap V2 ${invertPrice ? token0?.symbol : token1?.symbol} / ${ {`Your Uniswap V2 ${invertPrice ? token0?.symbol : token1?.symbol} / ${
......
...@@ -171,7 +171,7 @@ export default function Pool() { ...@@ -171,7 +171,7 @@ export default function Pool() {
as={Link} as={Link}
padding="6px 8px" padding="6px 8px"
borderRadius="12px" borderRadius="12px"
to="/add/ETH" to="/add/v2/ETH"
> >
<Text fontWeight={500} fontSize={16}> <Text fontWeight={500} fontSize={16}>
Add Liquidity Add Liquidity
......
...@@ -176,10 +176,10 @@ export function useDerivedMintInfo( ...@@ -176,10 +176,10 @@ export function useDerivedMintInfo(
[key: string]: number | undefined [key: string]: number | undefined
} = useMemo(() => { } = useMemo(() => {
return { return {
[Bound.LOWER]: poolForPosition ? tryParseTick(tokenA, tokenB, poolForPosition, lowerRangeTypedValue) : undefined, [Bound.LOWER]: tryParseTick(tokenA, tokenB, feeAmount, lowerRangeTypedValue),
[Bound.UPPER]: poolForPosition ? tryParseTick(tokenA, tokenB, poolForPosition, upperRangeTypedValue) : undefined, [Bound.UPPER]: tryParseTick(tokenA, tokenB, feeAmount, upperRangeTypedValue),
} }
}, [lowerRangeTypedValue, poolForPosition, tokenA, tokenB, upperRangeTypedValue]) }, [feeAmount, lowerRangeTypedValue, tokenA, tokenB, upperRangeTypedValue])
const { [Bound.LOWER]: tickLower, [Bound.UPPER]: tickUpper } = ticks || {} const { [Bound.LOWER]: tickLower, [Bound.UPPER]: tickUpper } = ticks || {}
const sortedTicks = useMemo( const sortedTicks = useMemo(
...@@ -194,10 +194,10 @@ export function useDerivedMintInfo( ...@@ -194,10 +194,10 @@ export function useDerivedMintInfo(
const pricesAtTicks = useMemo(() => { const pricesAtTicks = useMemo(() => {
return { return {
[Bound.LOWER]: poolForPosition ? getTickToPrice(tokenA, tokenB, ticks[Bound.LOWER]) : undefined, [Bound.LOWER]: getTickToPrice(tokenA, tokenB, ticks[Bound.LOWER]),
[Bound.UPPER]: poolForPosition ? getTickToPrice(tokenA, tokenB, ticks[Bound.UPPER]) : undefined, [Bound.UPPER]: getTickToPrice(tokenA, tokenB, ticks[Bound.UPPER]),
} }
}, [poolForPosition, ticks, tokenA, tokenB]) }, [tokenA, tokenB, ticks])
const { [Bound.LOWER]: lowerPrice, [Bound.UPPER]: upperPrice } = pricesAtTicks const { [Bound.LOWER]: lowerPrice, [Bound.UPPER]: upperPrice } = pricesAtTicks
// mark invalid range // mark invalid range
......
import { Pool, priceToClosestTick, nearestUsableTick } from '@uniswap/v3-sdk/dist/' import { priceToClosestTick, nearestUsableTick, FeeAmount, TICK_SPACINGS } from '@uniswap/v3-sdk/dist/'
import { Price, Token } from '@uniswap/sdk-core' import { Price, Token } from '@uniswap/sdk-core'
import { tryParseAmount } from 'state/swap/hooks' import { tryParseAmount } from 'state/swap/hooks'
export function tryParseTick( export function tryParseTick(
baseToken: Token | undefined, baseToken?: Token,
quoteToken: Token | undefined, quoteToken?: Token,
pool: Pool | undefined, feeAmount?: FeeAmount,
value?: string value?: string
): number | undefined { ): number | undefined {
if (!value || !baseToken || !quoteToken || !pool) { if (!baseToken || !quoteToken || !feeAmount || !value) {
return undefined return undefined
} }
...@@ -23,5 +23,5 @@ export function tryParseTick( ...@@ -23,5 +23,5 @@ export function tryParseTick(
const tick = priceToClosestTick(price) const tick = priceToClosestTick(price)
return nearestUsableTick(tick, pool.tickSpacing) return nearestUsableTick(tick, TICK_SPACINGS[feeAmount])
} }
import { Token, Price } from '@uniswap/sdk-core' import { Token, Price } from '@uniswap/sdk-core'
import { tickToPrice } from '@uniswap/v3-sdk' import { tickToPrice } from '@uniswap/v3-sdk'
export function getTickToPrice( export function getTickToPrice(baseToken?: Token, quoteToken?: Token, tick?: number): Price | undefined {
baseToken: Token | undefined, if (!baseToken || !quoteToken || typeof tick !== 'number') {
quoteToken: Token | undefined,
tick: number | undefined
): Price | undefined {
if (!baseToken || !quoteToken || tick === undefined) {
return undefined return undefined
} }
return tickToPrice(baseToken, quoteToken, tick) return tickToPrice(baseToken, quoteToken, tick)
......
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