Commit 925668c7 authored by Noah Zinsmeister's avatar Noah Zinsmeister

get skeleton remove working

parent d1fad3c4
...@@ -147,7 +147,7 @@ export default function PositionListItem({ positionDetails, positionIndex }: Pos ...@@ -147,7 +147,7 @@ export default function PositionListItem({ positionDetails, positionIndex }: Pos
const [poolState, pool] = usePool(currency0 ?? undefined, currency1 ?? undefined, feeAmount) const [poolState, pool] = usePool(currency0 ?? undefined, currency1 ?? undefined, feeAmount)
const position = useMemo(() => { const position = useMemo(() => {
if (pool) { if (pool) {
return new Position({ pool, liquidity, tickLower, tickUpper }) return new Position({ pool, liquidity: liquidity.toString(), tickLower, tickUpper })
} }
return undefined return undefined
}, [liquidity, pool, tickLower, tickUpper]) }, [liquidity, pool, tickLower, tickUpper])
......
...@@ -11,10 +11,10 @@ import { FACTORY_ADDRESSES } from 'constants/v3' ...@@ -11,10 +11,10 @@ import { FACTORY_ADDRESSES } from 'constants/v3'
import { useAllV3Ticks } from 'hooks/useAllV3Ticks' import { useAllV3Ticks } from 'hooks/useAllV3Ticks'
export enum PoolState { export enum PoolState {
LOADING, LOADING = 'LOADING',
NOT_EXISTS, NOT_EXISTS = 'NOT_EXISTS',
EXISTS, EXISTS = 'EXISTS',
INVALID, INVALID = 'INVALID',
} }
export function usePool(currencyA?: Currency, currencyB?: Currency, feeAmount?: FeeAmount): [PoolState, Pool | null] { export function usePool(currencyA?: Currency, currencyB?: Currency, feeAmount?: FeeAmount): [PoolState, Pool | null] {
......
...@@ -70,7 +70,7 @@ export function useAllV3Ticks( ...@@ -70,7 +70,7 @@ export function useAllV3Ticks(
'getPopulatedTicksInWord', 'getPopulatedTicksInWord',
tickLensArgs, tickLensArgs,
REFRESH_FREQUENCY, REFRESH_FREQUENCY,
1_500_000 3_000_000
) )
const error = useMemo(() => callStates.some(({ error }) => error), [callStates]) const error = useMemo(() => callStates.some(({ error }) => error), [callStates])
......
...@@ -2,17 +2,17 @@ import { useSingleCallResult, useSingleContractMultipleData, Result } from 'stat ...@@ -2,17 +2,17 @@ import { useSingleCallResult, useSingleContractMultipleData, Result } from 'stat
import { useMemo } from 'react' import { useMemo } from 'react'
import { PositionDetails } from 'types/position' import { PositionDetails } from 'types/position'
import { useV3NFTPositionManagerContract } from './useContract' import { useV3NFTPositionManagerContract } from './useContract'
import { BigNumber, BigNumberish } from '@ethersproject/bignumber' import { BigNumber } from '@ethersproject/bignumber'
interface UseV3PositionsResults { interface UseV3PositionsResults {
loading: boolean loading: boolean
error: boolean error: boolean
positions: PositionDetails[] | undefined positions: (PositionDetails & { tokenId: BigNumber })[] | undefined
} }
function useV3PositionsFromTokenIds(tokenIds: BigNumberish[]): UseV3PositionsResults { function useV3PositionsFromTokenIds(tokenIds: BigNumber[]): UseV3PositionsResults {
const positionManager = useV3NFTPositionManagerContract() const positionManager = useV3NFTPositionManagerContract()
const inputs = useMemo(() => tokenIds.map((tokenId) => [BigNumber.from(tokenId)]), [tokenIds]) const inputs = useMemo(() => tokenIds.map((tokenId) => [tokenId]), [tokenIds])
const results = useSingleContractMultipleData(positionManager ?? undefined, 'positions', inputs) const results = useSingleContractMultipleData(positionManager ?? undefined, 'positions', inputs)
const loading = useMemo(() => results.some(({ loading }) => loading), [results]) const loading = useMemo(() => results.some(({ loading }) => loading), [results])
...@@ -44,17 +44,17 @@ function useV3PositionsFromTokenIds(tokenIds: BigNumberish[]): UseV3PositionsRes ...@@ -44,17 +44,17 @@ function useV3PositionsFromTokenIds(tokenIds: BigNumberish[]): UseV3PositionsRes
return { return {
loading, loading,
error, error,
positions, positions: positions?.map((position, i) => ({ ...position, tokenId: inputs[i][0] })),
} }
} }
interface UseV3PositionResults { interface UseV3PositionResults {
loading: boolean loading: boolean
error: boolean error: boolean
position: PositionDetails | undefined position: (PositionDetails & { tokenId: BigNumber }) | undefined
} }
export function useV3PositionFromTokenId(tokenId: BigNumberish): UseV3PositionResults { export function useV3PositionFromTokenId(tokenId: BigNumber): UseV3PositionResults {
const position = useV3PositionsFromTokenIds([tokenId]) const position = useV3PositionsFromTokenIds([tokenId])
return { return {
loading: position.loading, loading: position.loading,
......
...@@ -47,7 +47,7 @@ function LiquidityInfo({ token0Amount, token1Amount }: { token0Amount: TokenAmou ...@@ -47,7 +47,7 @@ function LiquidityInfo({ token0Amount, token1Amount }: { token0Amount: TokenAmou
</Text> </Text>
<RowFixed> <RowFixed>
<Text fontSize={16} fontWeight={500} marginLeft={'6px'}> <Text fontSize={16} fontWeight={500} marginLeft={'6px'}>
{token0Amount.toSignificant(4)} <FormattedCurrencyAmount currencyAmount={token0Amount} />
</Text> </Text>
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={token0Amount.token} /> <CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={token0Amount.token} />
</RowFixed> </RowFixed>
......
...@@ -4,7 +4,7 @@ import { PoolState, usePool } from 'data/Pools' ...@@ -4,7 +4,7 @@ import { PoolState, usePool } from 'data/Pools'
import { useActiveWeb3React } from 'hooks' import { useActiveWeb3React } from 'hooks'
import { useToken } from 'hooks/Tokens' import { useToken } from 'hooks/Tokens'
import { useV3Positions } from 'hooks/useV3Positions' import { useV3Positions } from 'hooks/useV3Positions'
import { RouteComponentProps } from 'react-router-dom' import { RouteComponentProps, Link } from 'react-router-dom'
import { unwrappedToken } from 'utils/wrappedCurrency' import { unwrappedToken } from 'utils/wrappedCurrency'
import { LoadingRows } from './styleds' import { LoadingRows } from './styleds'
import styled from 'styled-components' import styled from 'styled-components'
...@@ -99,6 +99,7 @@ export function PositionPage({ ...@@ -99,6 +99,7 @@ export function PositionPage({
liquidity, liquidity,
tickLower, tickLower,
tickUpper, tickUpper,
tokenId,
// feeGrowthInside0LastX128, // feeGrowthInside0LastX128,
// feeGrowthInside1LastX128, // feeGrowthInside1LastX128,
} = positionDetails || {} } = positionDetails || {}
...@@ -112,8 +113,8 @@ export function PositionPage({ ...@@ -112,8 +113,8 @@ export function PositionPage({
// construct Position from details returned // construct Position from details returned
const [poolState, pool] = usePool(currency0 ?? undefined, currency1 ?? undefined, feeAmount) const [poolState, pool] = usePool(currency0 ?? undefined, currency1 ?? undefined, feeAmount)
const position = useMemo(() => { const position = useMemo(() => {
if (pool && tickLower && tickUpper) { if (pool && liquidity && tickLower && tickUpper) {
return new Position({ pool, liquidity, tickLower, tickUpper }) return new Position({ pool, liquidity: liquidity.toString(), tickLower, tickUpper })
} }
return undefined return undefined
}, [liquidity, pool, tickLower, tickUpper]) }, [liquidity, pool, tickLower, tickUpper])
...@@ -156,9 +157,11 @@ export function PositionPage({ ...@@ -156,9 +157,11 @@ export function PositionPage({
<BadgeText>{basisPointsToPercent(feeAmount / 100).toSignificant()}%</BadgeText> <BadgeText>{basisPointsToPercent(feeAmount / 100).toSignificant()}%</BadgeText>
</Badge> </Badge>
</RowFixed> </RowFixed>
<ButtonPrimary width="200px" padding="8px" borderRadius="12px"> {tokenId && (
Remove liquidity <ButtonPrimary width="200px" padding="8px" borderRadius="12px" as={Link} to={`/remove/${tokenId}`}>
</ButtonPrimary> Remove liquidity
</ButtonPrimary>
)}
</RowBetween> </RowBetween>
<RowBetween> <RowBetween>
<BadgeWrapper> <BadgeWrapper>
......
import React, { useCallback, useMemo } from 'react'
import { useV3PositionFromTokenId } from 'hooks/useV3Positions' import { useV3PositionFromTokenId } from 'hooks/useV3Positions'
import React from 'react'
import { RouteComponentProps } from 'react-router' import { RouteComponentProps } from 'react-router'
import { Redirect } from 'react-router-dom'
import AppBody from '../AppBody' import AppBody from '../AppBody'
import { BigNumber } from '@ethersproject/bignumber'
import useDebouncedChangeHandler from 'hooks/useDebouncedChangeHandler'
import { useBurnV3ActionHandlers, useBurnV3State, useDerivedV3BurnInfo } from 'state/burn/v3/hooks'
import Slider from 'components/Slider'
import { RowBetween, RowFixed } from 'components/Row'
import { MaxButton } from 'pages/Pool/styleds'
import { AutoColumn } from 'components/Column'
import { ButtonConfirmed } from 'components/Button'
import { LightCard } from 'components/Card'
import { Text } from 'rebass'
import CurrencyLogo from 'components/CurrencyLogo'
import FormattedCurrencyAmount from 'components/FormattedCurrencyAmount'
import { useV3NFTPositionManagerContract } from 'hooks/useContract'
import { useUserSlippageTolerance } from 'state/user/hooks'
import useTransactionDeadline from 'hooks/useTransactionDeadline'
import JSBI from 'jsbi'
import ReactGA from 'react-ga'
import { useActiveWeb3React } from 'hooks'
import { TransactionResponse } from '@ethersproject/providers'
import { useTransactionAdder } from 'state/transactions/hooks'
// TODO // TODO still a lot of polishing left here
const UINT128MAX = BigNumber.from(2).pow(128).sub(1)
// redirect invalid tokenIds
export default function RemoveLiquidityV3({ export default function RemoveLiquidityV3({
location,
match: { match: {
params: { tokenId }, params: { tokenId },
}, },
}: RouteComponentProps<{ tokenId: string }>) { }: RouteComponentProps<{ tokenId: string }>) {
const parsedTokenId = useMemo(() => {
try {
return BigNumber.from(tokenId)
} catch {
return null
}
}, [tokenId])
if (parsedTokenId === null || parsedTokenId.eq(0)) {
return <Redirect to={{ ...location, pathname: '/pool' }} />
}
return <Remove tokenId={parsedTokenId} />
}
function Remove({ tokenId }: { tokenId: BigNumber }) {
const position = useV3PositionFromTokenId(tokenId) const position = useV3PositionFromTokenId(tokenId)
// check that account actually owns the position const { account } = useActiveWeb3React()
console.log(position)
// burn state
const { percent } = useBurnV3State()
const { liquidity, liquidityValue0, liquidityValue1, feeValue0, feeValue1, error } = useDerivedV3BurnInfo(
position?.position
)
const { onPercentSelect } = useBurnV3ActionHandlers()
// boilerplate for the slider
const [percentForSlider, onPercentSelectForSlider] = useDebouncedChangeHandler(percent, onPercentSelect)
const deadline = useTransactionDeadline() // custom from users settings
const [allowedSlippage] = useUserSlippageTolerance() // custom from users
const addTransaction = useTransactionAdder()
const positionManager = useV3NFTPositionManagerContract()
const burn = useCallback(() => {
if (!liquidity || !positionManager || !liquidityValue0 || !liquidityValue1 || !deadline || !account) return
const data = []
// decreaseLiquidity if necessary
if (liquidity.gt(0)) {
data.push(
positionManager.interface.encodeFunctionData('decreaseLiquidity', [
{
tokenId,
liquidity,
amount0Min: `0x${JSBI.divide(
JSBI.multiply(liquidityValue0.raw, JSBI.BigInt(10000 - allowedSlippage)),
JSBI.BigInt(10000)
).toString(16)}`,
amount1Min: `0x${JSBI.divide(
JSBI.multiply(liquidityValue1.raw, JSBI.BigInt(10000 - allowedSlippage)),
JSBI.BigInt(10000)
).toString(16)}`,
deadline,
},
])
)
}
data.push(
positionManager.interface.encodeFunctionData('collect', [
{
tokenId,
recipient: account,
amount0Max: UINT128MAX,
amount1Max: UINT128MAX,
},
])
)
positionManager
.multicall(data)
.then((response: TransactionResponse) => {
ReactGA.event({
category: 'Liquidity',
action: 'RemoveV3',
label: [liquidityValue0.token.symbol, liquidityValue1.token.symbol].join('/'),
})
addTransaction(response, {
summary: `Remove ${liquidityValue0.token.symbol}/${liquidityValue1.token.symbol} V3 liquidity`,
})
})
.catch((error) => {
console.error(error)
})
}, [
tokenId,
liquidity,
liquidityValue0,
liquidityValue1,
deadline,
allowedSlippage,
account,
addTransaction,
positionManager,
])
return (
<AppBody>
<>
<Slider value={percentForSlider} onChange={onPercentSelectForSlider} />
<RowBetween>
<MaxButton onClick={() => onPercentSelect(25)} width="20%">
25%
</MaxButton>
<MaxButton onClick={() => onPercentSelect(50)} width="20%">
50%
</MaxButton>
<MaxButton onClick={() => onPercentSelect(75)} width="20%">
75%
</MaxButton>
<MaxButton onClick={() => onPercentSelect(100)} width="20%">
Max
</MaxButton>
</RowBetween>
<RowBetween my="1rem">
<Text fontSize={16} fontWeight={500}>
Pooled {liquidityValue0?.token?.symbol}:
</Text>
<RowFixed>
<Text fontSize={16} fontWeight={500} marginLeft={'6px'}>
{liquidityValue0 && <FormattedCurrencyAmount currencyAmount={liquidityValue0} />}
</Text>
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={liquidityValue0?.token} />
</RowFixed>
</RowBetween>
<RowBetween mb="1rem">
<Text fontSize={16} fontWeight={500}>
Pooled {liquidityValue1?.token?.symbol}:
</Text>
<RowFixed>
<Text fontSize={16} fontWeight={500} marginLeft={'6px'}>
{liquidityValue1 && <FormattedCurrencyAmount currencyAmount={liquidityValue1} />}
</Text>
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={liquidityValue1?.token} />
</RowFixed>
</RowBetween>
<RowBetween my="1rem">
<Text fontSize={16} fontWeight={500}>
{feeValue0?.token?.symbol} Fees:
</Text>
<RowFixed>
<Text fontSize={16} fontWeight={500} marginLeft={'6px'}>
{feeValue0 && <FormattedCurrencyAmount currencyAmount={feeValue0} />}
</Text>
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={feeValue0?.token} />
</RowFixed>
</RowBetween>
<RowBetween mb="1rem">
<Text fontSize={16} fontWeight={500}>
{feeValue1?.token?.symbol} Fees:
</Text>
<RowFixed>
<Text fontSize={16} fontWeight={500} marginLeft={'6px'}>
{feeValue1 && <FormattedCurrencyAmount currencyAmount={feeValue1} />}
</Text>
<CurrencyLogo size="20px" style={{ marginLeft: '8px' }} currency={feeValue1?.token} />
</RowFixed>
</RowBetween>
return <AppBody>TODO</AppBody> <LightCard>
<div style={{ display: 'flex', marginTop: '1rem' }}>
<AutoColumn gap="12px" style={{ flex: '1' }}>
<ButtonConfirmed confirmed={false} disabled={!liquidity} onClick={burn}>
{error ?? liquidity?.eq(0) ? 'Collect' : 'Burn'}
</ButtonConfirmed>
</AutoColumn>
</div>
</LightCard>
</>
</AppBody>
)
} }
import { createAction } from '@reduxjs/toolkit'
export const selectPercent = createAction<{ percent: number }>('burnV3/selectBurnPercent')
import { BigNumber } from '@ethersproject/bignumber'
import { TokenAmount } from '@uniswap/sdk-core'
import { Position } from '@uniswap/v3-sdk'
import { usePool } from 'data/Pools'
import { useActiveWeb3React } from 'hooks'
import { useToken } from 'hooks/Tokens'
import { useCallback, useMemo } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { PositionDetails } from 'types/position'
import { AppDispatch, AppState } from '../../index'
import { selectPercent } from './actions'
export function useBurnV3State(): AppState['burnV3'] {
return useSelector<AppState, AppState['burnV3']>((state) => state.burnV3)
}
export function useDerivedV3BurnInfo(
position?: PositionDetails & { tokenId: BigNumber }
): {
liquidity?: BigNumber
liquidityValue0?: TokenAmount
liquidityValue1?: TokenAmount
feeValue0?: TokenAmount
feeValue1?: TokenAmount
error?: string
} {
const { account } = useActiveWeb3React()
const { percent } = useBurnV3State()
const token0 = useToken(position?.token0)
const token1 = useToken(position?.token1)
const [, pool] = usePool(token0 ?? undefined, token1 ?? undefined, position?.fee)
const liquidity = position?.liquidity ? position.liquidity.mul(percent).div(100) : undefined
const positionSDK = useMemo(
() =>
pool && liquidity && position?.tickLower && position?.tickLower
? new Position({
pool,
liquidity: liquidity.toString(),
tickLower: position?.tickLower,
tickUpper: position?.tickUpper,
})
: undefined,
[pool, liquidity, position]
)
const liquidityValue0 = positionSDK?.amount0
const liquidityValue1 = positionSDK?.amount1
// TODO include counterfactual fees calculate from fee growth snapshots here
const feeValue0 =
token0 && position?.tokensOwed0 ? new TokenAmount(token0, position.tokensOwed0.toString()) : undefined
const feeValue1 =
token1 && position?.tokensOwed1 ? new TokenAmount(token1, position.tokensOwed1.toString()) : undefined
let error: string | undefined
if (!account) {
error = 'Connect Wallet'
}
if (percent === 0) {
error = error ?? 'Enter an percent'
}
return { liquidity, liquidityValue0, liquidityValue1, feeValue0, feeValue1, error }
}
export function useBurnV3ActionHandlers(): {
onPercentSelect: (percent: number) => void
} {
const dispatch = useDispatch<AppDispatch>()
const onPercentSelect = useCallback(
(percent: number) => {
dispatch(selectPercent({ percent }))
},
[dispatch]
)
return {
onPercentSelect,
}
}
import { createReducer } from '@reduxjs/toolkit'
import { selectPercent } from './actions'
export interface BurnV3State {
readonly percent: number
}
const initialState: BurnV3State = {
percent: 0,
}
export default createReducer<BurnV3State>(initialState, (builder) =>
builder.addCase(selectPercent, (state, { payload: { percent } }) => {
return {
...state,
percent,
}
})
)
...@@ -9,6 +9,7 @@ import swap from './swap/reducer' ...@@ -9,6 +9,7 @@ import swap from './swap/reducer'
import mint from './mint/reducer' import mint from './mint/reducer'
import lists from './lists/reducer' import lists from './lists/reducer'
import burn from './burn/reducer' import burn from './burn/reducer'
import burnV3 from './burn/v3/reducer'
import multicall from './multicall/reducer' import multicall from './multicall/reducer'
const PERSISTED_KEYS: string[] = ['user', 'transactions', 'lists'] const PERSISTED_KEYS: string[] = ['user', 'transactions', 'lists']
...@@ -21,6 +22,7 @@ const store = configureStore({ ...@@ -21,6 +22,7 @@ const store = configureStore({
swap, swap,
mint, mint,
burn, burn,
burnV3,
multicall, multicall,
lists, lists,
}, },
......
import { BigNumber } from '@ethersproject/bignumber'
export interface PositionDetails { export interface PositionDetails {
nonce: BigNumber nonce: BigNumber
operator: string operator: string
......
...@@ -4134,45 +4134,40 @@ ...@@ -4134,45 +4134,40 @@
tiny-invariant "^1.1.0" tiny-invariant "^1.1.0"
tiny-warning "^1.0.3" tiny-warning "^1.0.3"
"@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==
"@uniswap/v3-core@1.0.0-rc.2", "@uniswap/v3-core@^1.0.0-rc.2": "@uniswap/v3-core@1.0.0-rc.2", "@uniswap/v3-core@^1.0.0-rc.2":
version "1.0.0-rc.2" version "1.0.0-rc.2"
resolved "https://registry.yarnpkg.com/@uniswap/v3-core/-/v3-core-1.0.0-rc.2.tgz#a1afb3253a7295bec6165ad1d960121e6851a576" resolved "https://registry.yarnpkg.com/@uniswap/v3-core/-/v3-core-1.0.0-rc.2.tgz#a1afb3253a7295bec6165ad1d960121e6851a576"
integrity sha512-vsqkqAHPCKsVi0nWwWeX+mHnSTJ8ZUdu1zAVXB9Mj9A+aeBQGV9foRKs9ufDGJq7S1nqmz+7FdjSOcVoeiUqgQ== integrity sha512-vsqkqAHPCKsVi0nWwWeX+mHnSTJ8ZUdu1zAVXB9Mj9A+aeBQGV9foRKs9ufDGJq7S1nqmz+7FdjSOcVoeiUqgQ==
"@uniswap/v3-periphery@^1.0.0-beta.17": "@uniswap/v3-periphery@^1.0.0-beta.20":
version "1.0.0-beta.19" version "1.0.0-beta.20"
resolved "https://registry.yarnpkg.com/@uniswap/v3-periphery/-/v3-periphery-1.0.0-beta.19.tgz#d9af90b12657049674cd2f26ae1c61b6cc393261" resolved "https://registry.yarnpkg.com/@uniswap/v3-periphery/-/v3-periphery-1.0.0-beta.20.tgz#67a8086315e4820e3669b1f645916f9e246a6e56"
integrity sha512-ZQX5KN/89OB7UjrmGOSB7QZIEbgW+R0uaVM5NdlK63Ji0rZjmddeoYS8oNk7i5BU3WR+xJY5DgfiDSmn1W6Sww== integrity sha512-sWh2W+CBjRVAwbPbKwgu8DWKYY7J3ucZf5mjRPBnmvsNLi6ILM5/NDAtefCvMnKEX7IQzO3gk7gDWZHPrkWXyw==
dependencies: dependencies:
"@openzeppelin/contracts" "3.4.1-solc-0.7-2" "@openzeppelin/contracts" "3.4.1-solc-0.7-2"
"@uniswap/lib" "^4.0.1-alpha" "@uniswap/lib" "^4.0.1-alpha"
"@uniswap/v2-core" "1.0.1" "@uniswap/v2-core" "1.0.1"
"@uniswap/v3-core" "1.0.0-rc.1" "@uniswap/v3-core" "1.0.0-rc.2"
"@uniswap/v3-periphery@^1.0.0-beta.20": "@uniswap/v3-periphery@^1.0.0-beta.21":
version "1.0.0-beta.20" version "1.0.0-beta.21"
resolved "https://registry.yarnpkg.com/@uniswap/v3-periphery/-/v3-periphery-1.0.0-beta.20.tgz#67a8086315e4820e3669b1f645916f9e246a6e56" resolved "https://registry.yarnpkg.com/@uniswap/v3-periphery/-/v3-periphery-1.0.0-beta.21.tgz#0b8510bebca4b74aabdca72c5545bd5bec5128cd"
integrity sha512-sWh2W+CBjRVAwbPbKwgu8DWKYY7J3ucZf5mjRPBnmvsNLi6ILM5/NDAtefCvMnKEX7IQzO3gk7gDWZHPrkWXyw== integrity sha512-o4U+lyH6qtlG2RTy3H/mtUGJuflkmVJ0pnXyrThZKC1KV/avlVgf4hmlG2PvOCV0yfwGMjQARKQ4jv6OpLFVqA==
dependencies: dependencies:
"@openzeppelin/contracts" "3.4.1-solc-0.7-2" "@openzeppelin/contracts" "3.4.1-solc-0.7-2"
"@uniswap/lib" "^4.0.1-alpha" "@uniswap/lib" "^4.0.1-alpha"
"@uniswap/v2-core" "1.0.1" "@uniswap/v2-core" "1.0.1"
"@uniswap/v3-core" "1.0.0-rc.2" "@uniswap/v3-core" "1.0.0-rc.2"
"@uniswap/v3-sdk@^1.0.0-alpha.11": "@uniswap/v3-sdk@^1.0.0-alpha.13":
version "1.0.0-alpha.11" version "1.0.0-alpha.13"
resolved "https://registry.yarnpkg.com/@uniswap/v3-sdk/-/v3-sdk-1.0.0-alpha.11.tgz#184ed5ee8322b27f35aa830ad5e217b5dda6bd67" resolved "https://registry.yarnpkg.com/@uniswap/v3-sdk/-/v3-sdk-1.0.0-alpha.13.tgz#5634bb361e6bcb8e1a05d79a2aa61ffe13412f0c"
integrity sha512-Tl4IzxlukT/vg+3hMLhwDqNDd0tg1rN5ODbrlTlOTJRg6+fyBvrM9y10nRftjS5e5nzyq+owDIQh8BBhb86CBw== integrity sha512-OEEMhMoJlRQyqcd6u4r37cyifVy5jKJf/afW1jD8iqRqg/qAiYG0aR9Y/s7HiDA9WVHyaL/0YsWG8f0hv2UK/w==
dependencies: dependencies:
"@ethersproject/abi" "^5.0.12" "@ethersproject/abi" "^5.0.12"
"@ethersproject/solidity" "^5.0.9" "@ethersproject/solidity" "^5.0.9"
"@uniswap/sdk-core" "^1.0.9" "@uniswap/sdk-core" "^1.0.9"
"@uniswap/v3-periphery" "^1.0.0-beta.17" "@uniswap/v3-periphery" "^1.0.0-beta.21"
tiny-invariant "^1.1.0" tiny-invariant "^1.1.0"
tiny-warning "^1.0.3" tiny-warning "^1.0.3"
......
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