chore(trading): liquidity table DRY (#3346)
This commit is contained in:
parent
0914e7ce4b
commit
8463d371ad
@ -1,5 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
getId,
|
matchFilter,
|
||||||
liquidityProvisionsDataProvider,
|
liquidityProvisionsDataProvider,
|
||||||
LiquidityTable,
|
LiquidityTable,
|
||||||
lpAggregatedDataProvider,
|
lpAggregatedDataProvider,
|
||||||
@ -17,7 +17,6 @@ import {
|
|||||||
useNetworkParams,
|
useNetworkParams,
|
||||||
updateGridData,
|
updateGridData,
|
||||||
} from '@vegaprotocol/react-helpers';
|
} from '@vegaprotocol/react-helpers';
|
||||||
import * as Schema from '@vegaprotocol/types';
|
|
||||||
import {
|
import {
|
||||||
AsyncRenderer,
|
AsyncRenderer,
|
||||||
Tab,
|
Tab,
|
||||||
@ -26,19 +25,18 @@ import {
|
|||||||
Indicator,
|
Indicator,
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||||
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import { memo, useCallback, useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
import { Header, HeaderStat, HeaderTitle } from '../../components/header';
|
import { Header, HeaderStat, HeaderTitle } from '../../components/header';
|
||||||
|
|
||||||
import type { AgGridReact } from 'ag-grid-react';
|
import type { AgGridReact } from 'ag-grid-react';
|
||||||
import type { IGetRowsParams } from 'ag-grid-community';
|
import type { IGetRowsParams } from 'ag-grid-community';
|
||||||
|
|
||||||
import type { LiquidityProvisionData } from '@vegaprotocol/liquidity';
|
import type { LiquidityProvisionData, Filter } from '@vegaprotocol/liquidity';
|
||||||
import { Link, useParams } from 'react-router-dom';
|
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 {
|
const enum LiquidityTabs {
|
||||||
Active = 'active',
|
Active = 'active',
|
||||||
@ -67,8 +65,10 @@ const useReloadLiquidityData = (marketId: string | undefined) => {
|
|||||||
|
|
||||||
export const LiquidityContainer = ({
|
export const LiquidityContainer = ({
|
||||||
marketId,
|
marketId,
|
||||||
|
filter,
|
||||||
}: {
|
}: {
|
||||||
marketId: string | undefined;
|
marketId: string | undefined;
|
||||||
|
filter?: Filter;
|
||||||
}) => {
|
}) => {
|
||||||
const gridRef = useRef<AgGridReact | null>(null);
|
const gridRef = useRef<AgGridReact | null>(null);
|
||||||
const { data: market } = useMarket(marketId);
|
const { data: market } = useMarket(marketId);
|
||||||
@ -87,7 +87,7 @@ export const LiquidityContainer = ({
|
|||||||
const { data, loading, error } = useDataProvider({
|
const { data, loading, error } = useDataProvider({
|
||||||
dataProvider: lpAggregatedDataProvider,
|
dataProvider: lpAggregatedDataProvider,
|
||||||
update,
|
update,
|
||||||
variables: { marketId: marketId || '' },
|
variables: { marketId: marketId || '', filter },
|
||||||
skip: !marketId,
|
skip: !marketId,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -216,178 +216,56 @@ const LiquidityViewHeader = memo(({ marketId }: { marketId?: string }) => {
|
|||||||
});
|
});
|
||||||
LiquidityViewHeader.displayName = 'LiquidityViewHeader';
|
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 = ({
|
export const LiquidityViewContainer = ({
|
||||||
marketId,
|
marketId,
|
||||||
}: {
|
}: {
|
||||||
marketId: string | undefined;
|
marketId: string | undefined;
|
||||||
}) => {
|
}) => {
|
||||||
const [tab, setTab] = useState('');
|
const [tab, setTab] = useState<string | undefined>(undefined);
|
||||||
const { pubKey } = useVegaWallet();
|
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
|
const { data } = useDataProvider({
|
||||||
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,
|
dataProvider: lpAggregatedDataProvider,
|
||||||
update,
|
skipUpdates: true,
|
||||||
variables: { marketId: marketId || '' },
|
variables: { marketId: marketId || '' },
|
||||||
skip: !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(() => {
|
useEffect(() => {
|
||||||
if (tab) {
|
if (data) {
|
||||||
return;
|
if (pubKey && data.some((lp) => matchFilter({ partyId: pubKey }, lp))) {
|
||||||
|
setTab(LiquidityTabs.MyLiquidityProvision);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (data.some((lp) => matchFilter({ active: true }, lp))) {
|
||||||
|
setTab(LiquidityTabs.Active);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setTab(LiquidityTabs.Inactive);
|
||||||
}
|
}
|
||||||
let initialTab = LiquidityTabs.Active;
|
}, [data, pubKey]);
|
||||||
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 (
|
return (
|
||||||
<AsyncRenderer loading={loading} error={error} data={liquidityProviders}>
|
<div className="h-full grid grid-rows-[min-content_1fr]">
|
||||||
<div className="h-full grid grid-rows-[min-content_1fr]">
|
<LiquidityViewHeader marketId={marketId} />
|
||||||
<LiquidityViewHeader marketId={marketId} />
|
<Tabs value={tab || LiquidityTabs.Active} onValueChange={setTab}>
|
||||||
<Tabs value={tab} onValueChange={setTab}>
|
<Tab
|
||||||
<Tab
|
id={LiquidityTabs.MyLiquidityProvision}
|
||||||
id={LiquidityTabs.MyLiquidityProvision}
|
name={t('My liquidity provision')}
|
||||||
name={t('My liquidity provision')}
|
hidden={!pubKey}
|
||||||
hidden={!pubKey}
|
>
|
||||||
>
|
<LiquidityContainer
|
||||||
{myLpEdges && (
|
marketId={marketId}
|
||||||
<LiquidityTable
|
filter={{ partyId: pubKey || undefined }}
|
||||||
ref={gridRef}
|
/>
|
||||||
rowData={myLpEdges}
|
</Tab>
|
||||||
symbol={symbol}
|
<Tab id={LiquidityTabs.Active} name={t('Active')}>
|
||||||
stakeToCcyVolume={stakeToCcyVolume}
|
<LiquidityContainer marketId={marketId} filter={{ active: true }} />
|
||||||
assetDecimalPlaces={assetDecimalPlaces}
|
</Tab>
|
||||||
/>
|
<Tab id={LiquidityTabs.Inactive} name={t('Inactive')}>
|
||||||
)}
|
<LiquidityContainer marketId={marketId} filter={{ active: false }} />
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab id={LiquidityTabs.Active} name={t('Active')}>
|
</Tabs>
|
||||||
{activeEdges && (
|
</div>
|
||||||
<LiquidityTable
|
|
||||||
ref={gridRef}
|
|
||||||
rowData={activeEdges}
|
|
||||||
symbol={symbol}
|
|
||||||
assetDecimalPlaces={assetDecimalPlaces}
|
|
||||||
stakeToCcyVolume={stakeToCcyVolume}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Tab>
|
|
||||||
<Tab id={LiquidityTabs.Inactive} name={t('Inactive')}>
|
|
||||||
{inactiveEdges && (
|
|
||||||
<LiquidityTable
|
|
||||||
ref={gridRef}
|
|
||||||
rowData={inactiveEdges}
|
|
||||||
symbol={symbol}
|
|
||||||
assetDecimalPlaces={assetDecimalPlaces}
|
|
||||||
stakeToCcyVolume={stakeToCcyVolume}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Tab>
|
|
||||||
</Tabs>
|
|
||||||
</div>
|
|
||||||
</AsyncRenderer>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -153,35 +153,84 @@ export const liquidityFeeShareDataProvider = makeDataProvider<
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export type Filter = { partyId?: string; active?: boolean };
|
||||||
|
|
||||||
export const lpAggregatedDataProvider = makeDerivedDataProvider<
|
export const lpAggregatedDataProvider = makeDerivedDataProvider<
|
||||||
ReturnType<typeof getLiquidityProvision>,
|
LiquidityProvisionData[],
|
||||||
never,
|
never,
|
||||||
MarketLpQueryVariables
|
MarketLpQueryVariables & { filter?: Filter }
|
||||||
>(
|
>(
|
||||||
[
|
[
|
||||||
liquidityProvisionsDataProvider,
|
(callback, client, variables) =>
|
||||||
marketLiquidityDataProvider,
|
liquidityProvisionsDataProvider(callback, client, {
|
||||||
liquidityFeeShareDataProvider,
|
marketId: variables.marketId,
|
||||||
|
}),
|
||||||
|
(callback, client, variables) =>
|
||||||
|
marketLiquidityDataProvider(callback, client, {
|
||||||
|
marketId: variables.marketId,
|
||||||
|
}),
|
||||||
|
(callback, client, variables) =>
|
||||||
|
liquidityFeeShareDataProvider(callback, client, {
|
||||||
|
marketId: variables.marketId,
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
([
|
(
|
||||||
liquidityProvisions,
|
[liquidityProvisions, marketLiquidity, liquidityFeeShare],
|
||||||
marketLiquidity,
|
{ filter }
|
||||||
liquidityFeeShare,
|
): LiquidityProvisionData[] => {
|
||||||
]): LiquidityProvisionData[] => {
|
|
||||||
return getLiquidityProvision(
|
return getLiquidityProvision(
|
||||||
liquidityProvisions,
|
liquidityProvisions,
|
||||||
marketLiquidity,
|
marketLiquidity,
|
||||||
liquidityFeeShare
|
liquidityFeeShare,
|
||||||
|
filter
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const matchFilter = (
|
||||||
|
filter: Filter,
|
||||||
|
lp: LiquidityProvisionFieldsFragment
|
||||||
|
) => {
|
||||||
|
if (filter.partyId && lp.party.id !== filter.partyId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
filter.active === true &&
|
||||||
|
lp.status !== Schema.LiquidityProvisionStatus.STATUS_ACTIVE
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
filter.active === false &&
|
||||||
|
lp.status === Schema.LiquidityProvisionStatus.STATUS_ACTIVE
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
export const getLiquidityProvision = (
|
export const getLiquidityProvision = (
|
||||||
liquidityProvisions: LiquidityProvisionFieldsFragment[],
|
liquidityProvisions: LiquidityProvisionFieldsFragment[],
|
||||||
marketLiquidity: MarketLpQuery,
|
marketLiquidity: MarketLpQuery,
|
||||||
liquidityFeeShare: LiquidityProviderFeeShareFieldsFragment[]
|
liquidityFeeShare: LiquidityProviderFeeShareFieldsFragment[],
|
||||||
|
filter?: Filter
|
||||||
): LiquidityProvisionData[] => {
|
): LiquidityProvisionData[] => {
|
||||||
return liquidityProvisions
|
return liquidityProvisions
|
||||||
|
.filter((lp) => {
|
||||||
|
if (
|
||||||
|
![
|
||||||
|
Schema.LiquidityProvisionStatus.STATUS_ACTIVE,
|
||||||
|
Schema.LiquidityProvisionStatus.STATUS_UNDEPLOYED,
|
||||||
|
Schema.LiquidityProvisionStatus.STATUS_PENDING,
|
||||||
|
].includes(lp.status)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (filter && !matchFilter(filter, lp)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
})
|
||||||
.map((lp) => {
|
.map((lp) => {
|
||||||
const market = marketLiquidity?.market;
|
const market = marketLiquidity?.market;
|
||||||
const feeShare = liquidityFeeShare.find(
|
const feeShare = liquidityFeeShare.find(
|
||||||
@ -210,14 +259,7 @@ export const getLiquidityProvision = (
|
|||||||
.decimals,
|
.decimals,
|
||||||
balance,
|
balance,
|
||||||
};
|
};
|
||||||
})
|
});
|
||||||
.filter((e) =>
|
|
||||||
[
|
|
||||||
Schema.LiquidityProvisionStatus.STATUS_ACTIVE,
|
|
||||||
Schema.LiquidityProvisionStatus.STATUS_UNDEPLOYED,
|
|
||||||
Schema.LiquidityProvisionStatus.STATUS_PENDING,
|
|
||||||
].includes(e.status)
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface LiquidityProvisionData
|
export interface LiquidityProvisionData
|
||||||
|
Loading…
Reference in New Issue
Block a user