From 168a8af8568c8ec994c44309537ce8ce19897410 Mon Sep 17 00:00:00 2001 From: uncoolzero <107518216+uncoolzero@users.noreply.github.com> Date: Thu, 14 Dec 2023 22:44:50 -0300 Subject: [PATCH] Update Liquidity chart on Analytics page --- .../components/Analytics/Bean/Liquidity.tsx | 198 +++++++++++++++--- .../components/Forecast/LiquidityOverTime.tsx | 1 - 2 files changed, 167 insertions(+), 32 deletions(-) diff --git a/projects/ui/src/components/Analytics/Bean/Liquidity.tsx b/projects/ui/src/components/Analytics/Bean/Liquidity.tsx index 4babd429be..63c1d8f0e6 100644 --- a/projects/ui/src/components/Analytics/Bean/Liquidity.tsx +++ b/projects/ui/src/components/Analytics/Bean/Liquidity.tsx @@ -1,51 +1,187 @@ -import React from 'react'; -import { tickFormatUSD } from '~/components/Analytics/formatters'; -import { LineChartProps } from '~/components/Common/Charts/LineChart'; -import SeasonPlot, { - SeasonPlotBaseProps, -} from '~/components/Common/Charts/SeasonPlot'; +import React, { useMemo } from 'react'; import { - SeasonalLiquidityDocument, - SeasonalLiquidityQuery, + SeasonalLiquidityPerPoolDocument, } from '~/generated/graphql'; import useSeason from '~/hooks/beanstalk/useSeason'; - import { FC } from '~/types'; +import useSeasonsQuery, { SeasonRange } from '~/hooks/beanstalk/useSeasonsQuery'; +import { BaseDataPoint, ChartMultiStyles } from '../../Common/Charts/ChartPropProvider'; +import useSdk from '~/hooks/sdk'; +import useTimeTabState from '~/hooks/app/useTimeTabState'; +import BaseSeasonPlot, { QueryData } from '../../Common/Charts/BaseSeasonPlot'; +import { BEAN_CRV3_V1_LP, BEAN_LUSD_LP } from '~/constants/tokens'; +import { BeanstalkPalette } from '../../App/muiTheme'; +import { SeasonPlotBaseProps } from '~/components/Common/Charts/SeasonPlot'; -const getValue = (season: SeasonalLiquidityQuery['seasons'][number]) => - parseFloat(season.liquidityUSD); -const formatValue = (value: number) => - `$${value.toLocaleString('en-US', { maximumFractionDigits: 0 })}`; -const statProps = { +/// Setup SeasonPlot +const formatValue = (value: number) => ( + `$${(value || 0).toLocaleString('en-US', { maximumFractionDigits: 2 })}` +); +const StatProps = { title: 'Liquidity', titleTooltip: 'The total USD value of tokens in liquidity pools on the Minting Whitelist at the beginning of every Season. Pre-exploit values include liquidity in pools on the Deposit Whitelist.', gap: 0.25, -}; -const queryConfig = { - variables: { season_gt: 0 }, - context: { subgraph: 'bean' }, -}; -const lineChartProps: Partial = { - yTickFormat: tickFormatUSD, + color: 'primary', + sx: { ml: 0 }, }; -const Liquidity: FC<{ height?: SeasonPlotBaseProps['height'] }> = ({ - height, +const Liquidity: FC<{ height?: SeasonPlotBaseProps['height'] }> = ({ + height, }) => { + // + const sdk = useSdk(); + const timeTabParams = useTimeTabState(); const season = useSeason(); + + const getStatValue = (v?: T[]) => { + if (!v?.length) return 0; + const dataPoint = v[0]; + return dataPoint?.value || 0; + }; + + const BEAN_LUSD_LP_V1 = BEAN_LUSD_LP[1]; + const BEAN_CRV3_V1 = BEAN_CRV3_V1_LP[1]; + + const poolList = [ + sdk.pools.BEAN_CRV3, + sdk.pools.BEAN_ETH_WELL, + sdk.tokens.BEAN_ETH_UNIV2_LP, + BEAN_LUSD_LP_V1, + BEAN_CRV3_V1, + ]; + + const chartStyle: ChartMultiStyles = { + [sdk.pools.BEAN_CRV3.address]: { + stroke: BeanstalkPalette.theme.spring.blue, + fillPrimary: BeanstalkPalette.theme.spring.lightBlue + }, + [sdk.pools.BEAN_ETH_WELL.address]: { + stroke: BeanstalkPalette.theme.spring.beanstalkGreen, + fillPrimary: BeanstalkPalette.theme.spring.washedGreen + }, + [sdk.tokens.BEAN_ETH_UNIV2_LP.address]: { + stroke: BeanstalkPalette.theme.spring.chart.purple, + fillPrimary: BeanstalkPalette.theme.spring.chart.purpleLight + }, + [BEAN_LUSD_LP_V1.address]: { + stroke: BeanstalkPalette.theme.spring.grey, + fillPrimary: BeanstalkPalette.theme.spring.lightishGrey + }, + [BEAN_CRV3_V1.address]: { + stroke: BeanstalkPalette.theme.spring.chart.yellow, + fillPrimary: BeanstalkPalette.theme.spring.chart.yellowLight + }, + }; + + // Filters non-relevant tokens from the tooltip on a per-season basis + const seasonFilter = { + [sdk.tokens.BEAN_ETH_UNIV2_LP.address]: { from: 0, to: 6074 }, + [BEAN_LUSD_LP_V1.address]: { from: 5502, to: 6074 }, + [BEAN_CRV3_V1.address]: { from: 3658, to: 6074 }, + [sdk.pools.BEAN_CRV3.address]: { from: 6074, to: Infinity }, + [sdk.pools.BEAN_ETH_WELL.address]: { from: 15241, to: Infinity }, + }; + + const queryConfigBeanCrv3 = useMemo(() => ({ + variables: { pool: sdk.pools.BEAN_CRV3.address }, + context: { subgraph: 'bean' } + }), [sdk.pools.BEAN_CRV3.address]); + + const queryConfigBeanEthWell = useMemo(() => ({ + variables: { pool: sdk.pools.BEAN_ETH_WELL.address }, + context: { subgraph: 'bean' } + }), [sdk.pools.BEAN_ETH_WELL.address]); + + const queryConfigBeanEthOld = useMemo(() => ({ + variables: { pool: sdk.tokens.BEAN_ETH_UNIV2_LP.address }, + context: { subgraph: 'bean' } + }), [sdk.tokens.BEAN_ETH_UNIV2_LP.address]); + + const queryConfigBeanLusdOld = useMemo(() => ({ + variables: { pool: BEAN_LUSD_LP_V1.address }, + context: { subgraph: 'bean' } + }), [BEAN_LUSD_LP_V1.address]); + + const queryConfigBeanCrv3Old = useMemo(() => ({ + variables: { pool: BEAN_CRV3_V1.address }, + context: { subgraph: 'bean' } + }), [BEAN_CRV3_V1.address]); + + const beanCrv3 = useSeasonsQuery(SeasonalLiquidityPerPoolDocument, timeTabParams[0][1], queryConfigBeanCrv3); + const beanEthWell = useSeasonsQuery(SeasonalLiquidityPerPoolDocument, timeTabParams[0][1], queryConfigBeanEthWell); + const beanEthOld = useSeasonsQuery(SeasonalLiquidityPerPoolDocument, SeasonRange.ALL, queryConfigBeanEthOld); + const beanLusdOld = useSeasonsQuery(SeasonalLiquidityPerPoolDocument, SeasonRange.ALL, queryConfigBeanLusdOld); + const beanCrv3Old = useSeasonsQuery(SeasonalLiquidityPerPoolDocument, SeasonRange.ALL, queryConfigBeanCrv3Old); + + let seasonData + if (timeTabParams[0][1] === SeasonRange.ALL) { + seasonData = [ + beanCrv3.data?.seasons, + beanEthWell.data?.seasons, + beanEthOld.data?.seasons, + beanLusdOld.data?.seasons, + beanCrv3Old.data?.seasons + ].flat(Infinity); + } else { + seasonData = [ + beanCrv3.data?.seasons, + beanEthWell.data?.seasons, + ].flat(Infinity); + }; + + const loading = beanCrv3.loading || beanEthWell.loading || beanEthOld.loading || beanLusdOld.loading || beanCrv3Old.loading; + + const processedSeasons: any[] = []; + const defaultDataPoint = { + season: 0, + date: 0, + value: 0, + [sdk.pools.BEAN_CRV3.address]: 0, + [sdk.pools.BEAN_ETH_WELL.address]: 0, + [sdk.tokens.BEAN_ETH_UNIV2_LP.address]: 0, + [BEAN_LUSD_LP_V1.address]: 0, + [BEAN_CRV3_V1.address]: 0, + }; + + if (season && !loading && seasonData[0] && seasonData[0].season) { + const latestSeason = seasonData[0].season; + seasonData.forEach((dataPoint) => { + const seasonDiff = latestSeason - dataPoint.season; + if (!processedSeasons[seasonDiff]) { + processedSeasons[seasonDiff] = { ...defaultDataPoint }; + }; + processedSeasons[seasonDiff].season = Number(dataPoint.season); + processedSeasons[seasonDiff].date = new Date(Number(dataPoint.updatedAt) * 1000); + processedSeasons[seasonDiff][dataPoint.id.slice(0, 42)] = Number(dataPoint.liquidityUSD); + processedSeasons[seasonDiff].value += Number(dataPoint.liquidityUSD); + }); + }; + + const queryData: QueryData = { + data: [processedSeasons.filter(Boolean).reverse()], + loading: loading, + keys: poolList.map((pool) => pool.address), + error: undefined, + }; + return ( - ); }; export default Liquidity; + diff --git a/projects/ui/src/components/Forecast/LiquidityOverTime.tsx b/projects/ui/src/components/Forecast/LiquidityOverTime.tsx index be20da314d..812ca9c0aa 100644 --- a/projects/ui/src/components/Forecast/LiquidityOverTime.tsx +++ b/projects/ui/src/components/Forecast/LiquidityOverTime.tsx @@ -4,7 +4,6 @@ import { SeasonalLiquidityPerPoolDocument, } from '~/generated/graphql'; import useSeason from '~/hooks/beanstalk/useSeason'; - import { FC } from '~/types'; import useSeasonsQuery, { SeasonRange } from '~/hooks/beanstalk/useSeasonsQuery'; import { BaseDataPoint, ChartMultiStyles } from '../Common/Charts/ChartPropProvider';