feat: fix positions and margins providers update (#2753)

This commit is contained in:
Bartłomiej Głownia 2023-01-27 09:39:39 +01:00 committed by GitHub
parent 613262f7a5
commit 98b5260d93
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 140 additions and 207 deletions

View File

@ -112,7 +112,7 @@ export const SelectMarketPopover = ({
} = useMarketList(); } = useMarketList();
const variables = useMemo(() => ({ partyId: pubKey }), [pubKey]); const variables = useMemo(() => ({ partyId: pubKey }), [pubKey]);
const { const {
data: party, data: positions,
loading: positionsLoading, loading: positionsLoading,
reload, reload,
} = useDataProvider({ } = useDataProvider({
@ -132,11 +132,9 @@ export const SelectMarketPopover = ({
const markets = useMemo( const markets = useMemo(
() => () =>
data?.filter((market) => data?.filter((market) =>
party?.positionsConnection?.edges?.find( positions?.find((node) => node.market.id === market.id)
(edge) => edge.node.market.id === market.id
)
), ),
[data, party] [data, positions]
); );
useEffect(() => { useEffect(() => {
@ -172,15 +170,13 @@ export const SelectMarketPopover = ({
</div> </div>
) : ( ) : (
<table className="relative text-sm w-full whitespace-nowrap"> <table className="relative text-sm w-full whitespace-nowrap">
{pubKey && (party?.positionsConnection?.edges?.length ?? 0) > 0 ? ( {pubKey && (positions?.length ?? 0) > 0 ? (
<> <>
<TableTitle>{t('My markets')}</TableTitle> <TableTitle>{t('My markets')}</TableTitle>
<SelectAllMarketsTableBody <SelectAllMarketsTableBody
inViewRoot={inViewRoot} inViewRoot={inViewRoot}
markets={markets} markets={markets}
positions={party?.positionsConnection?.edges positions={positions || undefined}
?.filter((edge) => edge.node)
.map((edge) => edge.node)}
onSelect={onSelectMarket} onSelect={onSelectMarket}
onCellClick={onCellClick} onCellClick={onCellClick}
headers={columnHeadersPositionMarkets} headers={columnHeadersPositionMarkets}

View File

@ -96,7 +96,7 @@ const EthTxPendingToastContent = ({ tx }: EthTxToastContentProps) => {
return ( return (
<div> <div>
<h3 className="font-bold">{t('Awaiting confirmation')}</h3> <h3 className="font-bold">{t('Awaiting confirmation')}</h3>
<p>{t('Please wait for your transaction to be confirmed')}</p> <p>{t('Please wait for your transaction to be confirmed.')}</p>
<EtherscanLink tx={tx} /> <EtherscanLink tx={tx} />
<EthTransactionDetails tx={tx} /> <EthTransactionDetails tx={tx} />
</div> </div>
@ -138,7 +138,7 @@ const EthTxConfirmedToastContent = ({ tx }: EthTxToastContentProps) => {
return ( return (
<div> <div>
<h3 className="font-bold">{t('Transaction confirmed')}</h3> <h3 className="font-bold">{t('Transaction confirmed')}</h3>
<p>{t('Your transaction has been confirmed')}</p> <p>{t('Your transaction has been confirmed.')}</p>
<EtherscanLink tx={tx} /> <EtherscanLink tx={tx} />
<EthTransactionDetails tx={tx} /> <EthTransactionDetails tx={tx} />
</div> </div>
@ -153,7 +153,7 @@ const EthTxCompletedToastContent = ({ tx }: EthTxToastContentProps) => {
{t('Processing')} {isDeposit && t('deposit')} {t('Processing')} {isDeposit && t('deposit')}
</h3> </h3>
<p> <p>
{t('Your transaction has been completed.')} {t('Your transaction has been completed.')}{' '}
{isDeposit && t('Waiting for deposit confirmation.')} {isDeposit && t('Waiting for deposit confirmation.')}
</p> </p>
<EtherscanLink tx={tx} /> <EtherscanLink tx={tx} />

View File

@ -1,64 +1,62 @@
import produce from 'immer'; import produce from 'immer';
import { makeDataProvider } from '@vegaprotocol/react-helpers'; import {
makeDataProvider,
removePaginationWrapper,
} from '@vegaprotocol/react-helpers';
import { import {
MarginsSubscriptionDocument, MarginsSubscriptionDocument,
MarginsDocument, MarginsDocument,
} from './__generated__/Positions'; } from './__generated__/Positions';
import type { import type {
MarginsQuery, MarginsQuery,
MarginFieldsFragment,
MarginsSubscriptionSubscription, MarginsSubscriptionSubscription,
} from './__generated__/Positions'; } from './__generated__/Positions';
const update = ( const update = (
data: MarginsQuery['party'], data: MarginFieldsFragment[],
delta: MarginsSubscriptionSubscription['margins'] delta: MarginsSubscriptionSubscription['margins']
) => { ) => {
return produce(data, (draft) => { return produce(data, (draft) => {
const { marketId } = delta; const { marketId } = delta;
if (marketId && draft?.marginsConnection?.edges) { const index = draft.findIndex((node) => node.market.id === marketId);
const index = draft.marginsConnection.edges.findIndex( if (index !== -1) {
(edge) => edge.node.market.id === marketId const currNode = draft[index];
); draft[index] = {
if (index !== -1) { ...currNode,
const currNode = draft.marginsConnection.edges[index].node; maintenanceLevel: delta.maintenanceLevel,
draft.marginsConnection.edges[index].node = { searchLevel: delta.searchLevel,
...currNode, initialLevel: delta.initialLevel,
maintenanceLevel: delta.maintenanceLevel, collateralReleaseLevel: delta.collateralReleaseLevel,
searchLevel: delta.searchLevel, };
initialLevel: delta.initialLevel, } else {
collateralReleaseLevel: delta.collateralReleaseLevel, draft.unshift({
}; __typename: 'MarginLevels',
} else { market: {
draft.marginsConnection.edges.unshift({ __typename: 'Market',
__typename: 'MarginEdge', id: delta.marketId,
node: { },
__typename: 'MarginLevels', maintenanceLevel: delta.maintenanceLevel,
market: { searchLevel: delta.searchLevel,
__typename: 'Market', initialLevel: delta.initialLevel,
id: delta.marketId, collateralReleaseLevel: delta.collateralReleaseLevel,
}, asset: {
maintenanceLevel: delta.maintenanceLevel, __typename: 'Asset',
searchLevel: delta.searchLevel, id: delta.asset,
initialLevel: delta.initialLevel, },
collateralReleaseLevel: delta.collateralReleaseLevel, });
asset: {
__typename: 'Asset',
id: delta.asset,
},
},
});
}
} }
}); });
}; };
const getData = (responseData: MarginsQuery) => responseData.party; const getData = (responseData: MarginsQuery) =>
removePaginationWrapper(responseData.party?.marginsConnection?.edges) || [];
const getDelta = (subscriptionData: MarginsSubscriptionSubscription) => const getDelta = (subscriptionData: MarginsSubscriptionSubscription) =>
subscriptionData.margins; subscriptionData.margins;
export const marginsDataProvider = makeDataProvider< export const marginsDataProvider = makeDataProvider<
MarginsQuery, MarginsQuery,
MarginsQuery['party'], MarginFieldsFragment[],
MarginsSubscriptionSubscription, MarginsSubscriptionSubscription,
MarginsSubscriptionSubscription['margins'] MarginsSubscriptionSubscription['margins']
>({ >({

View File

@ -1,7 +1,10 @@
import * as Schema from '@vegaprotocol/types'; import * as Schema from '@vegaprotocol/types';
import type { Account } from '@vegaprotocol/accounts'; import type { Account } from '@vegaprotocol/accounts';
import type { MarketWithData } from '@vegaprotocol/market-list'; import type { MarketWithData } from '@vegaprotocol/market-list';
import type { PositionsQuery, MarginsQuery } from './__generated__/Positions'; import type {
PositionFieldsFragment,
MarginFieldsFragment,
} from './__generated__/Positions';
import { getMetrics, rejoinPositionData } from './positions-data-providers'; import { getMetrics, rejoinPositionData } from './positions-data-providers';
const accounts = [ const accounts = [
@ -63,47 +66,32 @@ const accounts = [
}, },
] as Account[]; ] as Account[];
const positions: PositionsQuery = { const positions: PositionFieldsFragment[] = [
party: { {
__typename: 'Party', __typename: 'Position',
id: '02eceaba4df2bef76ea10caf728d8a099a2aa846cced25737cccaa9812342f65', openVolume: '100',
positionsConnection: { averageEntryPrice: '8993727',
__typename: 'PositionConnection', updatedAt: '2022-07-28T14:53:54.725477Z',
edges: [ realisedPNL: '0',
{ unrealisedPNL: '43804770',
__typename: 'PositionEdge', market: {
node: { __typename: 'Market',
__typename: 'Position', id: '5e6035fe6a6df78c9ec44b333c231e63d357acef0a0620d2c243f5865d1dc0d8',
openVolume: '100',
averageEntryPrice: '8993727',
updatedAt: '2022-07-28T14:53:54.725477Z',
realisedPNL: '0',
unrealisedPNL: '43804770',
market: {
__typename: 'Market',
id: '5e6035fe6a6df78c9ec44b333c231e63d357acef0a0620d2c243f5865d1dc0d8',
},
},
},
{
__typename: 'PositionEdge',
node: {
__typename: 'Position',
openVolume: '-100',
realisedPNL: '0',
unrealisedPNL: '-9112700',
averageEntryPrice: '840158',
updatedAt: '2022-07-28T15:09:34.441143Z',
market: {
__typename: 'Market',
id: '10c4b1114d2f6fda239b73d018bca55888b6018f0ac70029972a17fea0a6a56e',
},
},
},
],
}, },
}, },
}; {
__typename: 'Position',
openVolume: '-100',
realisedPNL: '0',
unrealisedPNL: '-9112700',
averageEntryPrice: '840158',
updatedAt: '2022-07-28T15:09:34.441143Z',
market: {
__typename: 'Market',
id: '10c4b1114d2f6fda239b73d018bca55888b6018f0ac70029972a17fea0a6a56e',
},
},
];
const marketsData = [ const marketsData = [
{ {
@ -162,60 +150,44 @@ const marketsData = [
}, },
] as MarketWithData[]; ] as MarketWithData[];
const margins: MarginsQuery = { const margins: MarginFieldsFragment[] = [
party: { {
id: '02eceaba4df2bef76ea10caf728d8a099a2aa846cced25737cccaa9812342f65', __typename: 'MarginLevels',
marginsConnection: { maintenanceLevel: '0',
edges: [ searchLevel: '0',
{ initialLevel: '0',
__typename: 'MarginEdge', collateralReleaseLevel: '0',
node: { market: {
__typename: 'MarginLevels', __typename: 'Market',
maintenanceLevel: '0', id: '5e6035fe6a6df78c9ec44b333c231e63d357acef0a0620d2c243f5865d1dc0d8',
searchLevel: '0', },
initialLevel: '0', asset: {
collateralReleaseLevel: '0', __typename: 'Asset',
market: { id: 'tDAI-id',
__typename: 'Market',
id: '5e6035fe6a6df78c9ec44b333c231e63d357acef0a0620d2c243f5865d1dc0d8',
},
asset: {
__typename: 'Asset',
id: 'tDAI-id',
},
},
},
{
__typename: 'MarginEdge',
node: {
__typename: 'MarginLevels',
maintenanceLevel: '0',
searchLevel: '0',
initialLevel: '0',
collateralReleaseLevel: '0',
market: {
__typename: 'Market',
id: '10c4b1114d2f6fda239b73d018bca55888b6018f0ac70029972a17fea0a6a56e',
},
asset: {
__typename: 'Asset',
id: 'tDAI-id',
},
},
},
],
__typename: 'MarginConnection',
}, },
__typename: 'Party',
}, },
}; {
__typename: 'MarginLevels',
maintenanceLevel: '0',
searchLevel: '0',
initialLevel: '0',
collateralReleaseLevel: '0',
market: {
__typename: 'Market',
id: '10c4b1114d2f6fda239b73d018bca55888b6018f0ac70029972a17fea0a6a56e',
},
asset: {
__typename: 'Asset',
id: 'tDAI-id',
},
},
];
describe('getMetrics && rejoinPositionData', () => { describe('getMetrics && rejoinPositionData', () => {
it('returns positions metrics', () => { it('returns positions metrics', () => {
const positionsRejoined = rejoinPositionData( const positionsRejoined = rejoinPositionData(
positions.party, positions,
marketsData, marketsData,
margins.party margins
); );
const metrics = getMetrics(positionsRejoined, accounts || null); const metrics = getMetrics(positionsRejoined, accounts || null);
expect(metrics.length).toEqual(2); expect(metrics.length).toEqual(2);
@ -223,9 +195,9 @@ describe('getMetrics && rejoinPositionData', () => {
it('calculates metrics', () => { it('calculates metrics', () => {
const positionsRejoined = rejoinPositionData( const positionsRejoined = rejoinPositionData(
positions.party, positions,
marketsData, marketsData,
margins.party margins
); );
const metrics = getMetrics(positionsRejoined, accounts || null); const metrics = getMetrics(positionsRejoined, accounts || null);

View File

@ -8,14 +8,15 @@ import { toBigNum } from '@vegaprotocol/react-helpers';
import { import {
makeDataProvider, makeDataProvider,
makeDerivedDataProvider, makeDerivedDataProvider,
removePaginationWrapper,
} from '@vegaprotocol/react-helpers'; } from '@vegaprotocol/react-helpers';
import * as Schema from '@vegaprotocol/types'; import * as Schema from '@vegaprotocol/types';
import type { MarketWithData } from '@vegaprotocol/market-list'; import type { MarketWithData } from '@vegaprotocol/market-list';
import { marketsWithDataProvider } from '@vegaprotocol/market-list'; import { marketsWithDataProvider } from '@vegaprotocol/market-list';
import type { import type {
PositionsQuery, PositionsQuery,
PositionFieldsFragment,
PositionsSubscriptionSubscription, PositionsSubscriptionSubscription,
MarginsQuery,
MarginFieldsFragment, MarginFieldsFragment,
} from './__generated__/Positions'; } from './__generated__/Positions';
import { import {
@ -170,20 +171,17 @@ export const getMetrics = (
}; };
export const update = ( export const update = (
data: PositionsQuery['party'], data: PositionFieldsFragment[],
deltas: PositionsSubscriptionSubscription['positions'] deltas: PositionsSubscriptionSubscription['positions']
) => { ) => {
return produce(data, (draft) => { return produce(data, (draft) => {
deltas.forEach((delta) => { deltas.forEach((delta) => {
if (!draft?.positionsConnection?.edges || !delta) { const index = draft.findIndex(
return; (node) => node.market.id === delta.marketId
}
const index = draft.positionsConnection.edges.findIndex(
(edge) => edge.node.market.id === delta.marketId
); );
if (index !== -1) { if (index !== -1) {
const currNode = draft.positionsConnection.edges[index].node; const currNode = draft[index];
draft.positionsConnection.edges[index].node = { draft[index] = {
...currNode, ...currNode,
realisedPNL: delta.realisedPNL, realisedPNL: delta.realisedPNL,
unrealisedPNL: delta.unrealisedPNL, unrealisedPNL: delta.unrealisedPNL,
@ -192,15 +190,12 @@ export const update = (
updatedAt: delta.updatedAt, updatedAt: delta.updatedAt,
}; };
} else { } else {
draft.positionsConnection.edges.unshift({ draft.unshift({
__typename: 'PositionEdge', ...delta,
node: { __typename: 'Position',
...delta, market: {
__typename: 'Position', __typename: 'Market',
market: { id: delta.marketId,
__typename: 'Market',
id: delta.marketId,
},
}, },
}); });
} }
@ -210,29 +205,29 @@ export const update = (
export const positionsDataProvider = makeDataProvider< export const positionsDataProvider = makeDataProvider<
PositionsQuery, PositionsQuery,
PositionsQuery['party'], PositionFieldsFragment[],
PositionsSubscriptionSubscription, PositionsSubscriptionSubscription,
PositionsSubscriptionSubscription['positions'] PositionsSubscriptionSubscription['positions']
>({ >({
query: PositionsDocument, query: PositionsDocument,
subscriptionQuery: PositionsSubscriptionDocument, subscriptionQuery: PositionsSubscriptionDocument,
update, update,
getData: (responseData: PositionsQuery) => responseData.party, getData: (responseData: PositionsQuery) =>
removePaginationWrapper(responseData.party?.positionsConnection?.edges) ||
[],
getDelta: (subscriptionData: PositionsSubscriptionSubscription) => getDelta: (subscriptionData: PositionsSubscriptionSubscription) =>
subscriptionData.positions, subscriptionData.positions,
}); });
const upgradeMarginsConnection = ( const upgradeMarginsConnection = (
marketId: string, marketId: string,
margins: MarginsQuery['party'] | null margins: MarginFieldsFragment[] | null
) => { ) => {
if (marketId && margins?.marginsConnection?.edges) { if (marketId && margins) {
const index = const index =
margins.marginsConnection.edges.findIndex( margins.findIndex((node) => node.market.id === marketId) ?? -1;
(edge) => edge.node.market.id === marketId
) ?? -1;
if (index >= 0) { if (index >= 0) {
const marginLevel = margins.marginsConnection.edges[index].node; const marginLevel = margins[index];
return { return {
maintenanceLevel: marginLevel.maintenanceLevel, maintenanceLevel: marginLevel.maintenanceLevel,
searchLevel: marginLevel.searchLevel, searchLevel: marginLevel.searchLevel,
@ -244,12 +239,12 @@ const upgradeMarginsConnection = (
}; };
export const rejoinPositionData = ( export const rejoinPositionData = (
positions: PositionsQuery['party'] | null, positions: PositionFieldsFragment[] | null,
marketsData: MarketWithData[] | null, marketsData: MarketWithData[] | null,
margins: MarginsQuery['party'] | null margins: MarginFieldsFragment[] | null
): PositionRejoined[] | null => { ): PositionRejoined[] | null => {
if (positions?.positionsConnection?.edges && marketsData && margins) { if (positions && marketsData && margins) {
return positions.positionsConnection.edges.map(({ node }) => { return positions.map((node) => {
return { return {
realisedPNL: node.realisedPNL, realisedPNL: node.realisedPNL,
openVolume: node.openVolume, openVolume: node.openVolume,

View File

@ -2,30 +2,17 @@ import { useCallback, useState } from 'react';
import { useVegaWallet } from '@vegaprotocol/wallet'; import { useVegaWallet } from '@vegaprotocol/wallet';
import { useDataProvider } from '@vegaprotocol/react-helpers'; import { useDataProvider } from '@vegaprotocol/react-helpers';
import { marginsDataProvider } from './margin-data-provider'; import { marginsDataProvider } from './margin-data-provider';
import type { import type { MarginFieldsFragment } from './__generated__/Positions';
MarginsQuery,
MarginsSubscriptionSubscription,
} from './__generated__/Positions';
const getMarketMarginPosition = ({
data,
marketId,
}: {
data: MarginsQuery['party'] | null;
marketId: string;
}) => {
const positions =
data?.marginsConnection?.edges?.map((item) => item.node) ?? [];
return positions.find((item) => item.market.id === marketId);
};
export const useMarketMargin = (marketId: string) => { export const useMarketMargin = (marketId: string) => {
const { pubKey } = useVegaWallet(); const { pubKey } = useVegaWallet();
const [marginLevel, setMarginLevel] = useState<string>(''); const [marginLevel, setMarginLevel] = useState<string>('');
const update = useCallback( const update = useCallback(
({ data }: { data: MarginsQuery['party'] | null }) => { ({ data }: { data: MarginFieldsFragment[] | null }) => {
const marginMarketPosition = getMarketMarginPosition({ data, marketId }); const marginMarketPosition = data?.find(
(item) => item.market.id === marketId
);
if (marginMarketPosition?.maintenanceLevel) { if (marginMarketPosition?.maintenanceLevel) {
setMarginLevel(marginMarketPosition?.maintenanceLevel || ''); setMarginLevel(marginMarketPosition?.maintenanceLevel || '');
} }
@ -34,10 +21,7 @@ export const useMarketMargin = (marketId: string) => {
[setMarginLevel, marketId] [setMarginLevel, marketId]
); );
useDataProvider< useDataProvider({
MarginsQuery['party'],
MarginsSubscriptionSubscription['margins']
>({
dataProvider: marginsDataProvider, dataProvider: marginsDataProvider,
variables: { partyId: pubKey || '' }, variables: { partyId: pubKey || '' },
skip: !pubKey || !marketId, skip: !pubKey || !marketId,

View File

@ -3,28 +3,16 @@ import { useVegaWallet } from '@vegaprotocol/wallet';
import { positionsDataProvider } from './positions-data-providers'; import { positionsDataProvider } from './positions-data-providers';
import { useDataProvider } from '@vegaprotocol/react-helpers'; import { useDataProvider } from '@vegaprotocol/react-helpers';
import type { import type {
PositionsQuery, PositionFieldsFragment,
PositionsSubscriptionSubscription, PositionsSubscriptionSubscription,
} from './__generated__/Positions'; } from './__generated__/Positions';
const getMarketPosition = ({
data,
marketId,
}: {
data: PositionsQuery['party'];
marketId: string;
}) => {
const positions =
data?.positionsConnection?.edges?.map((item) => item.node) ?? [];
return positions.find((item) => item.market.id === marketId);
};
export const useMarketPositionOpenVolume = (marketId: string) => { export const useMarketPositionOpenVolume = (marketId: string) => {
const { pubKey } = useVegaWallet(); const { pubKey } = useVegaWallet();
const [openVolume, setOpenVolume] = useState<string>(''); const [openVolume, setOpenVolume] = useState<string>('');
const update = useCallback( const update = useCallback(
({ data }: { data: PositionsQuery['party'] | undefined }) => { ({ data }: { data: PositionFieldsFragment[] | null }) => {
const position = getMarketPosition({ data, marketId }); const position = data?.find((node) => node.market.id === marketId);
if (position?.openVolume) { if (position?.openVolume) {
setOpenVolume(position?.openVolume || ''); setOpenVolume(position?.openVolume || '');
} }
@ -34,7 +22,7 @@ export const useMarketPositionOpenVolume = (marketId: string) => {
); );
useDataProvider< useDataProvider<
PositionsQuery['party'], PositionFieldsFragment[],
PositionsSubscriptionSubscription['positions'] PositionsSubscriptionSubscription['positions']
>({ >({
dataProvider: positionsDataProvider, dataProvider: positionsDataProvider,