feat: use TickLens on chains where subgraph is not functional (#3149)
This commit is contained in:
parent
b878d764e5
commit
c9642c6cd0
@ -1,16 +1,10 @@
|
|||||||
import { Currency } from '@uniswap/sdk-core'
|
import { Currency } from '@uniswap/sdk-core'
|
||||||
import { FeeAmount } from '@uniswap/v3-sdk'
|
import { FeeAmount } from '@uniswap/v3-sdk'
|
||||||
import { usePoolActiveLiquidity } from 'hooks/usePoolTickData'
|
import { TickProcessed, usePoolActiveLiquidity } from 'hooks/usePoolTickData'
|
||||||
import JSBI from 'jsbi'
|
|
||||||
import { useCallback, useMemo } from 'react'
|
import { useCallback, useMemo } from 'react'
|
||||||
|
|
||||||
import { ChartEntry } from './types'
|
import { ChartEntry } from './types'
|
||||||
|
|
||||||
export interface TickProcessed {
|
|
||||||
liquidityActive: JSBI
|
|
||||||
price0: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useDensityChartData({
|
export function useDensityChartData({
|
||||||
currencyA,
|
currencyA,
|
||||||
currencyB,
|
currencyB,
|
||||||
|
@ -107,3 +107,8 @@ export const V3_MIGRATOR_ADDRESSES: AddressMap = constructSameAddressMap('0xA564
|
|||||||
SupportedChainId.POLYGON_MUMBAI,
|
SupportedChainId.POLYGON_MUMBAI,
|
||||||
SupportedChainId.POLYGON,
|
SupportedChainId.POLYGON,
|
||||||
])
|
])
|
||||||
|
|
||||||
|
export const TICK_LENS_ADDRESSES: AddressMap = {
|
||||||
|
[SupportedChainId.ARBITRUM_ONE]: '0xbfd8137f7d1516D3ea5cA83523914859ec47F573',
|
||||||
|
[SupportedChainId.ARBITRUM_RINKEBY]: '0xbfd8137f7d1516D3ea5cA83523914859ec47F573',
|
||||||
|
}
|
||||||
|
@ -6,6 +6,7 @@ import { abi as MERKLE_DISTRIBUTOR_ABI } from '@uniswap/merkle-distributor/build
|
|||||||
import { abi as IUniswapV2PairABI } from '@uniswap/v2-core/build/IUniswapV2Pair.json'
|
import { abi as IUniswapV2PairABI } from '@uniswap/v2-core/build/IUniswapV2Pair.json'
|
||||||
import { abi as IUniswapV2Router02ABI } from '@uniswap/v2-periphery/build/IUniswapV2Router02.json'
|
import { abi as IUniswapV2Router02ABI } from '@uniswap/v2-periphery/build/IUniswapV2Router02.json'
|
||||||
import { abi as QuoterABI } from '@uniswap/v3-periphery/artifacts/contracts/lens/Quoter.sol/Quoter.json'
|
import { abi as QuoterABI } from '@uniswap/v3-periphery/artifacts/contracts/lens/Quoter.sol/Quoter.json'
|
||||||
|
import { abi as TickLensABI } from '@uniswap/v3-periphery/artifacts/contracts/lens/TickLens.sol/TickLens.json'
|
||||||
import { abi as MulticallABI } from '@uniswap/v3-periphery/artifacts/contracts/lens/UniswapInterfaceMulticall.sol/UniswapInterfaceMulticall.json'
|
import { abi as MulticallABI } from '@uniswap/v3-periphery/artifacts/contracts/lens/UniswapInterfaceMulticall.sol/UniswapInterfaceMulticall.json'
|
||||||
import { abi as NFTPositionManagerABI } from '@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json'
|
import { abi as NFTPositionManagerABI } from '@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json'
|
||||||
import { abi as V2MigratorABI } from '@uniswap/v3-periphery/artifacts/contracts/V3Migrator.sol/V3Migrator.json'
|
import { abi as V2MigratorABI } from '@uniswap/v3-periphery/artifacts/contracts/V3Migrator.sol/V3Migrator.json'
|
||||||
@ -30,13 +31,14 @@ import {
|
|||||||
MULTICALL_ADDRESS,
|
MULTICALL_ADDRESS,
|
||||||
NONFUNGIBLE_POSITION_MANAGER_ADDRESSES,
|
NONFUNGIBLE_POSITION_MANAGER_ADDRESSES,
|
||||||
QUOTER_ADDRESSES,
|
QUOTER_ADDRESSES,
|
||||||
|
TICK_LENS_ADDRESSES,
|
||||||
V2_ROUTER_ADDRESS,
|
V2_ROUTER_ADDRESS,
|
||||||
V3_MIGRATOR_ADDRESSES,
|
V3_MIGRATOR_ADDRESSES,
|
||||||
} from 'constants/addresses'
|
} from 'constants/addresses'
|
||||||
import { UNI, WRAPPED_NATIVE_CURRENCY } from 'constants/tokens'
|
import { UNI, WRAPPED_NATIVE_CURRENCY } from 'constants/tokens'
|
||||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
import { NonfungiblePositionManager, Quoter, UniswapInterfaceMulticall } from 'types/v3'
|
import { NonfungiblePositionManager, Quoter, TickLens, UniswapInterfaceMulticall } from 'types/v3'
|
||||||
import { V3Migrator } from 'types/v3/V3Migrator'
|
import { V3Migrator } from 'types/v3/V3Migrator'
|
||||||
|
|
||||||
import { getContract } from '../utils'
|
import { getContract } from '../utils'
|
||||||
@ -159,3 +161,9 @@ export function useV3NFTPositionManagerContract(withSignerIfPossible?: boolean):
|
|||||||
export function useV3Quoter() {
|
export function useV3Quoter() {
|
||||||
return useContract<Quoter>(QUOTER_ADDRESSES, QuoterABI)
|
return useContract<Quoter>(QUOTER_ADDRESSES, QuoterABI)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useTickLens(): TickLens | null {
|
||||||
|
const { chainId } = useActiveWeb3React()
|
||||||
|
const address = chainId ? TICK_LENS_ADDRESSES[chainId] : undefined
|
||||||
|
return useContract(address, TickLensABI) as TickLens | null
|
||||||
|
}
|
||||||
|
@ -1,30 +1,136 @@
|
|||||||
import { skipToken } from '@reduxjs/toolkit/query/react'
|
import { skipToken } from '@reduxjs/toolkit/query/react'
|
||||||
import { Currency } from '@uniswap/sdk-core'
|
import { Currency } from '@uniswap/sdk-core'
|
||||||
import { FeeAmount, Pool, TICK_SPACINGS, tickToPrice } from '@uniswap/v3-sdk'
|
import { ChainId } from '@uniswap/smart-order-router'
|
||||||
|
import { FeeAmount, nearestUsableTick, Pool, TICK_SPACINGS, tickToPrice } from '@uniswap/v3-sdk'
|
||||||
|
import { ZERO_ADDRESS } from 'constants/misc'
|
||||||
import JSBI from 'jsbi'
|
import JSBI from 'jsbi'
|
||||||
|
import { useSingleContractMultipleData } from 'lib/hooks/multicall'
|
||||||
import ms from 'ms.macro'
|
import ms from 'ms.macro'
|
||||||
import { useMemo } from 'react'
|
import { useEffect, useMemo, useState } from 'react'
|
||||||
import { useAllV3TicksQuery } from 'state/data/enhanced'
|
import { useAllV3TicksQuery } from 'state/data/enhanced'
|
||||||
import { AllV3TicksQuery } from 'state/data/generated'
|
|
||||||
import computeSurroundingTicks from 'utils/computeSurroundingTicks'
|
import computeSurroundingTicks from 'utils/computeSurroundingTicks'
|
||||||
|
|
||||||
|
import { useTickLens } from './useContract'
|
||||||
import { PoolState, usePool } from './usePools'
|
import { PoolState, usePool } from './usePools'
|
||||||
|
|
||||||
const PRICE_FIXED_DIGITS = 8
|
const PRICE_FIXED_DIGITS = 8
|
||||||
|
const CHAIN_IDS_MISSING_SUBGRAPH_DATA = [ChainId.ARBITRUM_ONE, ChainId.ARBITRUM_RINKEBY]
|
||||||
|
|
||||||
|
export interface TickData {
|
||||||
|
tick: number
|
||||||
|
liquidityNet: JSBI
|
||||||
|
liquidityGross: JSBI
|
||||||
|
}
|
||||||
|
|
||||||
// Tick with fields parsed to JSBIs, and active liquidity computed.
|
// Tick with fields parsed to JSBIs, and active liquidity computed.
|
||||||
export interface TickProcessed {
|
export interface TickProcessed {
|
||||||
tickIdx: number
|
tick: number
|
||||||
liquidityActive: JSBI
|
liquidityActive: JSBI
|
||||||
liquidityNet: JSBI
|
liquidityNet: JSBI
|
||||||
price0: string
|
price0: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const REFRESH_FREQUENCY = { blocksPerFetch: 2 }
|
||||||
|
|
||||||
const getActiveTick = (tickCurrent: number | undefined, feeAmount: FeeAmount | undefined) =>
|
const getActiveTick = (tickCurrent: number | undefined, feeAmount: FeeAmount | undefined) =>
|
||||||
tickCurrent && feeAmount ? Math.floor(tickCurrent / TICK_SPACINGS[feeAmount]) * TICK_SPACINGS[feeAmount] : undefined
|
tickCurrent && feeAmount ? Math.floor(tickCurrent / TICK_SPACINGS[feeAmount]) * TICK_SPACINGS[feeAmount] : undefined
|
||||||
|
|
||||||
// Fetches all ticks for a given pool
|
const bitmapIndex = (tick: number, tickSpacing: number) => {
|
||||||
export function useAllV3Ticks(
|
return Math.floor(tick / tickSpacing / 256)
|
||||||
|
}
|
||||||
|
|
||||||
|
function useTicksFromTickLens(
|
||||||
|
currencyA: Currency | undefined,
|
||||||
|
currencyB: Currency | undefined,
|
||||||
|
feeAmount: FeeAmount | undefined,
|
||||||
|
numSurroundingTicks: number | undefined = 125
|
||||||
|
) {
|
||||||
|
const [tickDataLatestSynced, setTickDataLatestSynced] = useState<TickData[]>([])
|
||||||
|
|
||||||
|
const [poolState, pool] = usePool(currencyA, currencyB, feeAmount)
|
||||||
|
|
||||||
|
const tickSpacing = feeAmount && TICK_SPACINGS[feeAmount]
|
||||||
|
|
||||||
|
// Find nearest valid tick for pool in case tick is not initialized.
|
||||||
|
const activeTick = pool?.tickCurrent && tickSpacing ? nearestUsableTick(pool?.tickCurrent, tickSpacing) : undefined
|
||||||
|
|
||||||
|
const poolAddress =
|
||||||
|
currencyA && currencyB && feeAmount && poolState === PoolState.EXISTS
|
||||||
|
? Pool.getAddress(currencyA?.wrapped, currencyB?.wrapped, feeAmount)
|
||||||
|
: undefined
|
||||||
|
|
||||||
|
// it is also possible to grab all tick data but it is extremely slow
|
||||||
|
// bitmapIndex(nearestUsableTick(TickMath.MIN_TICK, tickSpacing), tickSpacing)
|
||||||
|
const minIndex = useMemo(
|
||||||
|
() =>
|
||||||
|
tickSpacing && activeTick ? bitmapIndex(activeTick - numSurroundingTicks * tickSpacing, tickSpacing) : undefined,
|
||||||
|
[tickSpacing, activeTick, numSurroundingTicks]
|
||||||
|
)
|
||||||
|
|
||||||
|
const maxIndex = useMemo(
|
||||||
|
() =>
|
||||||
|
tickSpacing && activeTick ? bitmapIndex(activeTick + numSurroundingTicks * tickSpacing, tickSpacing) : undefined,
|
||||||
|
[tickSpacing, activeTick, numSurroundingTicks]
|
||||||
|
)
|
||||||
|
|
||||||
|
const tickLensArgs: [string, number][] = useMemo(
|
||||||
|
() =>
|
||||||
|
maxIndex && minIndex && poolAddress && poolAddress !== ZERO_ADDRESS
|
||||||
|
? new Array(maxIndex - minIndex + 1)
|
||||||
|
.fill(0)
|
||||||
|
.map((_, i) => i + minIndex)
|
||||||
|
.map((wordIndex) => [poolAddress, wordIndex])
|
||||||
|
: [],
|
||||||
|
[minIndex, maxIndex, poolAddress]
|
||||||
|
)
|
||||||
|
|
||||||
|
const tickLens = useTickLens()
|
||||||
|
const callStates = useSingleContractMultipleData(
|
||||||
|
tickLensArgs.length > 0 ? tickLens : undefined,
|
||||||
|
'getPopulatedTicksInWord',
|
||||||
|
tickLensArgs,
|
||||||
|
REFRESH_FREQUENCY
|
||||||
|
)
|
||||||
|
|
||||||
|
const isError = useMemo(() => callStates.some(({ error }) => error), [callStates])
|
||||||
|
const isLoading = useMemo(() => callStates.some(({ loading }) => loading), [callStates])
|
||||||
|
const IsSyncing = useMemo(() => callStates.some(({ syncing }) => syncing), [callStates])
|
||||||
|
const isValid = useMemo(() => callStates.some(({ valid }) => valid), [callStates])
|
||||||
|
|
||||||
|
const tickData: TickData[] = useMemo(
|
||||||
|
() =>
|
||||||
|
callStates
|
||||||
|
.map(({ result }) => result?.populatedTicks)
|
||||||
|
.reduce(
|
||||||
|
(accumulator, current) => [
|
||||||
|
...accumulator,
|
||||||
|
...(current?.map((tickData: TickData) => {
|
||||||
|
return {
|
||||||
|
tick: tickData.tick,
|
||||||
|
liquidityNet: JSBI.BigInt(tickData.liquidityNet),
|
||||||
|
liquidityGross: JSBI.BigInt(tickData.liquidityGross),
|
||||||
|
}
|
||||||
|
}) ?? []),
|
||||||
|
],
|
||||||
|
[]
|
||||||
|
),
|
||||||
|
[callStates]
|
||||||
|
)
|
||||||
|
|
||||||
|
// return the latest synced tickData even if we are still loading the newest data
|
||||||
|
useEffect(() => {
|
||||||
|
if (!IsSyncing && !isLoading && !isError && isValid) {
|
||||||
|
setTickDataLatestSynced(tickData.sort((a, b) => a.tick - b.tick))
|
||||||
|
}
|
||||||
|
}, [isError, isLoading, IsSyncing, tickData, isValid])
|
||||||
|
|
||||||
|
return useMemo(
|
||||||
|
() => ({ isLoading, IsSyncing, isError, isValid, tickData: tickDataLatestSynced }),
|
||||||
|
[isLoading, IsSyncing, isError, isValid, tickDataLatestSynced]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function useTicksFromSubgraph(
|
||||||
currencyA: Currency | undefined,
|
currencyA: Currency | undefined,
|
||||||
currencyB: Currency | undefined,
|
currencyB: Currency | undefined,
|
||||||
feeAmount: FeeAmount | undefined
|
feeAmount: FeeAmount | undefined
|
||||||
@ -32,19 +138,34 @@ export function useAllV3Ticks(
|
|||||||
const poolAddress =
|
const poolAddress =
|
||||||
currencyA && currencyB && feeAmount ? Pool.getAddress(currencyA?.wrapped, currencyB?.wrapped, feeAmount) : undefined
|
currencyA && currencyB && feeAmount ? Pool.getAddress(currencyA?.wrapped, currencyB?.wrapped, feeAmount) : undefined
|
||||||
|
|
||||||
const { isLoading, isError, error, isUninitialized, data } = useAllV3TicksQuery(
|
return useAllV3TicksQuery(poolAddress ? { poolAddress: poolAddress?.toLowerCase(), skip: 0 } : skipToken, {
|
||||||
poolAddress ? { poolAddress: poolAddress?.toLowerCase(), skip: 0 } : skipToken,
|
|
||||||
{
|
|
||||||
pollingInterval: ms`30s`,
|
pollingInterval: ms`30s`,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
// Fetches all ticks for a given pool
|
||||||
|
function useAllV3Ticks(
|
||||||
|
currencyA: Currency | undefined,
|
||||||
|
currencyB: Currency | undefined,
|
||||||
|
feeAmount: FeeAmount | undefined
|
||||||
|
): {
|
||||||
|
isLoading: boolean
|
||||||
|
isUninitialized: boolean
|
||||||
|
isError: boolean
|
||||||
|
error: unknown
|
||||||
|
ticks: TickData[] | undefined
|
||||||
|
} {
|
||||||
|
const useSubgraph = currencyA ? !CHAIN_IDS_MISSING_SUBGRAPH_DATA.includes(currencyA.chainId) : true
|
||||||
|
|
||||||
|
const tickLensTickData = useTicksFromTickLens(!useSubgraph ? currencyA : undefined, currencyB, feeAmount)
|
||||||
|
const subgraphTickData = useTicksFromSubgraph(useSubgraph ? currencyA : undefined, currencyB, feeAmount)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isLoading,
|
isLoading: useSubgraph ? subgraphTickData.isLoading : tickLensTickData.isLoading,
|
||||||
isUninitialized,
|
isUninitialized: useSubgraph ? subgraphTickData.isUninitialized : false,
|
||||||
isError,
|
isError: useSubgraph ? subgraphTickData.isError : tickLensTickData.isError,
|
||||||
error,
|
error: useSubgraph ? subgraphTickData.error : tickLensTickData.isError,
|
||||||
ticks: data?.ticks as AllV3TicksQuery['ticks'],
|
ticks: useSubgraph ? subgraphTickData.data?.ticks : tickLensTickData.tickData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,7 +215,7 @@ export function usePoolActiveLiquidity(
|
|||||||
// find where the active tick would be to partition the array
|
// find where the active tick would be to partition the array
|
||||||
// if the active tick is initialized, the pivot will be an element
|
// if the active tick is initialized, the pivot will be an element
|
||||||
// if not, take the previous tick as pivot
|
// if not, take the previous tick as pivot
|
||||||
const pivot = ticks.findIndex(({ tickIdx }) => tickIdx > activeTick) - 1
|
const pivot = ticks.findIndex(({ tick }) => tick > activeTick) - 1
|
||||||
|
|
||||||
if (pivot < 0) {
|
if (pivot < 0) {
|
||||||
// consider setting a local error
|
// consider setting a local error
|
||||||
@ -111,9 +232,8 @@ export function usePoolActiveLiquidity(
|
|||||||
|
|
||||||
const activeTickProcessed: TickProcessed = {
|
const activeTickProcessed: TickProcessed = {
|
||||||
liquidityActive: JSBI.BigInt(pool[1]?.liquidity ?? 0),
|
liquidityActive: JSBI.BigInt(pool[1]?.liquidity ?? 0),
|
||||||
tickIdx: activeTick,
|
tick: activeTick,
|
||||||
liquidityNet:
|
liquidityNet: Number(ticks[pivot].tick) === activeTick ? JSBI.BigInt(ticks[pivot].liquidityNet) : JSBI.BigInt(0),
|
||||||
Number(ticks[pivot].tickIdx) === activeTick ? JSBI.BigInt(ticks[pivot].liquidityNet) : JSBI.BigInt(0),
|
|
||||||
price0: tickToPrice(token0, token1, activeTick).toFixed(PRICE_FIXED_DIGITS),
|
price0: tickToPrice(token0, token1, activeTick).toFixed(PRICE_FIXED_DIGITS),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ export const api = createApi({
|
|||||||
document: gql`
|
document: gql`
|
||||||
query allV3Ticks($poolAddress: String!, $skip: Int!) {
|
query allV3Ticks($poolAddress: String!, $skip: Int!) {
|
||||||
ticks(first: 1000, skip: $skip, where: { poolAddress: $poolAddress }, orderBy: tickIdx) {
|
ticks(first: 1000, skip: $skip, where: { poolAddress: $poolAddress }, orderBy: tickIdx) {
|
||||||
tickIdx
|
tick: tickIdx
|
||||||
liquidityNet
|
liquidityNet
|
||||||
price0
|
price0
|
||||||
price1
|
price1
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
import { Token } from '@uniswap/sdk-core'
|
import { Token } from '@uniswap/sdk-core'
|
||||||
import { FeeAmount, TICK_SPACINGS } from '@uniswap/v3-sdk'
|
import { FeeAmount, TICK_SPACINGS } from '@uniswap/v3-sdk'
|
||||||
|
import { TickData, TickProcessed } from 'hooks/usePoolTickData'
|
||||||
import JSBI from 'jsbi'
|
import JSBI from 'jsbi'
|
||||||
import { AllV3TicksQuery } from 'state/data/generated'
|
|
||||||
|
|
||||||
import computeSurroundingTicks from './computeSurroundingTicks'
|
import computeSurroundingTicks from './computeSurroundingTicks'
|
||||||
|
|
||||||
const getV3Tick = (tickIdx: number, liquidityNet: number) => ({
|
const getV3Tick = (tick: number, liquidityNet: number): TickData => ({
|
||||||
tickIdx,
|
tick,
|
||||||
liquidityNet: JSBI.BigInt(liquidityNet),
|
liquidityNet: JSBI.BigInt(liquidityNet),
|
||||||
price0: '1',
|
liquidityGross: JSBI.BigInt(liquidityNet),
|
||||||
price1: '2',
|
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('#computeSurroundingTicks', () => {
|
describe('#computeSurroundingTicks', () => {
|
||||||
@ -18,22 +17,22 @@ describe('#computeSurroundingTicks', () => {
|
|||||||
const token1 = new Token(1, '0x1f9840a85d5af5bf1d1762f925bdaddc4201f984', 18)
|
const token1 = new Token(1, '0x1f9840a85d5af5bf1d1762f925bdaddc4201f984', 18)
|
||||||
const feeAmount = FeeAmount.LOW
|
const feeAmount = FeeAmount.LOW
|
||||||
const spacing = TICK_SPACINGS[feeAmount]
|
const spacing = TICK_SPACINGS[feeAmount]
|
||||||
const activeTickProcessed = {
|
const activeTickProcessed: TickProcessed = {
|
||||||
tickIdx: 1000,
|
tick: 1000,
|
||||||
liquidityActive: JSBI.BigInt(300),
|
liquidityActive: JSBI.BigInt(300),
|
||||||
liquidityNet: JSBI.BigInt(100),
|
liquidityNet: JSBI.BigInt(100),
|
||||||
price0: '100',
|
price0: '100',
|
||||||
}
|
}
|
||||||
const pivot = 3
|
const pivot = 3
|
||||||
const ascending = true
|
const ascending = true
|
||||||
const sortedTickData: AllV3TicksQuery['ticks'] = [
|
const sortedTickData: TickData[] = [
|
||||||
getV3Tick(activeTickProcessed.tickIdx - 4 * spacing, 10),
|
getV3Tick(activeTickProcessed.tick - 4 * spacing, 10),
|
||||||
getV3Tick(activeTickProcessed.tickIdx - 2 * spacing, 20),
|
getV3Tick(activeTickProcessed.tick - 2 * spacing, 20),
|
||||||
getV3Tick(activeTickProcessed.tickIdx - 1 * spacing, 30),
|
getV3Tick(activeTickProcessed.tick - 1 * spacing, 30),
|
||||||
getV3Tick(activeTickProcessed.tickIdx * spacing, 100),
|
getV3Tick(activeTickProcessed.tick * spacing, 100),
|
||||||
getV3Tick(activeTickProcessed.tickIdx + 1 * spacing, 40),
|
getV3Tick(activeTickProcessed.tick + 1 * spacing, 40),
|
||||||
getV3Tick(activeTickProcessed.tickIdx + 2 * spacing, 20),
|
getV3Tick(activeTickProcessed.tick + 2 * spacing, 20),
|
||||||
getV3Tick(activeTickProcessed.tickIdx + 5 * spacing, 20),
|
getV3Tick(activeTickProcessed.tick + 5 * spacing, 20),
|
||||||
]
|
]
|
||||||
|
|
||||||
const previous = computeSurroundingTicks(token0, token1, activeTickProcessed, sortedTickData, pivot, !ascending)
|
const previous = computeSurroundingTicks(token0, token1, activeTickProcessed, sortedTickData, pivot, !ascending)
|
||||||
@ -41,17 +40,17 @@ describe('#computeSurroundingTicks', () => {
|
|||||||
const subsequent = computeSurroundingTicks(token0, token1, activeTickProcessed, sortedTickData, pivot, ascending)
|
const subsequent = computeSurroundingTicks(token0, token1, activeTickProcessed, sortedTickData, pivot, ascending)
|
||||||
|
|
||||||
expect(previous.length).toEqual(3)
|
expect(previous.length).toEqual(3)
|
||||||
expect(previous.map((t) => [t.tickIdx, parseFloat(t.liquidityActive.toString())])).toEqual([
|
expect(previous.map((t) => [t.tick, parseFloat(t.liquidityActive.toString())])).toEqual([
|
||||||
[activeTickProcessed.tickIdx - 4 * spacing, 150],
|
[activeTickProcessed.tick - 4 * spacing, 150],
|
||||||
[activeTickProcessed.tickIdx - 2 * spacing, 170],
|
[activeTickProcessed.tick - 2 * spacing, 170],
|
||||||
[activeTickProcessed.tickIdx - 1 * spacing, 200],
|
[activeTickProcessed.tick - 1 * spacing, 200],
|
||||||
])
|
])
|
||||||
|
|
||||||
expect(subsequent.length).toEqual(3)
|
expect(subsequent.length).toEqual(3)
|
||||||
expect(subsequent.map((t) => [t.tickIdx, parseFloat(t.liquidityActive.toString())])).toEqual([
|
expect(subsequent.map((t) => [t.tick, parseFloat(t.liquidityActive.toString())])).toEqual([
|
||||||
[activeTickProcessed.tickIdx + 1 * spacing, 340],
|
[activeTickProcessed.tick + 1 * spacing, 340],
|
||||||
[activeTickProcessed.tickIdx + 2 * spacing, 360],
|
[activeTickProcessed.tick + 2 * spacing, 360],
|
||||||
[activeTickProcessed.tickIdx + 5 * spacing, 380],
|
[activeTickProcessed.tick + 5 * spacing, 380],
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { Token } from '@uniswap/sdk-core'
|
import { Token } from '@uniswap/sdk-core'
|
||||||
import { tickToPrice } from '@uniswap/v3-sdk'
|
import { tickToPrice } from '@uniswap/v3-sdk'
|
||||||
import { TickProcessed } from 'hooks/usePoolTickData'
|
import { TickData, TickProcessed } from 'hooks/usePoolTickData'
|
||||||
import JSBI from 'jsbi'
|
import JSBI from 'jsbi'
|
||||||
import { AllV3TicksQuery } from 'state/data/generated'
|
|
||||||
|
|
||||||
const PRICE_FIXED_DIGITS = 8
|
const PRICE_FIXED_DIGITS = 8
|
||||||
|
|
||||||
@ -11,7 +10,7 @@ export default function computeSurroundingTicks(
|
|||||||
token0: Token,
|
token0: Token,
|
||||||
token1: Token,
|
token1: Token,
|
||||||
activeTickProcessed: TickProcessed,
|
activeTickProcessed: TickProcessed,
|
||||||
sortedTickData: AllV3TicksQuery['ticks'],
|
sortedTickData: TickData[],
|
||||||
pivot: number,
|
pivot: number,
|
||||||
ascending: boolean
|
ascending: boolean
|
||||||
): TickProcessed[] {
|
): TickProcessed[] {
|
||||||
@ -22,12 +21,12 @@ export default function computeSurroundingTicks(
|
|||||||
// building active liquidity for every tick.
|
// building active liquidity for every tick.
|
||||||
let processedTicks: TickProcessed[] = []
|
let processedTicks: TickProcessed[] = []
|
||||||
for (let i = pivot + (ascending ? 1 : -1); ascending ? i < sortedTickData.length : i >= 0; ascending ? i++ : i--) {
|
for (let i = pivot + (ascending ? 1 : -1); ascending ? i < sortedTickData.length : i >= 0; ascending ? i++ : i--) {
|
||||||
const tickIdx = Number(sortedTickData[i].tickIdx)
|
const tick = Number(sortedTickData[i].tick)
|
||||||
const currentTickProcessed: TickProcessed = {
|
const currentTickProcessed: TickProcessed = {
|
||||||
liquidityActive: previousTickProcessed.liquidityActive,
|
liquidityActive: previousTickProcessed.liquidityActive,
|
||||||
tickIdx,
|
tick,
|
||||||
liquidityNet: JSBI.BigInt(sortedTickData[i].liquidityNet),
|
liquidityNet: JSBI.BigInt(sortedTickData[i].liquidityNet),
|
||||||
price0: tickToPrice(token0, token1, tickIdx).toFixed(PRICE_FIXED_DIGITS),
|
price0: tickToPrice(token0, token1, tick).toFixed(PRICE_FIXED_DIGITS),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the active liquidity.
|
// Update the active liquidity.
|
||||||
|
Loading…
Reference in New Issue
Block a user