fix(trading): stabilize the liquidity provision table (#3320)
Co-authored-by: Bartłomiej Głownia <bglownia@gmail.com>
This commit is contained in:
parent
b9c4057ce5
commit
c899da52c2
@ -1,4 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
|
getId,
|
||||||
liquidityProvisionsDataProvider,
|
liquidityProvisionsDataProvider,
|
||||||
LiquidityTable,
|
LiquidityTable,
|
||||||
lpAggregatedDataProvider,
|
lpAggregatedDataProvider,
|
||||||
@ -25,7 +26,7 @@ import {
|
|||||||
Indicator,
|
Indicator,
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
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';
|
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 { Links, Routes } from '../../pages/client-router';
|
||||||
|
|
||||||
import { useMarket, useStaticMarketData } from '@vegaprotocol/market-list';
|
import { useMarket, useStaticMarketData } from '@vegaprotocol/market-list';
|
||||||
|
import isEqual from 'lodash/isEqual';
|
||||||
|
|
||||||
|
const enum LiquidityTabs {
|
||||||
|
Active = 'active',
|
||||||
|
Inactive = 'inactive',
|
||||||
|
MyLiquidityProvision = 'myLP',
|
||||||
|
}
|
||||||
|
|
||||||
export const Liquidity = () => {
|
export const Liquidity = () => {
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
@ -48,10 +56,11 @@ const useReloadLiquidityData = (marketId: string | undefined) => {
|
|||||||
const { reload } = useDataProvider({
|
const { reload } = useDataProvider({
|
||||||
dataProvider: liquidityProvisionsDataProvider,
|
dataProvider: liquidityProvisionsDataProvider,
|
||||||
variables: { marketId: marketId || '' },
|
variables: { marketId: marketId || '' },
|
||||||
|
update: () => true,
|
||||||
skip: !marketId,
|
skip: !marketId,
|
||||||
});
|
});
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const interval = setInterval(reload, 10000);
|
const interval = setInterval(reload, 30000);
|
||||||
return () => clearInterval(interval);
|
return () => clearInterval(interval);
|
||||||
}, [reload]);
|
}, [reload]);
|
||||||
};
|
};
|
||||||
@ -126,47 +135,9 @@ export const LiquidityContainer = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const LiquidityViewContainer = ({
|
const LiquidityViewHeader = memo(({ marketId }: { marketId?: string }) => {
|
||||||
marketId,
|
|
||||||
}: {
|
|
||||||
marketId: string | undefined;
|
|
||||||
}) => {
|
|
||||||
const { pubKey } = useVegaWallet();
|
|
||||||
const gridRef = useRef<AgGridReact | null>(null);
|
|
||||||
const { data: market } = useMarket(marketId);
|
const { data: market } = useMarket(marketId);
|
||||||
const { data: marketData } = useStaticMarketData(marketId);
|
const { data: marketData } = useStaticMarketData(marketId);
|
||||||
|
|
||||||
const dataRef = useRef<LiquidityProvisionData[] | null>(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 targetStake = marketData?.targetStake;
|
||||||
const suppliedStake = marketData?.suppliedStake;
|
const suppliedStake = marketData?.suppliedStake;
|
||||||
const assetDecimalPlaces =
|
const assetDecimalPlaces =
|
||||||
@ -178,44 +149,8 @@ export const LiquidityViewContainer = ({
|
|||||||
NetworkParams.market_liquidity_stakeToCcyVolume,
|
NetworkParams.market_liquidity_stakeToCcyVolume,
|
||||||
NetworkParams.market_liquidity_targetstake_triggering_ratio,
|
NetworkParams.market_liquidity_targetstake_triggering_ratio,
|
||||||
]);
|
]);
|
||||||
const stakeToCcyVolume = params.market_liquidity_stakeToCcyVolume;
|
|
||||||
const triggeringRatio =
|
const triggeringRatio =
|
||||||
params.market_liquidity_targetstake_triggering_ratio || '1';
|
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({
|
const { percentage, status } = useCheckLiquidityStatus({
|
||||||
suppliedStake: suppliedStake || 0,
|
suppliedStake: suppliedStake || 0,
|
||||||
@ -224,17 +159,15 @@ export const LiquidityViewContainer = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AsyncRenderer loading={loading} error={error} data={liquidityProviders}>
|
|
||||||
<div className="h-full grid grid-rows-[min-content_1fr]">
|
|
||||||
<Header
|
<Header
|
||||||
title={
|
title={
|
||||||
market?.tradableInstrument.instrument.name &&
|
market?.tradableInstrument.instrument.name &&
|
||||||
market?.tradableInstrument.instrument.code &&
|
market?.tradableInstrument.instrument.code &&
|
||||||
marketId && (
|
marketId && (
|
||||||
<HeaderTitle
|
<HeaderTitle
|
||||||
primaryContent={`${
|
primaryContent={`${market.tradableInstrument.instrument.code} ${t(
|
||||||
market.tradableInstrument.instrument.code
|
'liquidity provision'
|
||||||
} ${t('liquidity provision')}`}
|
)}`}
|
||||||
secondaryContent={
|
secondaryContent={
|
||||||
<Link to={Links[Routes.MARKET](marketId)}>
|
<Link to={Links[Routes.MARKET](marketId)}>
|
||||||
<UiToolkitLink>{t('Go to trading')}</UiToolkitLink>
|
<UiToolkitLink>{t('Go to trading')}</UiToolkitLink>
|
||||||
@ -270,10 +203,7 @@ export const LiquidityViewContainer = ({
|
|||||||
: '-'}
|
: '-'}
|
||||||
</div>
|
</div>
|
||||||
</HeaderStat>
|
</HeaderStat>
|
||||||
<HeaderStat
|
<HeaderStat heading={t('Liquidity supplied')} testId="liquidity-supplied">
|
||||||
heading={t('Liquidity supplied')}
|
|
||||||
testId="liquidity-supplied"
|
|
||||||
>
|
|
||||||
<Indicator variant={status} />
|
<Indicator variant={status} />
|
||||||
|
|
||||||
{formatNumberPercentage(percentage, 2)}
|
{formatNumberPercentage(percentage, 2)}
|
||||||
@ -282,7 +212,143 @@ export const LiquidityViewContainer = ({
|
|||||||
<div className="break-word">{marketId}</div>
|
<div className="break-word">{marketId}</div>
|
||||||
</HeaderStat>
|
</HeaderStat>
|
||||||
</Header>
|
</Header>
|
||||||
<Tabs defaultValue={getActiveDefaultId()}>
|
);
|
||||||
|
});
|
||||||
|
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<AgGridReact | null>(null);
|
||||||
|
const { data: market } = useMarket(marketId);
|
||||||
|
const dataRef = useRef<LiquidityProvisionData[] | null>(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 (
|
||||||
|
<AsyncRenderer loading={loading} error={error} data={liquidityProviders}>
|
||||||
|
<div className="h-full grid grid-rows-[min-content_1fr]">
|
||||||
|
<LiquidityViewHeader marketId={marketId} />
|
||||||
|
<Tabs value={tab} onValueChange={setTab}>
|
||||||
<Tab
|
<Tab
|
||||||
id={LiquidityTabs.MyLiquidityProvision}
|
id={LiquidityTabs.MyLiquidityProvision}
|
||||||
name={t('My liquidity provision')}
|
name={t('My liquidity provision')}
|
||||||
@ -309,7 +375,6 @@ export const LiquidityViewContainer = ({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Tab>
|
</Tab>
|
||||||
{
|
|
||||||
<Tab id={LiquidityTabs.Inactive} name={t('Inactive')}>
|
<Tab id={LiquidityTabs.Inactive} name={t('Inactive')}>
|
||||||
{inactiveEdges && (
|
{inactiveEdges && (
|
||||||
<LiquidityTable
|
<LiquidityTable
|
||||||
@ -321,7 +386,6 @@ export const LiquidityViewContainer = ({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Tab>
|
</Tab>
|
||||||
}
|
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</div>
|
</div>
|
||||||
</AsyncRenderer>
|
</AsyncRenderer>
|
||||||
|
@ -65,11 +65,23 @@ export const liquidityProvisionsDataProvider = makeDataProvider<
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
getData: (responseData: LiquidityProvisionsQuery | null) => {
|
getData: (responseData: LiquidityProvisionsQuery | null) => {
|
||||||
|
// to remove dedupe after core fix https://github.com/vegaprotocol/vega/issues/8043
|
||||||
|
const dedupeArr: string[] = [];
|
||||||
return (
|
return (
|
||||||
responseData?.market?.liquidityProvisionsConnection?.edges?.map(
|
responseData?.market?.liquidityProvisionsConnection?.edges?.map(
|
||||||
(e) => e?.node
|
(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: (
|
getDelta: (
|
||||||
subscriptionData: LiquidityProvisionsUpdateSubscription
|
subscriptionData: LiquidityProvisionsUpdateSubscription
|
||||||
@ -96,8 +108,8 @@ export const getId = (
|
|||||||
>
|
>
|
||||||
) =>
|
) =>
|
||||||
isLpFragment(entry)
|
isLpFragment(entry)
|
||||||
? `${entry.party.id}${entry.status}${entry.createdAt}`
|
? `${entry.party.id}${entry.status}${entry.createdAt}${entry.updatedAt}`
|
||||||
: `${entry.partyID}${entry.status}${entry.createdAt}`;
|
: `${entry.partyID}${entry.status}${entry.createdAt}${entry.updatedAt}`;
|
||||||
|
|
||||||
export const marketLiquidityDataProvider = makeDataProvider<
|
export const marketLiquidityDataProvider = makeDataProvider<
|
||||||
MarketLpQuery,
|
MarketLpQuery,
|
||||||
|
@ -339,7 +339,7 @@ function makeDataProviderInternal<
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const initialFetch = async () => {
|
const initialFetch = async (isUpdate = false) => {
|
||||||
if (!client) {
|
if (!client) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -394,7 +394,7 @@ function makeDataProviderInternal<
|
|||||||
subscription = undefined;
|
subscription = undefined;
|
||||||
} finally {
|
} finally {
|
||||||
loading = false;
|
loading = false;
|
||||||
notifyAll();
|
notifyAll({ isUpdate });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -410,7 +410,7 @@ function makeDataProviderInternal<
|
|||||||
} else {
|
} else {
|
||||||
loading = true;
|
loading = true;
|
||||||
error = undefined;
|
error = undefined;
|
||||||
initialFetch();
|
initialFetch(true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user