From c899da52c2cef5bd79d3672178fa193c91275863 Mon Sep 17 00:00:00 2001 From: Maciek Date: Fri, 31 Mar 2023 12:41:16 +0200 Subject: [PATCH] fix(trading): stabilize the liquidity provision table (#3320) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Głownia --- .../client-pages/liquidity/liquidity.tsx | 358 +++++++++++------- .../src/lib/liquidity-data-provider.ts | 18 +- libs/utils/src/lib/generic-data-provider.ts | 6 +- 3 files changed, 229 insertions(+), 153 deletions(-) diff --git a/apps/trading/client-pages/liquidity/liquidity.tsx b/apps/trading/client-pages/liquidity/liquidity.tsx index 8191493d8..af166f9ad 100644 --- a/apps/trading/client-pages/liquidity/liquidity.tsx +++ b/apps/trading/client-pages/liquidity/liquidity.tsx @@ -1,4 +1,5 @@ import { + getId, liquidityProvisionsDataProvider, LiquidityTable, lpAggregatedDataProvider, @@ -25,7 +26,7 @@ import { Indicator, } from '@vegaprotocol/ui-toolkit'; import { useVegaWallet } from '@vegaprotocol/wallet'; -import { useCallback, useEffect, useMemo, useRef } from 'react'; +import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { Header, HeaderStat, HeaderTitle } from '../../components/header'; @@ -37,6 +38,13 @@ import { Link, useParams } from 'react-router-dom'; import { Links, Routes } from '../../pages/client-router'; import { useMarket, useStaticMarketData } from '@vegaprotocol/market-list'; +import isEqual from 'lodash/isEqual'; + +const enum LiquidityTabs { + Active = 'active', + Inactive = 'inactive', + MyLiquidityProvision = 'myLP', +} export const Liquidity = () => { const params = useParams(); @@ -48,10 +56,11 @@ const useReloadLiquidityData = (marketId: string | undefined) => { const { reload } = useDataProvider({ dataProvider: liquidityProvisionsDataProvider, variables: { marketId: marketId || '' }, + update: () => true, skip: !marketId, }); useEffect(() => { - const interval = setInterval(reload, 10000); + const interval = setInterval(reload, 30000); return () => clearInterval(interval); }, [reload]); }; @@ -126,47 +135,9 @@ export const LiquidityContainer = ({ ); }; -export const LiquidityViewContainer = ({ - marketId, -}: { - marketId: string | undefined; -}) => { - const { pubKey } = useVegaWallet(); - const gridRef = useRef(null); +const LiquidityViewHeader = memo(({ marketId }: { marketId?: string }) => { const { data: market } = useMarket(marketId); const { data: marketData } = useStaticMarketData(marketId); - - const dataRef = useRef(null); - - // To be removed when liquidityProvision subscriptions are working - useReloadLiquidityData(marketId); - - const update = useCallback( - ({ data }: { data: LiquidityProvisionData[] | null }) => { - if (!gridRef.current?.api) { - return false; - } - if (dataRef.current?.length) { - dataRef.current = data; - gridRef.current.api.refreshInfiniteCache(); - return true; - } - return false; - }, - [gridRef] - ); - - const { - data: liquidityProviders, - loading, - error, - } = useDataProvider({ - dataProvider: lpAggregatedDataProvider, - update, - variables: { marketId: marketId || '' }, - skip: !marketId, - }); - const targetStake = marketData?.targetStake; const suppliedStake = marketData?.suppliedStake; const assetDecimalPlaces = @@ -178,44 +149,8 @@ export const LiquidityViewContainer = ({ NetworkParams.market_liquidity_stakeToCcyVolume, NetworkParams.market_liquidity_targetstake_triggering_ratio, ]); - const stakeToCcyVolume = params.market_liquidity_stakeToCcyVolume; const triggeringRatio = params.market_liquidity_targetstake_triggering_ratio || '1'; - const myLpEdges = useMemo( - () => liquidityProviders?.filter((e) => e.party.id === pubKey), - [liquidityProviders, pubKey] - ); - const activeEdges = useMemo( - () => - liquidityProviders?.filter( - (e) => e.status === Schema.LiquidityProvisionStatus.STATUS_ACTIVE - ), - [liquidityProviders] - ); - const inactiveEdges = useMemo( - () => - liquidityProviders?.filter( - (e) => e.status !== Schema.LiquidityProvisionStatus.STATUS_ACTIVE - ), - [liquidityProviders] - ); - - const enum LiquidityTabs { - Active = 'active', - Inactive = 'inactive', - MyLiquidityProvision = 'myLP', - } - - const getActiveDefaultId = () => { - if (myLpEdges && myLpEdges.length > 0) { - return LiquidityTabs.MyLiquidityProvision; - } - if (activeEdges?.length) return LiquidityTabs.Active; - else if (inactiveEdges && inactiveEdges.length > 0) { - return LiquidityTabs.Inactive; - } - return LiquidityTabs.Active; - }; const { percentage, status } = useCheckLiquidityStatus({ suppliedStake: suppliedStake || 0, @@ -223,66 +158,197 @@ export const LiquidityViewContainer = ({ triggeringRatio, }); + return ( +
+ {t('Go to trading')} + + } + /> + ) + } + > + +
+ {targetStake + ? `${addDecimalsFormatNumber( + targetStake, + assetDecimalPlaces ?? 0 + )} ${symbol}` + : '-'} +
+
+ +
+ {suppliedStake + ? `${addDecimalsFormatNumber( + suppliedStake, + assetDecimalPlaces ?? 0 + )} ${symbol}` + : '-'} +
+
+ + + + {formatNumberPercentage(percentage, 2)} + + +
{marketId}
+
+
+ ); +}); +LiquidityViewHeader.displayName = 'LiquidityViewHeader'; + +const filterLiquidities = ( + tab: string, + liquidities?: LiquidityProvisionData[] | null, + pubKey?: string | null +) => { + switch (tab) { + case LiquidityTabs.MyLiquidityProvision: + return pubKey + ? (liquidities || []).filter((e) => e.party.id === pubKey) + : []; + break; + case LiquidityTabs.Active: + return (liquidities || []).filter( + (e) => e.status === Schema.LiquidityProvisionStatus.STATUS_ACTIVE + ); + case LiquidityTabs.Inactive: + return (liquidities || []).filter( + (e) => e.status !== Schema.LiquidityProvisionStatus.STATUS_ACTIVE + ); + default: + return []; + } +}; + +export const LiquidityViewContainer = ({ + marketId, +}: { + marketId: string | undefined; +}) => { + const [tab, setTab] = useState(''); + const { pubKey } = useVegaWallet(); + const [liquidityProviders, setLiquidityProviders] = useState< + LiquidityProvisionData[] | null + >(); + const gridRef = useRef(null); + const { data: market } = useMarket(marketId); + const dataRef = useRef(null); + + // To be removed when liquidityProvision subscriptions are working + useReloadLiquidityData(marketId); + + const update = useCallback( + ({ data }: { data: LiquidityProvisionData[] | null }) => { + if (!dataRef.current) { + setLiquidityProviders(data); + dataRef.current = data; + } + if (!gridRef.current?.api) { + return false; + } + const updateRows: LiquidityProvisionData[] = []; + const addRows: LiquidityProvisionData[] = []; + if (gridRef.current?.api?.getModel().getType() === 'infinite') { + dataRef.current = data; + gridRef.current.api.refreshInfiniteCache(); + } else { + const filteredData = filterLiquidities(tab, data, pubKey as string); + filteredData?.forEach((d) => { + const rowNode = gridRef.current?.api?.getRowNode(getId(d)); + if (rowNode) { + if (!isEqual(rowNode.data, d)) { + updateRows.push(d); + } + } else { + addRows.push(d); + } + }); + gridRef.current?.api?.applyTransaction({ + update: updateRows, + add: addRows, + addIndex: 0, + }); + } + return true; + }, + [gridRef, tab, pubKey] + ); + + const { loading, error } = useDataProvider({ + dataProvider: lpAggregatedDataProvider, + update, + variables: { marketId: marketId || '' }, + skip: !marketId, + }); + const assetDecimalPlaces = + market?.tradableInstrument.instrument.product.settlementAsset.decimals || 0; + const symbol = + market?.tradableInstrument.instrument.product.settlementAsset.symbol; + + const { params } = useNetworkParams([ + NetworkParams.market_liquidity_stakeToCcyVolume, + NetworkParams.market_liquidity_targetstake_triggering_ratio, + ]); + const stakeToCcyVolume = params.market_liquidity_stakeToCcyVolume; + const myLpEdges = useMemo( + () => + filterLiquidities( + LiquidityTabs.MyLiquidityProvision, + liquidityProviders, + pubKey + ), + [liquidityProviders, pubKey] + ); + const activeEdges = useMemo( + () => filterLiquidities(LiquidityTabs.Active, liquidityProviders), + [liquidityProviders] + ); + const inactiveEdges = useMemo( + () => filterLiquidities(LiquidityTabs.Inactive, liquidityProviders), + [liquidityProviders] + ); + + useEffect(() => { + if (tab) { + return; + } + let initialTab = LiquidityTabs.Active; + if (myLpEdges.length > 0) { + initialTab = LiquidityTabs.MyLiquidityProvision; + } + if (activeEdges?.length) { + initialTab = LiquidityTabs.Active; + } else if (inactiveEdges.length > 0) { + initialTab = LiquidityTabs.Inactive; + } + setTab(initialTab); + }, [tab, myLpEdges?.length, activeEdges?.length, inactiveEdges?.length]); + return (
-
- {t('Go to trading')} - - } - /> - ) - } - > - -
- {targetStake - ? `${addDecimalsFormatNumber( - targetStake, - assetDecimalPlaces ?? 0 - )} ${symbol}` - : '-'} -
-
- -
- {suppliedStake - ? `${addDecimalsFormatNumber( - suppliedStake, - assetDecimalPlaces ?? 0 - )} ${symbol}` - : '-'} -
-
- - - - {formatNumberPercentage(percentage, 2)} - - -
{marketId}
-
-
- + + )} - { - - {inactiveEdges && ( - - )} - - } + + {inactiveEdges && ( + + )} +
diff --git a/libs/liquidity/src/lib/liquidity-data-provider.ts b/libs/liquidity/src/lib/liquidity-data-provider.ts index 8e46ccb66..0c2beb807 100644 --- a/libs/liquidity/src/lib/liquidity-data-provider.ts +++ b/libs/liquidity/src/lib/liquidity-data-provider.ts @@ -65,11 +65,23 @@ export const liquidityProvisionsDataProvider = makeDataProvider< }); }, getData: (responseData: LiquidityProvisionsQuery | null) => { + // to remove dedupe after core fix https://github.com/vegaprotocol/vega/issues/8043 + const dedupeArr: string[] = []; return ( responseData?.market?.liquidityProvisionsConnection?.edges?.map( (e) => e?.node ) ?? [] - ).filter((e) => !!e) as LiquidityProvisionFieldsFragment[]; + ).filter((e) => { + if (e) { + const id = getId(e); + if (dedupeArr.includes(id)) { + return false; + } + dedupeArr.push(id); + return true; + } + return false; + }) as LiquidityProvisionFieldsFragment[]; }, getDelta: ( subscriptionData: LiquidityProvisionsUpdateSubscription @@ -96,8 +108,8 @@ export const getId = ( > ) => isLpFragment(entry) - ? `${entry.party.id}${entry.status}${entry.createdAt}` - : `${entry.partyID}${entry.status}${entry.createdAt}`; + ? `${entry.party.id}${entry.status}${entry.createdAt}${entry.updatedAt}` + : `${entry.partyID}${entry.status}${entry.createdAt}${entry.updatedAt}`; export const marketLiquidityDataProvider = makeDataProvider< MarketLpQuery, diff --git a/libs/utils/src/lib/generic-data-provider.ts b/libs/utils/src/lib/generic-data-provider.ts index 7a14f1b4c..2dae214a5 100644 --- a/libs/utils/src/lib/generic-data-provider.ts +++ b/libs/utils/src/lib/generic-data-provider.ts @@ -339,7 +339,7 @@ function makeDataProviderInternal< } }; - const initialFetch = async () => { + const initialFetch = async (isUpdate = false) => { if (!client) { return; } @@ -394,7 +394,7 @@ function makeDataProviderInternal< subscription = undefined; } finally { loading = false; - notifyAll(); + notifyAll({ isUpdate }); } }; @@ -410,7 +410,7 @@ function makeDataProviderInternal< } else { loading = true; error = undefined; - initialFetch(); + initialFetch(true); } };