Commit 2db29f20 authored by Justin Domingue's avatar Justin Domingue Committed by GitHub

fix: simplify liqudity depth hooks and improve chart primitives (#1999)

* updated hooks and chart primitives

* add lodash.inrange to package.json
parent 3ae9e2af
...@@ -27,7 +27,7 @@ const Axis = ({ axisGenerator }: { axisGenerator: d3Axis<NumberValue> }) => { ...@@ -27,7 +27,7 @@ const Axis = ({ axisGenerator }: { axisGenerator: d3Axis<NumberValue> }) => {
export const AxisBottom = ({ export const AxisBottom = ({
xScale, xScale,
innerHeight, innerHeight,
offset = 5, offset = 0,
}: { }: {
xScale: ScaleLinear<number, number> xScale: ScaleLinear<number, number>
innerHeight: number innerHeight: number
......
...@@ -37,6 +37,9 @@ const Tooltip = styled.text` ...@@ -37,6 +37,9 @@ const Tooltip = styled.text`
fill: ${({ theme }) => theme.text1}; fill: ${({ theme }) => theme.text1};
` `
// flips the handles draggers when close to the container edges
const FLIP_HANDLE_THRESHOLD_PX = 20
export const Brush = ({ export const Brush = ({
id, id,
xScale, xScale,
...@@ -144,8 +147,8 @@ export const Brush = ({ ...@@ -144,8 +147,8 @@ export const Brush = ({
return () => clearTimeout(timeout) return () => clearTimeout(timeout)
}, [localBrushExtent]) }, [localBrushExtent])
const flipWestHandle = localBrushExtent && xScale(localBrushExtent[0]) > 15 const flipWestHandle = localBrushExtent && xScale(localBrushExtent[0]) > FLIP_HANDLE_THRESHOLD_PX
const flipEastHandle = localBrushExtent && xScale(localBrushExtent[1]) > innerWidth - 15 const flipEastHandle = localBrushExtent && xScale(localBrushExtent[1]) > innerWidth - FLIP_HANDLE_THRESHOLD_PX
return useMemo( return useMemo(
() => ( () => (
......
...@@ -20,8 +20,8 @@ const Button = styled(ButtonGray)` ...@@ -20,8 +20,8 @@ const Button = styled(ButtonGray)`
color: ${({ theme }) => theme.text1}; color: ${({ theme }) => theme.text1};
} }
width: 28px; width: 32px;
height: 28px; height: 32px;
padding: 4px; padding: 4px;
` `
...@@ -91,14 +91,14 @@ export default function Zoom({ ...@@ -91,14 +91,14 @@ export default function Zoom({
<Wrapper count={showClear ? 3 : 2}> <Wrapper count={showClear ? 3 : 2}>
{showClear && ( {showClear && (
<Button onClick={reset} disabled={false}> <Button onClick={reset} disabled={false}>
<RefreshCcw size={14} /> <RefreshCcw size={16} />
</Button> </Button>
)} )}
<Button onClick={zoomIn} disabled={false}> <Button onClick={zoomIn} disabled={false}>
<ZoomIn size={14} /> <ZoomIn size={16} />
</Button> </Button>
<Button onClick={zoomOut} disabled={false}> <Button onClick={zoomOut} disabled={false}>
<ZoomOut size={14} /> <ZoomOut size={16} />
</Button> </Button>
</Wrapper> </Wrapper>
) )
......
import { useEffect, useState } from 'react' import { useCallback, useMemo } from 'react'
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 { usePoolActiveLiquidity } from 'hooks/usePoolTickData'
import { ChartEntry } from './types' import { ChartEntry } from './types'
import JSBI from 'jsbi' import JSBI from 'jsbi'
// Tick with fields parsed to JSBIs, and active liquidity computed.
export interface TickProcessed { export interface TickProcessed {
tickIdx: number
liquidityActive: JSBI liquidityActive: JSBI
liquidityNet: JSBI
price0: string price0: string
} }
...@@ -22,23 +19,11 @@ export function useDensityChartData({ ...@@ -22,23 +19,11 @@ export function useDensityChartData({
currencyB: Currency | undefined currencyB: Currency | undefined
feeAmount: FeeAmount | undefined feeAmount: FeeAmount | undefined
}) { }) {
const [formattedData, setFormattedData] = useState<ChartEntry[] | undefined>() const { isLoading, isUninitialized, isError, error, data } = usePoolActiveLiquidity(currencyA, currencyB, feeAmount)
const { isLoading, isUninitialized, isError, error, activeTick, data } = usePoolActiveLiquidity( const formatData = useCallback(() => {
currencyA,
currencyB,
feeAmount
)
useEffect(() => {
// clear data when inputs are cleared
setFormattedData(undefined)
}, [currencyA, currencyB, feeAmount])
useEffect(() => {
function formatData() {
if (!data?.length) { if (!data?.length) {
return return undefined
} }
const newData: ChartEntry[] = [] const newData: ChartEntry[] = []
...@@ -54,21 +39,16 @@ export function useDensityChartData({ ...@@ -54,21 +39,16 @@ export function useDensityChartData({
newData.push(chartEntry) newData.push(chartEntry)
} }
if (newData) { return newData
setFormattedData(newData) }, [data])
}
}
if (!isLoading) {
formatData()
}
}, [isLoading, activeTick, data])
return useMemo(() => {
return { return {
isLoading, isLoading,
isUninitialized, isUninitialized,
isError, isError,
error, error,
formattedData, formattedData: !isLoading && !isUninitialized ? formatData() : undefined,
} }
}, [isLoading, isUninitialized, isError, error, formatData])
} }
...@@ -124,11 +124,6 @@ export default function LiquidityChartRangeInput({ ...@@ -124,11 +124,6 @@ export default function LiquidityChartRangeInput({
category: 'Liquidity', category: 'Liquidity',
fatal: false, fatal: false,
}) })
if (error?.name === 'UnsupportedChainId') {
// do not show the chart container when the chain is not supported
return null
}
} }
return ( return (
...@@ -142,12 +137,12 @@ export default function LiquidityChartRangeInput({ ...@@ -142,12 +137,12 @@ export default function LiquidityChartRangeInput({
<InfoBox icon={<Loader size="40px" stroke={theme.text4} />} /> <InfoBox icon={<Loader size="40px" stroke={theme.text4} />} />
) : isError ? ( ) : isError ? (
<InfoBox <InfoBox
message={<Trans>Subgraph data not available</Trans>} message={<Trans>Liquidity data not available.</Trans>}
icon={<CloudOff size={56} stroke={theme.text4} />} icon={<CloudOff size={56} stroke={theme.text4} />}
/> />
) : !formattedData || formattedData === [] || !price ? ( ) : !formattedData || formattedData === [] || !price ? (
<InfoBox <InfoBox
message={<Trans>There is no liquidity data</Trans>} message={<Trans>There is no liquidity data.</Trans>}
icon={<BarChart2 size={56} stroke={theme.text4} />} icon={<BarChart2 size={56} stroke={theme.text4} />}
/> />
) : ( ) : (
...@@ -155,7 +150,7 @@ export default function LiquidityChartRangeInput({ ...@@ -155,7 +150,7 @@ export default function LiquidityChartRangeInput({
<Chart <Chart
data={{ series: formattedData, current: price }} data={{ series: formattedData, current: price }}
dimensions={{ width: 400, height: 200 }} dimensions={{ width: 400, height: 200 }}
margins={{ top: 10, right: 2, bottom: 30, left: 0 }} margins={{ top: 10, right: 2, bottom: 20, left: 0 }}
styles={{ styles={{
area: { area: {
selection: theme.blue1, selection: theme.blue1,
......
...@@ -2,7 +2,7 @@ import { Currency } from '@uniswap/sdk-core' ...@@ -2,7 +2,7 @@ import { Currency } from '@uniswap/sdk-core'
import { FeeAmount, Pool, tickToPrice, TICK_SPACINGS } from '@uniswap/v3-sdk' import { FeeAmount, Pool, tickToPrice, TICK_SPACINGS } from '@uniswap/v3-sdk'
import JSBI from 'jsbi' import JSBI from 'jsbi'
import { PoolState, usePool } from './usePools' import { PoolState, usePool } from './usePools'
import { useEffect, useMemo, useState } from 'react' import { useMemo } from 'react'
import computeSurroundingTicks from 'utils/computeSurroundingTicks' import computeSurroundingTicks from 'utils/computeSurroundingTicks'
import { useAllV3TicksQuery } from 'state/data/enhanced' import { useAllV3TicksQuery } from 'state/data/enhanced'
import { skipToken } from '@reduxjs/toolkit/query/react' import { skipToken } from '@reduxjs/toolkit/query/react'
...@@ -52,9 +52,14 @@ export function usePoolActiveLiquidity( ...@@ -52,9 +52,14 @@ export function usePoolActiveLiquidity(
currencyA: Currency | undefined, currencyA: Currency | undefined,
currencyB: Currency | undefined, currencyB: Currency | undefined,
feeAmount: FeeAmount | undefined feeAmount: FeeAmount | undefined
) { ): {
const [ticksProcessed, setTicksProcessed] = useState<TickProcessed[]>([]) isLoading: boolean
isUninitialized: boolean
isError: boolean
error: any
activeTick: number | undefined
data: TickProcessed[] | undefined
} {
const pool = usePool(currencyA, currencyB, feeAmount) const pool = usePool(currencyA, currencyB, feeAmount)
// Find nearest valid tick for pool in case tick is not initialized. // Find nearest valid tick for pool in case tick is not initialized.
...@@ -62,15 +67,25 @@ export function usePoolActiveLiquidity( ...@@ -62,15 +67,25 @@ export function usePoolActiveLiquidity(
const { isLoading, isUninitialized, isError, error, ticks } = useAllV3Ticks(currencyA, currencyB, feeAmount) const { isLoading, isUninitialized, isError, error, ticks } = useAllV3Ticks(currencyA, currencyB, feeAmount)
useEffect(() => { return useMemo(() => {
// reset local ticks processed if (
setTicksProcessed([]) !currencyA ||
}, [currencyA, currencyB, feeAmount]) !currencyB ||
!activeTick ||
useEffect(() => { pool[0] !== PoolState.EXISTS ||
if (!currencyA || !currencyB || !activeTick || pool[0] !== PoolState.EXISTS || !ticks || ticks.length === 0) { !ticks ||
setTicksProcessed([]) ticks.length === 0 ||
return isLoading ||
isUninitialized
) {
return {
isLoading: isLoading || pool[0] === PoolState.LOADING,
isUninitialized,
isError,
error,
activeTick,
data: undefined,
}
} }
const token0 = currencyA?.wrapped const token0 = currencyA?.wrapped
...@@ -84,7 +99,14 @@ export function usePoolActiveLiquidity( ...@@ -84,7 +99,14 @@ export function usePoolActiveLiquidity(
if (pivot < 0) { if (pivot < 0) {
// consider setting a local error // consider setting a local error
console.error('TickData pivot not found') console.error('TickData pivot not found')
return return {
isLoading,
isUninitialized,
isError,
error,
activeTick,
data: undefined,
}
} }
const activeTickProcessed: TickProcessed = { const activeTickProcessed: TickProcessed = {
...@@ -99,17 +121,15 @@ export function usePoolActiveLiquidity( ...@@ -99,17 +121,15 @@ export function usePoolActiveLiquidity(
const previousTicks = computeSurroundingTicks(token0, token1, activeTickProcessed, ticks, pivot, false) const previousTicks = computeSurroundingTicks(token0, token1, activeTickProcessed, ticks, pivot, false)
const newTicksProcessed = previousTicks.concat(activeTickProcessed).concat(subsequentTicks) const ticksProcessed = previousTicks.concat(activeTickProcessed).concat(subsequentTicks)
setTicksProcessed(newTicksProcessed)
}, [currencyA, currencyB, activeTick, pool, ticks])
return { return {
isLoading: isLoading || pool[0] === PoolState.LOADING, isLoading,
isUninitialized, isUninitialized,
isError: isError, isError: isError,
error, error,
activeTick, activeTick,
data: ticksProcessed, data: ticksProcessed,
} }
}, [currencyA, currencyB, activeTick, pool, ticks, isLoading, isUninitialized, isError, error])
} }
...@@ -3572,6 +3572,13 @@ ...@@ -3572,6 +3572,13 @@
dependencies: dependencies:
"@types/lodash" "*" "@types/lodash" "*"
"@types/lodash.inrange@^3.3.6":
version "3.3.6"
resolved "https://registry.yarnpkg.com/@types/lodash.inrange/-/lodash.inrange-3.3.6.tgz#bc2be446082069604d96ee8c30bd07317af6fcc7"
integrity sha512-lB01EnNz+7lj9IVWDZ0cUTbKnTyyyuX2elKbqtrRj0oXWm66BaILR8bwVzYu99KX21PiiwOLXeQcXw62FV88fw==
dependencies:
"@types/lodash" "*"
"@types/lodash@*", "@types/lodash@^4.14.53": "@types/lodash@*", "@types/lodash@^4.14.53":
version "4.14.169" version "4.14.169"
resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.169.tgz" resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.169.tgz"
...@@ -12748,6 +12755,11 @@ lodash.includes@^4.3.0: ...@@ -12748,6 +12755,11 @@ lodash.includes@^4.3.0:
resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f"
integrity sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8= integrity sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=
lodash.inrange@^3.3.6:
version "3.3.6"
resolved "https://registry.yarnpkg.com/lodash.inrange/-/lodash.inrange-3.3.6.tgz#dfdfe915f6e30e8056293707e2395dab88ea128d"
integrity sha1-39/pFfbjDoBWKTcH4jldq4jqEo0=
lodash.isboolean@^3.0.3: lodash.isboolean@^3.0.3:
version "3.0.3" version "3.0.3"
resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6"
......
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