chore(2415): get rid of polling queries on deal ticket (#2427)

* chore: get rid of polling queries on dael ticket

* chore: get rid of polling queries on dael ticket - fix tests

* chore: get rid of polling queries on deal ticket - fix linter

* chore: get rid of polling queries on deal ticket - fix linter

* chore: get rid of polling queries on deal ticket - adjust int test

* chore: get rid of polling queries on deal ticket - adjust int test in console-lite

* chore: get rid of polling queries on deal ticket - adjust unit some test

* chore: get rid of polling queries on deal ticket - adjust unit some test

* chore: get rid of polling queries on deal ticket - clean up some redundant types

* chore: get rid of polling queries on deal ticket - clean up some redundant files
This commit is contained in:
macqbat 2022-12-20 10:01:10 +01:00 committed by GitHub
parent 07b766e4d2
commit b9ff2388db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
48 changed files with 514 additions and 1382 deletions

View File

@ -7,11 +7,7 @@ import {
generateSimpleMarkets, generateSimpleMarkets,
} from '../support/mocks/generate-markets'; } from '../support/mocks/generate-markets';
import { generateMarketTags } from '../support/mocks/generate-market-tags'; import { generateMarketTags } from '../support/mocks/generate-market-tags';
import { generateMarketPositions } from '../support/mocks/generate-market-positions';
import { generateEstimateOrder } from '../support/mocks/generate-estimate-order'; import { generateEstimateOrder } from '../support/mocks/generate-estimate-order';
import { generatePartyBalance } from '../support/mocks/generate-party-balance';
import { generatePartyMarketData } from '../support/mocks/generate-party-market-data';
import { generateMarketMarkPrice } from '../support/mocks/generate-market-mark-price';
import { generateMarketNames } from '../support/mocks/generate-market-names'; import { generateMarketNames } from '../support/mocks/generate-market-names';
import { generateMarketDepth } from '../support/mocks/generate-market-depth'; import { generateMarketDepth } from '../support/mocks/generate-market-depth';
import type { Market, MarketsQuery } from '@vegaprotocol/market-list'; import type { Market, MarketsQuery } from '@vegaprotocol/market-list';
@ -30,11 +26,7 @@ describe('market selector', { tags: '@smoke' }, () => {
aliasQuery(req, 'MarketData', generateMarketData()); aliasQuery(req, 'MarketData', generateMarketData());
aliasQuery(req, 'Market', generateMarket()); aliasQuery(req, 'Market', generateMarket());
aliasQuery(req, 'MarketTags', generateMarketTags()); aliasQuery(req, 'MarketTags', generateMarketTags());
aliasQuery(req, 'MarketPositions', generateMarketPositions());
aliasQuery(req, 'EstimateOrder', generateEstimateOrder()); aliasQuery(req, 'EstimateOrder', generateEstimateOrder());
aliasQuery(req, 'PartyBalance', generatePartyBalance());
aliasQuery(req, 'PartyMarketData', generatePartyMarketData());
aliasQuery(req, 'MarketMarkPrice', generateMarketMarkPrice());
aliasQuery(req, 'MarketNames', generateMarketNames()); aliasQuery(req, 'MarketNames', generateMarketNames());
aliasQuery(req, 'MarketDepth', generateMarketDepth()); aliasQuery(req, 'MarketDepth', generateMarketDepth());
}); });

View File

@ -7,15 +7,14 @@ import {
generateMarketData, generateMarketData,
} from '../support/mocks/generate-markets'; } from '../support/mocks/generate-markets';
import { generateMarketTags } from '../support/mocks/generate-market-tags'; import { generateMarketTags } from '../support/mocks/generate-market-tags';
import { generateMarketPositions } from '../support/mocks/generate-market-positions';
import { generateEstimateOrder } from '../support/mocks/generate-estimate-order'; import { generateEstimateOrder } from '../support/mocks/generate-estimate-order';
import { generatePartyBalance } from '../support/mocks/generate-party-balance';
import { generatePartyMarketData } from '../support/mocks/generate-party-market-data';
import { generateMarketMarkPrice } from '../support/mocks/generate-market-mark-price';
import { generateMarketDepth } from '../support/mocks/generate-market-depth'; import { generateMarketDepth } from '../support/mocks/generate-market-depth';
import type { MarketsQuery, Market } from '@vegaprotocol/market-list'; import type { MarketsQuery, Market } from '@vegaprotocol/market-list';
import { generateChainId } from '../support/mocks/generate-chain-id'; import { generateChainId } from '../support/mocks/generate-chain-id';
import { generateStatistics } from '../support/mocks/generate-statistics'; import { generateStatistics } from '../support/mocks/generate-statistics';
import { generateAccounts } from '../support/mocks/generate-accounts';
import { generateAssets } from '../support/mocks/generate-assets';
import { generatePositions } from '../support/mocks/generate-positions';
describe('Market trade', { tags: '@smoke' }, () => { describe('Market trade', { tags: '@smoke' }, () => {
let markets: Market[]; let markets: Market[];
@ -28,14 +27,13 @@ describe('Market trade', { tags: '@smoke' }, () => {
aliasQuery(req, 'MarketsData', generateMarketsData()); aliasQuery(req, 'MarketsData', generateMarketsData());
aliasQuery(req, 'SimpleMarkets', generateSimpleMarkets()); aliasQuery(req, 'SimpleMarkets', generateSimpleMarkets());
aliasQuery(req, 'MarketTags', generateMarketTags()); aliasQuery(req, 'MarketTags', generateMarketTags());
aliasQuery(req, 'MarketPositions', generateMarketPositions());
aliasQuery(req, 'EstimateOrder', generateEstimateOrder()); aliasQuery(req, 'EstimateOrder', generateEstimateOrder());
aliasQuery(req, 'PartyBalance', generatePartyBalance()); aliasQuery(req, 'Accounts', generateAccounts());
aliasQuery(req, 'PartyMarketData', generatePartyMarketData()); aliasQuery(req, 'Assets', generateAssets());
aliasQuery(req, 'MarketMarkPrice', generateMarketMarkPrice());
aliasQuery(req, 'MarketDepth', generateMarketDepth()); aliasQuery(req, 'MarketDepth', generateMarketDepth());
aliasQuery(req, 'Market', generateMarket()); aliasQuery(req, 'Market', generateMarket());
aliasQuery(req, 'MarketData', generateMarketData()); aliasQuery(req, 'MarketData', generateMarketData());
aliasQuery(req, 'Positions', generatePositions());
}); });
cy.visit('/markets'); cy.visit('/markets');
cy.wait('@Markets').then((response) => { cy.wait('@Markets').then((response) => {
@ -112,6 +110,24 @@ describe('Market trade', { tags: '@smoke' }, () => {
it('size slider should work well', () => { it('size slider should work well', () => {
if (markets?.length) { if (markets?.length) {
const marketId = markets[1].id;
cy.mockGQL((req) => {
aliasQuery(
req,
'Market',
generateMarket({
market: {
id: marketId,
tradableInstrument: {
instrument: {
product: { settlementAsset: { id: 'asset-id-2' } },
},
},
},
})
);
});
cy.visit(`/trading/${marketId}`);
cy.visit(`/trading/${markets[1].id}`); cy.visit(`/trading/${markets[1].id}`);
cy.connectVegaWallet(); cy.connectVegaWallet();
cy.get('#step-1-control [aria-label^="Selected value"]').click(); cy.get('#step-1-control [aria-label^="Selected value"]').click();
@ -134,7 +150,24 @@ describe('Market trade', { tags: '@smoke' }, () => {
it('percentage selection should work well', () => { it('percentage selection should work well', () => {
if (markets?.length) { if (markets?.length) {
cy.visit(`/trading/${markets[1].id}`); const marketId = markets[1].id;
cy.mockGQL((req) => {
aliasQuery(
req,
'Market',
generateMarket({
market: {
id: marketId,
tradableInstrument: {
instrument: {
product: { settlementAsset: { id: 'asset-id-2' } },
},
},
},
})
);
});
cy.visit(`/trading/${marketId}`);
cy.connectVegaWallet(); cy.connectVegaWallet();
cy.get('#step-1-control [aria-label^="Selected value"]').click(); cy.get('#step-1-control [aria-label^="Selected value"]').click();
cy.get('button[aria-label="Open short position"]').click(); cy.get('button[aria-label="Open short position"]').click();
@ -145,7 +178,7 @@ describe('Market trade', { tags: '@smoke' }, () => {
.find('button') .find('button')
.should('have.text', '1'); .should('have.text', '1');
cy.getByTestId('max-label').should('have.text', '21'); cy.getByTestId('max-label').should('have.text', '11');
cy.getByTestId('percentage-selector') cy.getByTestId('percentage-selector')
.find('button') .find('button')
@ -155,7 +188,7 @@ describe('Market trade', { tags: '@smoke' }, () => {
.find('dd') .find('dd')
.eq(0) .eq(0)
.find('button') .find('button')
.should('have.text', '21'); .should('have.text', '11');
} }
}); });
@ -189,7 +222,24 @@ describe('Market trade', { tags: '@smoke' }, () => {
it('slippage value should be displayed', () => { it('slippage value should be displayed', () => {
if (markets?.length) { if (markets?.length) {
cy.visit(`/trading/${markets[1].id}`); const marketId = markets[1].id;
cy.mockGQL((req) => {
aliasQuery(
req,
'Market',
generateMarket({
market: {
id: marketId,
tradableInstrument: {
instrument: {
product: { settlementAsset: { id: 'asset-id-2' } },
},
},
},
})
);
});
cy.visit(`/trading/${marketId}`);
cy.connectVegaWallet(); cy.connectVegaWallet();
cy.get('#step-1-control [aria-label^="Selected value"]').click(); cy.get('#step-1-control [aria-label^="Selected value"]').click();
cy.get('button[aria-label="Open short position"]').click(); cy.get('button[aria-label="Open short position"]').click();
@ -205,7 +255,24 @@ describe('Market trade', { tags: '@smoke' }, () => {
it('allow slippage value to be adjusted', () => { it('allow slippage value to be adjusted', () => {
if (markets?.length) { if (markets?.length) {
cy.visit(`/trading/${markets[1].id}`); const marketId = markets[1].id;
cy.mockGQL((req) => {
aliasQuery(
req,
'Market',
generateMarket({
market: {
id: marketId,
tradableInstrument: {
instrument: {
product: { settlementAsset: { id: 'asset-id-2' } },
},
},
},
})
);
});
cy.visit(`/trading/${marketId}`);
cy.connectVegaWallet(); cy.connectVegaWallet();
cy.get('#step-1-control [aria-label^="Selected value"]').click(); cy.get('#step-1-control [aria-label^="Selected value"]').click();
cy.get('button[aria-label="Open short position"]').click(); cy.get('button[aria-label="Open short position"]').click();

View File

@ -108,7 +108,7 @@ describe('Portfolio page tabs', { tags: '@smoke' }, () => {
}); });
it('data should be properly rendered', () => { it('data should be properly rendered', () => {
cy.get('.ag-center-cols-container .ag-row').should('have.length', 2); cy.get('.ag-center-cols-container .ag-row').should('have.length', 1);
}); });
}); });

View File

@ -74,6 +74,21 @@ export const generateAccounts = (
}, },
}, },
}, },
{
__typename: 'AccountEdge',
node: {
type: Types.AccountType.ACCOUNT_TYPE_MARGIN,
asset: {
__typename: 'Asset',
id: 'asset-id-2',
},
balance: '265329',
market: {
id: '57fbaa322e97cfc8bb5f1de048c37e033c41b1ac1906d3aed9960912a067ef5a',
__typename: 'Market',
},
},
},
{ {
__typename: 'AccountEdge', __typename: 'AccountEdge',
node: { node: {

View File

@ -110,91 +110,91 @@ export const generateMarketDepth = (
], ],
buy: [ buy: [
{ {
price: '9893005', price: '9891005',
volume: '4', volume: '4',
numberOfOrders: '3', numberOfOrders: '3',
__typename: 'PriceLevel', __typename: 'PriceLevel',
}, },
{ {
price: '9893003', price: '9890003',
volume: '2', volume: '2',
numberOfOrders: '1', numberOfOrders: '1',
__typename: 'PriceLevel', __typename: 'PriceLevel',
}, },
{ {
price: '9893001', price: '9889001',
volume: '1', volume: '1',
numberOfOrders: '1', numberOfOrders: '1',
__typename: 'PriceLevel', __typename: 'PriceLevel',
}, },
{ {
price: '9892006', price: '9888006',
volume: '3', volume: '3',
numberOfOrders: '2', numberOfOrders: '2',
__typename: 'PriceLevel', __typename: 'PriceLevel',
}, },
{ {
price: '9891006', price: '9887006',
volume: '2', volume: '2',
numberOfOrders: '1', numberOfOrders: '1',
__typename: 'PriceLevel', __typename: 'PriceLevel',
}, },
{ {
price: '9891001', price: '9886001',
volume: '1', volume: '1',
numberOfOrders: '1', numberOfOrders: '1',
__typename: 'PriceLevel', __typename: 'PriceLevel',
}, },
{ {
price: '9890101', price: '9885101',
volume: '2', volume: '2',
numberOfOrders: '1', numberOfOrders: '1',
__typename: 'PriceLevel', __typename: 'PriceLevel',
}, },
{ {
price: '9890091', price: '9884091',
volume: '5', volume: '5',
numberOfOrders: '1', numberOfOrders: '1',
__typename: 'PriceLevel', __typename: 'PriceLevel',
}, },
{ {
price: '9890081', price: '9883081',
volume: '4', volume: '4',
numberOfOrders: '1', numberOfOrders: '1',
__typename: 'PriceLevel', __typename: 'PriceLevel',
}, },
{ {
price: '9890050', price: '9882050',
volume: '2', volume: '2',
numberOfOrders: '1', numberOfOrders: '1',
__typename: 'PriceLevel', __typename: 'PriceLevel',
}, },
{ {
price: '9890040', price: '9881040',
volume: '6', volume: '6',
numberOfOrders: '3', numberOfOrders: '3',
__typename: 'PriceLevel', __typename: 'PriceLevel',
}, },
{ {
price: '9890030', price: '9880030',
volume: '6', volume: '6',
numberOfOrders: '2', numberOfOrders: '2',
__typename: 'PriceLevel', __typename: 'PriceLevel',
}, },
{ {
price: '9890021', price: '9879021',
volume: '3', volume: '3',
numberOfOrders: '1', numberOfOrders: '1',
__typename: 'PriceLevel', __typename: 'PriceLevel',
}, },
{ {
price: '9890011', price: '9878011',
volume: '1', volume: '1',
numberOfOrders: '1', numberOfOrders: '1',
__typename: 'PriceLevel', __typename: 'PriceLevel',
}, },
{ {
price: '9890001', price: '9877001',
volume: '11', volume: '11',
numberOfOrders: '1', numberOfOrders: '1',
__typename: 'PriceLevel', __typename: 'PriceLevel',

View File

@ -1,9 +0,0 @@
export const generateMarketMarkPrice = () => {
return {
market: {
decimalPlaces: 5,
data: { markPrice: '692748', __typename: 'MarketData' },
__typename: 'Market',
},
};
};

View File

@ -1,72 +0,0 @@
import type { MarketPositionsQuery } from '@vegaprotocol/deal-ticket';
import * as Schema from '@vegaprotocol/types';
export const generateMarketPositions = (): MarketPositionsQuery => {
return {
party: {
id: '2e1ef32e5804e14232406aebaad719087d326afa5c648b7824d0823d8a46c8d1',
accountsConnection: {
__typename: 'AccountsConnection',
edges: [
{
__typename: 'AccountEdge',
node: {
__typename: 'AccountBalance',
type: Schema.AccountType.ACCOUNT_TYPE_GENERAL,
asset: {
decimals: 5,
},
balance: '400000000000000000000',
market: {
id: '2751c508f9759761f912890f37fb3f97a00300bf7685c02a56a86e05facfe221',
__typename: 'Market',
},
},
},
{
__typename: 'AccountEdge',
node: {
type: Schema.AccountType.ACCOUNT_TYPE_MARGIN,
asset: {
decimals: 5,
},
balance: '265329',
market: {
id: 'ca7768f6de84bf86a21bbb6b0109d9659c81917b0e0339b2c262566c9b581a15',
__typename: 'Market',
},
},
},
],
},
positionsConnection: {
edges: [
{
node: {
openVolume: '3',
market: {
id: '2751c508f9759761f912890f37fb3f97a00300bf7685c02a56a86e05facfe221',
__typename: 'Market',
},
__typename: 'Position',
},
__typename: 'PositionEdge',
},
{
node: {
openVolume: '12',
market: {
id: 'ca7768f6de84bf86a21bbb6b0109d9659c81917b0e0339b2c262566c9b581a15',
__typename: 'Market',
},
__typename: 'Position',
},
__typename: 'PositionEdge',
},
],
__typename: 'PositionConnection',
},
__typename: 'Party',
},
};
};

View File

@ -1392,12 +1392,15 @@ export const generatePositionsMarkets = () => {
}; };
}; };
export const generateMarket = (): MarketQuery => { export const generateMarket = (
return { override?: PartialDeep<MarketQuery>
): MarketQuery => {
const defaultResult = {
market: { market: {
...singleMarket, ...singleMarket,
}, },
}; };
return merge(defaultResult, override);
}; };
export const generateMarketData = (): MarketDataQuery => { export const generateMarketData = (): MarketDataQuery => {

View File

@ -1,81 +0,0 @@
import merge from 'lodash/merge';
import type { PartyBalanceQuery } from '@vegaprotocol/deal-ticket';
import type { PartialDeep } from 'type-fest';
import * as Types from '@vegaprotocol/types';
export const generatePartyBalance = (
override?: PartialDeep<PartyBalanceQuery>
): PartyBalanceQuery => {
const defaultResult: PartyBalanceQuery = {
party: {
accountsConnection: {
__typename: 'AccountsConnection',
edges: [
{
__typename: 'AccountEdge',
node: {
balance: '88474051',
type: Types.AccountType.ACCOUNT_TYPE_GENERAL,
asset: {
id: 'dai-id',
symbol: 'tDAI',
name: 'tDAI TEST',
decimals: 5,
__typename: 'Asset',
},
__typename: 'AccountBalance',
},
},
{
__typename: 'AccountEdge',
node: {
balance: '100000000',
type: Types.AccountType.ACCOUNT_TYPE_GENERAL,
asset: {
id: '8b52d4a3a4b0ffe733cddbc2b67be273816cfeb6ca4c8b339bac03ffba08e4e4',
symbol: 'tEURO',
name: 'tEURO TEST',
decimals: 5,
__typename: 'Asset',
},
__typename: 'AccountBalance',
},
},
{
__typename: 'AccountEdge',
node: {
balance: '3412867',
type: Types.AccountType.ACCOUNT_TYPE_GENERAL,
asset: {
id: 'dai-id',
symbol: 'tDAI',
name: 'tDAI TEST',
decimals: 5,
__typename: 'Asset',
},
__typename: 'AccountBalance',
},
},
{
__typename: 'AccountEdge',
node: {
balance: '70007',
type: Types.AccountType.ACCOUNT_TYPE_GENERAL,
asset: {
id: 'dai-id',
symbol: 'tDAI',
name: 'tDAI TEST',
decimals: 5,
__typename: 'Asset',
},
__typename: 'AccountBalance',
},
},
],
},
__typename: 'Party',
},
};
return merge(defaultResult, override);
};

View File

@ -1,40 +0,0 @@
import type { PartyMarketDataQuery } from '@vegaprotocol/deal-ticket';
import * as Types from '@vegaprotocol/types';
export const generatePartyMarketData = (): PartyMarketDataQuery => {
return {
party: {
id: '2e1ef32e5804e14232406aebaad719087d326afa5c648b7824d0823d8a46c8d1',
accountsConnection: {
__typename: 'AccountsConnection',
edges: [
{
__typename: 'AccountEdge',
node: {
type: Types.AccountType.ACCOUNT_TYPE_GENERAL,
balance: '1200000',
asset: { id: 'fBTC', decimals: 5, __typename: 'Asset' },
market: null,
__typename: 'AccountBalance',
},
},
{
__typename: 'AccountEdge',
node: {
__typename: 'AccountBalance',
type: Types.AccountType.ACCOUNT_TYPE_GENERAL,
balance: '0.000000001',
asset: {
__typename: 'Asset',
id: '5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c',
decimals: 0,
},
},
},
],
},
marginsConnection: { edges: null, __typename: 'MarginConnection' },
__typename: 'Party',
},
};
};

View File

@ -41,7 +41,7 @@ export const generatePositions = (
averageEntryPrice: '84400088', averageEntryPrice: '84400088',
updatedAt: '2022-07-28T14:53:54.725477Z', updatedAt: '2022-07-28T14:53:54.725477Z',
market: { market: {
id: '5a4b0b9e9c0629f0315ec56fcb7bd444b0c6e4da5ec7677719d502626658a376', id: '57fbaa322e97cfc8bb5f1de048c37e033c41b1ac1906d3aed9960912a067ef5a',
__typename: 'Market', __typename: 'Market',
}, },
__typename: 'Position', __typename: 'Position',

View File

@ -1,18 +0,0 @@
query PartyBalanceQuery($partyId: ID!) {
party(id: $partyId) {
accountsConnection {
edges {
node {
type
balance
asset {
id
symbol
name
decimals
}
}
}
}
}
}

View File

@ -1,61 +0,0 @@
import * as Types from '@vegaprotocol/types';
import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
export type PartyBalanceQueryQueryVariables = Types.Exact<{
partyId: Types.Scalars['ID'];
}>;
export type PartyBalanceQueryQuery = { __typename?: 'Query', party?: { __typename?: 'Party', accountsConnection?: { __typename?: 'AccountsConnection', edges?: Array<{ __typename?: 'AccountEdge', node: { __typename?: 'AccountBalance', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number } } } | null> | null } | null } | null };
export const PartyBalanceQueryDocument = gql`
query PartyBalanceQuery($partyId: ID!) {
party(id: $partyId) {
accountsConnection {
edges {
node {
type
balance
asset {
id
symbol
name
decimals
}
}
}
}
}
}
`;
/**
* __usePartyBalanceQueryQuery__
*
* To run a query within a React component, call `usePartyBalanceQueryQuery` and pass it any options that fit your needs.
* When your component renders, `usePartyBalanceQueryQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = usePartyBalanceQueryQuery({
* variables: {
* partyId: // value for 'partyId'
* },
* });
*/
export function usePartyBalanceQueryQuery(baseOptions: Apollo.QueryHookOptions<PartyBalanceQueryQuery, PartyBalanceQueryQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<PartyBalanceQueryQuery, PartyBalanceQueryQueryVariables>(PartyBalanceQueryDocument, options);
}
export function usePartyBalanceQueryLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<PartyBalanceQueryQuery, PartyBalanceQueryQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<PartyBalanceQueryQuery, PartyBalanceQueryQueryVariables>(PartyBalanceQueryDocument, options);
}
export type PartyBalanceQueryQueryHookResult = ReturnType<typeof usePartyBalanceQueryQuery>;
export type PartyBalanceQueryLazyQueryHookResult = ReturnType<typeof usePartyBalanceQueryLazyQuery>;
export type PartyBalanceQueryQueryResult = Apollo.QueryResult<PartyBalanceQueryQuery, PartyBalanceQueryQueryVariables>;

View File

@ -1,9 +1,13 @@
import React from 'react'; import React from 'react';
import { render } from '@testing-library/react'; import { render } from '@testing-library/react';
import type { AccountFragment } from '@vegaprotocol/deal-ticket'; import { MockedProvider } from '@apollo/client/testing';
import { DealTicketBalance } from './deal-ticket-balance';
import * as Schema from '@vegaprotocol/types';
import type { MarketDealTicketAsset } from '@vegaprotocol/market-list'; import type { MarketDealTicketAsset } from '@vegaprotocol/market-list';
import { DealTicketBalance } from './deal-ticket-balance';
jest.mock('@vegaprotocol/wallet', () => ({
...jest.requireActual('@vegaprotocol/wallet'),
useVegaWallet: jest.fn().mockReturnValue('wallet-pub-key'),
}));
const tDAI: MarketDealTicketAsset = { const tDAI: MarketDealTicketAsset = {
__typename: 'Asset', __typename: 'Asset',
@ -13,23 +17,20 @@ const tDAI: MarketDealTicketAsset = {
decimals: 2, decimals: 2,
}; };
const accounts: AccountFragment[] = [ let mockAccountBalance: {
{ accountBalance: string;
__typename: 'AccountBalance', accountDecimals: number | null;
type: Schema.AccountType.ACCOUNT_TYPE_GENERAL, } = { accountBalance: '1000000', accountDecimals: 2 };
balance: '1000000', jest.mock('@vegaprotocol/accounts', () => ({
asset: tDAI, ...jest.requireActual('@vegaprotocol/accounts'),
}, useAccountBalance: jest.fn(() => mockAccountBalance),
]; }));
describe('DealTicketBalance', function () { describe('DealTicketBalance', function () {
it('should render the balance', () => { it('should render the balance', () => {
const { getByText, getByRole } = render( const { getByText, getByRole } = render(
<DealTicketBalance <DealTicketBalance settlementAsset={tDAI} isWalletConnected />,
settlementAsset={tDAI} { wrapper: MockedProvider }
accounts={accounts}
isWalletConnected
/>
); );
expect(getByRole('complementary')).toHaveAccessibleName('tDAI Balance'); expect(getByRole('complementary')).toHaveAccessibleName('tDAI Balance');
@ -39,11 +40,8 @@ describe('DealTicketBalance', function () {
it('should prompt to connect wallet', () => { it('should prompt to connect wallet', () => {
const { getByText } = render( const { getByText } = render(
<DealTicketBalance <DealTicketBalance settlementAsset={tDAI} isWalletConnected={false} />,
settlementAsset={tDAI} { wrapper: MockedProvider }
accounts={accounts}
isWalletConnected={false}
/>
); );
expect( expect(
@ -52,12 +50,10 @@ describe('DealTicketBalance', function () {
}); });
it('should display zero balance', () => { it('should display zero balance', () => {
mockAccountBalance = { accountBalance: '', accountDecimals: null };
const { getByText } = render( const { getByText } = render(
<DealTicketBalance <DealTicketBalance settlementAsset={tDAI} isWalletConnected={true} />,
settlementAsset={tDAI} { wrapper: MockedProvider }
accounts={[]}
isWalletConnected={true}
/>
); );
expect(getByText('No tDAI left to trade')).toBeInTheDocument(); expect(getByText('No tDAI left to trade')).toBeInTheDocument();

View File

@ -1,41 +1,38 @@
import classNames from 'classnames'; import classNames from 'classnames';
import { addDecimalsFormatNumber, t } from '@vegaprotocol/react-helpers'; import {
import * as Schema from '@vegaprotocol/types'; addDecimalsFormatNumber,
import type { AccountFragment } from '@vegaprotocol/deal-ticket'; t,
toBigNum,
} from '@vegaprotocol/react-helpers';
import type { MarketDealTicket } from '@vegaprotocol/market-list'; import type { MarketDealTicket } from '@vegaprotocol/market-list';
import { useSettlementAccount } from '@vegaprotocol/deal-ticket'; import { useAccountBalance } from '@vegaprotocol/accounts';
interface DealTicketBalanceProps { interface DealTicketBalanceProps {
settlementAsset: MarketDealTicket['tradableInstrument']['instrument']['product']['settlementAsset']; settlementAsset: MarketDealTicket['tradableInstrument']['instrument']['product']['settlementAsset'];
accounts: AccountFragment[];
isWalletConnected: boolean; isWalletConnected: boolean;
className?: string; className?: string;
} }
export const DealTicketBalance = ({ export const DealTicketBalance = ({
settlementAsset, settlementAsset,
accounts,
isWalletConnected, isWalletConnected,
className = '', className = '',
}: DealTicketBalanceProps) => { }: DealTicketBalanceProps) => {
const settlementAssetId = settlementAsset?.id; const settlementAssetId = settlementAsset?.id;
const settlementAssetSymbol = settlementAsset?.symbol; const settlementAssetSymbol = settlementAsset?.symbol;
const settlementAccount = useSettlementAccount(
settlementAssetId, const { accountBalance, accountDecimals } =
accounts, useAccountBalance(settlementAssetId) || {};
Schema.AccountType.ACCOUNT_TYPE_GENERAL const settlementBalance = toBigNum(accountBalance || 0, accountDecimals || 0);
);
const formattedNumber = const formattedNumber =
settlementAccount?.balance && accountBalance &&
settlementAccount.asset.decimals && accountDecimals &&
addDecimalsFormatNumber( addDecimalsFormatNumber(accountBalance, accountDecimals);
settlementAccount.balance,
settlementAccount.asset.decimals
);
const balance = ( const balance = (
<p className="text-blue text-lg font-semibold"> <p className="text-blue text-lg font-semibold">
{settlementAccount {!settlementBalance.isZero()
? t(`${formattedNumber}`) ? t(`${formattedNumber}`)
: `No ${settlementAssetSymbol} left to trade`} : `No ${settlementAssetSymbol} left to trade`}
</p> </p>

View File

@ -1,14 +1,7 @@
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import { import { DealTicketManager } from '@vegaprotocol/deal-ticket';
DealTicketManager,
usePartyBalanceQuery,
} from '@vegaprotocol/deal-ticket';
import { Loader, Splash } from '@vegaprotocol/ui-toolkit'; import { Loader, Splash } from '@vegaprotocol/ui-toolkit';
import { import { t, useDataProvider } from '@vegaprotocol/react-helpers';
t,
useDataProvider,
removePaginationWrapper,
} from '@vegaprotocol/react-helpers';
import { useVegaWallet } from '@vegaprotocol/wallet'; import { useVegaWallet } from '@vegaprotocol/wallet';
import { DealTicketSteps } from './deal-ticket-steps'; import { DealTicketSteps } from './deal-ticket-steps';
import { DealTicketBalance } from './deal-ticket-balance'; import { DealTicketBalance } from './deal-ticket-balance';
@ -29,11 +22,6 @@ export const DealTicketContainer = () => {
const { marketId } = useParams<{ marketId: string }>(); const { marketId } = useParams<{ marketId: string }>();
const { pubKey } = useVegaWallet(); const { pubKey } = useVegaWallet();
const { data: partyData } = usePartyBalanceQuery({
variables: { partyId: pubKey || '' },
skip: !pubKey,
});
const variables = useMemo( const variables = useMemo(
() => ({ () => ({
marketId: marketId || '', marketId: marketId || '',
@ -49,10 +37,6 @@ export const DealTicketContainer = () => {
skip: !marketId, skip: !marketId,
}); });
const accounts = removePaginationWrapper(
partyData?.party?.accountsConnection?.edges
);
const loader = <Loader />; const loader = <Loader />;
if (marketId && data) { if (marketId && data) {
const balance = ( const balance = (
@ -61,7 +45,6 @@ export const DealTicketContainer = () => {
settlementAsset={ settlementAsset={
data.tradableInstrument.instrument.product?.settlementAsset data.tradableInstrument.instrument.product?.settlementAsset
} }
accounts={accounts || []}
isWalletConnected={!!pubKey} isWalletConnected={!!pubKey}
/> />
); );

View File

@ -6,7 +6,6 @@ import {
getDefaultOrder, getDefaultOrder,
useOrderCloseOut, useOrderCloseOut,
useOrderMargin, useOrderMargin,
usePartyBalanceQuery,
useMaximumPositionSize, useMaximumPositionSize,
useCalculateSlippage, useCalculateSlippage,
validateAmount, validateAmount,
@ -24,7 +23,6 @@ import {
addDecimalsFormatNumber, addDecimalsFormatNumber,
addDecimal, addDecimal,
formatNumber, formatNumber,
removePaginationWrapper,
} from '@vegaprotocol/react-helpers'; } from '@vegaprotocol/react-helpers';
import { import {
useOrderSubmit, useOrderSubmit,
@ -77,17 +75,7 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
}); });
const { submit, transaction, finalizedOrder, Dialog } = useOrderSubmit(); const { submit, transaction, finalizedOrder, Dialog } = useOrderSubmit();
const { data: partyBalance } = usePartyBalanceQuery({
variables: { partyId: pubKey || '' },
skip: !pubKey,
});
const accounts = removePaginationWrapper(
partyBalance?.party?.accountsConnection?.edges
);
const maxTrade = useMaximumPositionSize({ const maxTrade = useMaximumPositionSize({
partyId: pubKey || '',
accounts: accounts,
marketId: market.id, marketId: market.id,
settlementAssetId: settlementAssetId:
market.tradableInstrument.instrument.product.settlementAsset.id, market.tradableInstrument.instrument.product.settlementAsset.id,
@ -98,7 +86,6 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
const estCloseOut = useOrderCloseOut({ const estCloseOut = useOrderCloseOut({
order, order,
market, market,
partyData: partyBalance,
}); });
const slippage = useCalculateSlippage({ marketId: market.id, order }); const slippage = useCalculateSlippage({ marketId: market.id, order });
const [slippageValue, setSlippageValue] = useState( const [slippageValue, setSlippageValue] = useState(

View File

@ -697,7 +697,7 @@ describe('account validation', { tags: '@regression' }, () => {
); );
cy.getByTestId('dealticket-warning-margin').should( cy.getByTestId('dealticket-warning-margin').should(
'contain.text', 'contain.text',
'10,000.00 tBTC currently required, 1,000.00 tBTC available' '9,999.99 tBTC currently required, 1,000.00 tBTC available'
); );
cy.getByTestId('deal-ticket-deposit-dialog-button').click(); cy.getByTestId('deal-ticket-deposit-dialog-button').click();
cy.getByTestId('dialog-content') cy.getByTestId('dialog-content')

View File

@ -1,12 +1,6 @@
import type { PartialDeep } from 'type-fest'; import type { PartialDeep } from 'type-fest';
import merge from 'lodash/merge'; import merge from 'lodash/merge';
import * as Types from '@vegaprotocol/types'; import type { EstimateOrderQuery } from '@vegaprotocol/deal-ticket';
import type {
EstimateOrderQuery,
MarketMarkPriceQuery,
PartyBalanceQuery,
PartyMarketDataQuery,
} from '@vegaprotocol/deal-ticket';
const estimateOrderMock: EstimateOrderQuery = { const estimateOrderMock: EstimateOrderQuery = {
estimateOrder: { estimateOrder: {
@ -27,87 +21,3 @@ export const generateEstimateOrder = (
) => { ) => {
return merge(estimateOrderMock, override); return merge(estimateOrderMock, override);
}; };
const marketMarkPriceMock: MarketMarkPriceQuery = {
market: {
__typename: 'Market',
decimalPlaces: 5,
data: {
__typename: 'MarketData',
markPrice: '100',
market: { __typename: 'Market', id: 'market-0' },
},
},
};
export const generateMarkPrice = () => {
return marketMarkPriceMock;
};
const partyBalanceMock: PartyBalanceQuery = {
party: {
__typename: 'Party',
accountsConnection: {
__typename: 'AccountsConnection',
edges: [
{
__typename: 'AccountEdge',
node: {
__typename: 'AccountBalance',
type: Types.AccountType.ACCOUNT_TYPE_GENERAL,
balance: '100',
asset: {
__typename: 'Asset',
id: '5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c',
symbol: 'tBTC',
name: 'BTC',
decimals: 5,
},
},
},
],
},
},
};
export const generatePartyBalance = () => {
return partyBalanceMock;
};
export const generatePartyMarketData = (): PartyMarketDataQuery => {
return {
party: {
id: Cypress.env('VEGA_PUBLIC_KEY'),
accountsConnection: {
__typename: 'AccountsConnection',
edges: [
{
__typename: 'AccountEdge',
node: {
type: Types.AccountType.ACCOUNT_TYPE_GENERAL,
balance: '1200000',
asset: { id: 'fBTC', decimals: 5, __typename: 'Asset' },
market: null,
__typename: 'AccountBalance',
},
},
{
__typename: 'AccountEdge',
node: {
__typename: 'AccountBalance',
type: Types.AccountType.ACCOUNT_TYPE_GENERAL,
balance: '100',
asset: {
__typename: 'Asset',
id: '5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c',
decimals: 5,
},
},
},
],
},
marginsConnection: { edges: null, __typename: 'MarginConnection' },
__typename: 'Party',
},
};
};

View File

@ -18,12 +18,7 @@ import { generateOrders } from './mocks/generate-orders';
import { generateMargins, generatePositions } from './mocks/generate-positions'; import { generateMargins, generatePositions } from './mocks/generate-positions';
import { generateTrades } from './mocks/generate-trades'; import { generateTrades } from './mocks/generate-trades';
import { generateWithdrawals } from './mocks/generate-withdrawals'; import { generateWithdrawals } from './mocks/generate-withdrawals';
import { import { generateEstimateOrder } from './mocks/generate-fees';
generateEstimateOrder,
generateMarkPrice,
generatePartyBalance,
generatePartyMarketData,
} from './mocks/generate-fees';
import { generateMarketProposals } from './mocks/generate-proposals'; import { generateMarketProposals } from './mocks/generate-proposals';
import { generateStatistics } from './mocks/generate-statistics'; import { generateStatistics } from './mocks/generate-statistics';
import { generateChainId } from './mocks/generate-chain-id'; import { generateChainId } from './mocks/generate-chain-id';
@ -94,10 +89,7 @@ const mockTradingPage = (
aliasQuery(req, 'Withdrawals', generateWithdrawals()); aliasQuery(req, 'Withdrawals', generateWithdrawals());
aliasQuery(req, 'NetworkParams', generateNetworkParameters()); aliasQuery(req, 'NetworkParams', generateNetworkParameters());
aliasQuery(req, 'EstimateOrder', generateEstimateOrder()); aliasQuery(req, 'EstimateOrder', generateEstimateOrder());
aliasQuery(req, 'MarketMarkPrice', generateMarkPrice());
aliasQuery(req, 'PartyBalance', generatePartyBalance());
aliasQuery(req, 'MarketPositions', generatePositions()); aliasQuery(req, 'MarketPositions', generatePositions());
aliasQuery(req, 'PartyMarketData', generatePartyMarketData());
aliasQuery(req, 'ProposalsList', generateMarketProposals()); aliasQuery(req, 'ProposalsList', generateMarketProposals());
aliasQuery(req, 'Deposits', generateDeposits()); aliasQuery(req, 'Deposits', generateDeposits());
}; };

View File

@ -0,0 +1,15 @@
import type { Account } from './accounts-data-provider';
import * as Schema from '@vegaprotocol/types';
interface Props {
accounts: Account[] | null;
marketId: string;
}
export const getMarketAccount = ({ accounts, marketId }: Props) =>
accounts?.find((account) => {
return (
account.market?.id === marketId &&
account.type === Schema.AccountType.ACCOUNT_TYPE_MARGIN
);
}) || null;

View File

@ -6,3 +6,4 @@ export * from './accounts-manager';
export * from './breakdown-table'; export * from './breakdown-table';
export * from './use-account-balance'; export * from './use-account-balance';
export * from './get-settlement-account'; export * from './get-settlement-account';
export * from './use-market-account-balance';

View File

@ -0,0 +1,43 @@
import { useCallback, useMemo, useState } from 'react';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { useDataProvider } from '@vegaprotocol/react-helpers';
import { accountsDataProvider } from './accounts-data-provider';
import type { Account } from './accounts-data-provider';
import { getMarketAccount } from './get-market-account';
export const useMarketAccountBalance = (marketId: string) => {
const { pubKey } = useVegaWallet();
const [accountBalance, setAccountBalance] = useState<string>('');
const [accountDecimals, setAccountDecimals] = useState<number | null>(null);
const variables = useMemo(() => {
return { partyId: pubKey || '' };
}, [pubKey]);
const update = useCallback(
({ data }: { data: Account[] | null }) => {
const account = getMarketAccount({ accounts: data, marketId });
if (accountBalance !== account?.balance) {
setAccountBalance(account?.balance || '');
}
if (accountDecimals !== account?.asset.decimals) {
setAccountDecimals(account?.asset.decimals || null);
}
return true;
},
[accountBalance, accountDecimals, marketId]
);
useDataProvider({
dataProvider: accountsDataProvider,
variables,
skip: !pubKey || !marketId,
update,
});
return useMemo(
() => ({
accountBalance,
accountDecimals,
}),
[accountBalance, accountDecimals]
);
};

View File

@ -1,11 +0,0 @@
query MarketMarkPrice($marketId: ID!) {
market(id: $marketId) {
decimalPlaces
data {
markPrice
market {
id
}
}
}
}

View File

@ -1,29 +0,0 @@
query MarketPositions($partyId: ID!) {
party(id: $partyId) {
id
accountsConnection {
edges {
node {
type
balance
asset {
decimals
}
market {
id
}
}
}
}
positionsConnection {
edges {
node {
openVolume
market {
id
}
}
}
}
}
}

View File

@ -1,22 +0,0 @@
query PartyBalance($partyId: ID!) {
party(id: $partyId) {
accountsConnection {
edges {
node {
...Account
}
}
}
}
}
fragment Account on AccountBalance {
type
balance
asset {
id
symbol
name
decimals
}
}

View File

@ -1,32 +0,0 @@
query PartyMarketData($partyId: ID!) {
party(id: $partyId) {
id
accountsConnection {
edges {
node {
type
balance
asset {
id
decimals
}
market {
id
}
}
}
}
marginsConnection {
edges {
node {
market {
id
}
initialLevel
maintenanceLevel
searchLevel
}
}
}
}
}

View File

@ -1,54 +0,0 @@
import * as Types from '@vegaprotocol/types';
import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
export type MarketMarkPriceQueryVariables = Types.Exact<{
marketId: Types.Scalars['ID'];
}>;
export type MarketMarkPriceQuery = { __typename?: 'Query', market?: { __typename?: 'Market', decimalPlaces: number, data?: { __typename?: 'MarketData', markPrice: string, market: { __typename?: 'Market', id: string } } | null } | null };
export const MarketMarkPriceDocument = gql`
query MarketMarkPrice($marketId: ID!) {
market(id: $marketId) {
decimalPlaces
data {
markPrice
market {
id
}
}
}
}
`;
/**
* __useMarketMarkPriceQuery__
*
* To run a query within a React component, call `useMarketMarkPriceQuery` and pass it any options that fit your needs.
* When your component renders, `useMarketMarkPriceQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useMarketMarkPriceQuery({
* variables: {
* marketId: // value for 'marketId'
* },
* });
*/
export function useMarketMarkPriceQuery(baseOptions: Apollo.QueryHookOptions<MarketMarkPriceQuery, MarketMarkPriceQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<MarketMarkPriceQuery, MarketMarkPriceQueryVariables>(MarketMarkPriceDocument, options);
}
export function useMarketMarkPriceLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<MarketMarkPriceQuery, MarketMarkPriceQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<MarketMarkPriceQuery, MarketMarkPriceQueryVariables>(MarketMarkPriceDocument, options);
}
export type MarketMarkPriceQueryHookResult = ReturnType<typeof useMarketMarkPriceQuery>;
export type MarketMarkPriceLazyQueryHookResult = ReturnType<typeof useMarketMarkPriceLazyQuery>;
export type MarketMarkPriceQueryResult = Apollo.QueryResult<MarketMarkPriceQuery, MarketMarkPriceQueryVariables>;

View File

@ -1,72 +0,0 @@
import * as Types from '@vegaprotocol/types';
import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
export type MarketPositionsQueryVariables = Types.Exact<{
partyId: Types.Scalars['ID'];
}>;
export type MarketPositionsQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, accountsConnection?: { __typename?: 'AccountsConnection', edges?: Array<{ __typename?: 'AccountEdge', node: { __typename?: 'AccountBalance', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', decimals: number }, market?: { __typename?: 'Market', id: string } | null } } | null> | null } | null, positionsConnection?: { __typename?: 'PositionConnection', edges?: Array<{ __typename?: 'PositionEdge', node: { __typename?: 'Position', openVolume: string, market: { __typename?: 'Market', id: string } } }> | null } | null } | null };
export const MarketPositionsDocument = gql`
query MarketPositions($partyId: ID!) {
party(id: $partyId) {
id
accountsConnection {
edges {
node {
type
balance
asset {
decimals
}
market {
id
}
}
}
}
positionsConnection {
edges {
node {
openVolume
market {
id
}
}
}
}
}
}
`;
/**
* __useMarketPositionsQuery__
*
* To run a query within a React component, call `useMarketPositionsQuery` and pass it any options that fit your needs.
* When your component renders, `useMarketPositionsQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useMarketPositionsQuery({
* variables: {
* partyId: // value for 'partyId'
* },
* });
*/
export function useMarketPositionsQuery(baseOptions: Apollo.QueryHookOptions<MarketPositionsQuery, MarketPositionsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<MarketPositionsQuery, MarketPositionsQueryVariables>(MarketPositionsDocument, options);
}
export function useMarketPositionsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<MarketPositionsQuery, MarketPositionsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<MarketPositionsQuery, MarketPositionsQueryVariables>(MarketPositionsDocument, options);
}
export type MarketPositionsQueryHookResult = ReturnType<typeof useMarketPositionsQuery>;
export type MarketPositionsLazyQueryHookResult = ReturnType<typeof useMarketPositionsLazyQuery>;
export type MarketPositionsQueryResult = Apollo.QueryResult<MarketPositionsQuery, MarketPositionsQueryVariables>;

View File

@ -1,67 +0,0 @@
import * as Types from '@vegaprotocol/types';
import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
export type PartyBalanceQueryVariables = Types.Exact<{
partyId: Types.Scalars['ID'];
}>;
export type PartyBalanceQuery = { __typename?: 'Query', party?: { __typename?: 'Party', accountsConnection?: { __typename?: 'AccountsConnection', edges?: Array<{ __typename?: 'AccountEdge', node: { __typename?: 'AccountBalance', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number } } } | null> | null } | null } | null };
export type AccountFragment = { __typename?: 'AccountBalance', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number } };
export const AccountFragmentDoc = gql`
fragment Account on AccountBalance {
type
balance
asset {
id
symbol
name
decimals
}
}
`;
export const PartyBalanceDocument = gql`
query PartyBalance($partyId: ID!) {
party(id: $partyId) {
accountsConnection {
edges {
node {
...Account
}
}
}
}
}
${AccountFragmentDoc}`;
/**
* __usePartyBalanceQuery__
*
* To run a query within a React component, call `usePartyBalanceQuery` and pass it any options that fit your needs.
* When your component renders, `usePartyBalanceQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = usePartyBalanceQuery({
* variables: {
* partyId: // value for 'partyId'
* },
* });
*/
export function usePartyBalanceQuery(baseOptions: Apollo.QueryHookOptions<PartyBalanceQuery, PartyBalanceQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<PartyBalanceQuery, PartyBalanceQueryVariables>(PartyBalanceDocument, options);
}
export function usePartyBalanceLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<PartyBalanceQuery, PartyBalanceQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<PartyBalanceQuery, PartyBalanceQueryVariables>(PartyBalanceDocument, options);
}
export type PartyBalanceQueryHookResult = ReturnType<typeof usePartyBalanceQuery>;
export type PartyBalanceLazyQueryHookResult = ReturnType<typeof usePartyBalanceLazyQuery>;
export type PartyBalanceQueryResult = Apollo.QueryResult<PartyBalanceQuery, PartyBalanceQueryVariables>;

View File

@ -1,75 +0,0 @@
import * as Types from '@vegaprotocol/types';
import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
export type PartyMarketDataQueryVariables = Types.Exact<{
partyId: Types.Scalars['ID'];
}>;
export type PartyMarketDataQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, accountsConnection?: { __typename?: 'AccountsConnection', edges?: Array<{ __typename?: 'AccountEdge', node: { __typename?: 'AccountBalance', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', id: string, decimals: number }, market?: { __typename?: 'Market', id: string } | null } } | null> | null } | null, marginsConnection?: { __typename?: 'MarginConnection', edges?: Array<{ __typename?: 'MarginEdge', node: { __typename?: 'MarginLevels', initialLevel: string, maintenanceLevel: string, searchLevel: string, market: { __typename?: 'Market', id: string } } }> | null } | null } | null };
export const PartyMarketDataDocument = gql`
query PartyMarketData($partyId: ID!) {
party(id: $partyId) {
id
accountsConnection {
edges {
node {
type
balance
asset {
id
decimals
}
market {
id
}
}
}
}
marginsConnection {
edges {
node {
market {
id
}
initialLevel
maintenanceLevel
searchLevel
}
}
}
}
}
`;
/**
* __usePartyMarketDataQuery__
*
* To run a query within a React component, call `usePartyMarketDataQuery` and pass it any options that fit your needs.
* When your component renders, `usePartyMarketDataQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = usePartyMarketDataQuery({
* variables: {
* partyId: // value for 'partyId'
* },
* });
*/
export function usePartyMarketDataQuery(baseOptions: Apollo.QueryHookOptions<PartyMarketDataQuery, PartyMarketDataQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<PartyMarketDataQuery, PartyMarketDataQueryVariables>(PartyMarketDataDocument, options);
}
export function usePartyMarketDataLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<PartyMarketDataQuery, PartyMarketDataQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<PartyMarketDataQuery, PartyMarketDataQueryVariables>(PartyMarketDataDocument, options);
}
export type PartyMarketDataQueryHookResult = ReturnType<typeof usePartyMarketDataQuery>;
export type PartyMarketDataLazyQueryHookResult = ReturnType<typeof usePartyMarketDataLazyQuery>;
export type PartyMarketDataQueryResult = Apollo.QueryResult<PartyMarketDataQuery, PartyMarketDataQueryVariables>;

View File

@ -1,14 +1,8 @@
export * from './__generated__/EstimateOrder'; export * from './__generated__/EstimateOrder';
export * from './__generated__/MarketMarkPrice';
export * from './__generated__/MarketPositions';
export * from './__generated__/PartyBalance';
export * from './__generated__/PartyMarketData';
export * from './use-calculate-slippage'; export * from './use-calculate-slippage';
export * from './use-fee-deal-ticket-details'; export * from './use-fee-deal-ticket-details';
export * from './use-market-data-mark-price';
export * from './use-market-positions'; export * from './use-market-positions';
export * from './use-maximum-position-size'; export * from './use-maximum-position-size';
export * from './use-order-closeout'; export * from './use-order-closeout';
export * from './use-order-margin'; export * from './use-order-margin';
export * from './use-order-margin-validation'; export * from './use-order-margin-validation';
export * from './use-settlement-account';

View File

@ -16,7 +16,6 @@ import {
EST_MARGIN_TOOLTIP_TEXT, EST_MARGIN_TOOLTIP_TEXT,
NOTIONAL_SIZE_TOOLTIP_TEXT, NOTIONAL_SIZE_TOOLTIP_TEXT,
} from '../constants'; } from '../constants';
import { usePartyBalanceQuery } from './__generated__/PartyBalance';
import { useCalculateSlippage } from './use-calculate-slippage'; import { useCalculateSlippage } from './use-calculate-slippage';
import { useOrderCloseOut } from './use-order-closeout'; import { useOrderCloseOut } from './use-order-closeout';
import { useOrderMargin } from './use-order-margin'; import { useOrderMargin } from './use-order-margin';
@ -49,22 +48,16 @@ export const useFeeDealTicketDetails = (
return null; return null;
}, [derivedPrice, order.side, slippage]); }, [derivedPrice, order.side, slippage]);
const estMargin: OrderMargin | null = useOrderMargin({ const estMargin = useOrderMargin({
order, order,
market, market,
partyId: pubKey || '', partyId: pubKey || '',
derivedPrice, derivedPrice,
}); });
const { data: partyBalance } = usePartyBalanceQuery({
variables: { partyId: pubKey || '' },
skip: !pubKey,
});
const estCloseOut = useOrderCloseOut({ const estCloseOut = useOrderCloseOut({
order, order,
market, market,
partyData: partyBalance,
}); });
const notionalSize = useMemo(() => { const notionalSize = useMemo(() => {
@ -87,7 +80,6 @@ export const useFeeDealTicketDetails = (
estCloseOut, estCloseOut,
slippage, slippage,
slippageAdjustedPrice, slippageAdjustedPrice,
partyData: partyBalance,
}; };
}, [ }, [
market, market,
@ -97,7 +89,6 @@ export const useFeeDealTicketDetails = (
estCloseOut, estCloseOut,
slippage, slippage,
slippageAdjustedPrice, slippageAdjustedPrice,
partyBalance,
]); ]);
}; };

View File

@ -1,21 +0,0 @@
import { useMemo, useRef } from 'react';
import type { MarketMarkPriceQuery } from './__generated__/MarketMarkPrice';
import { useMarketMarkPriceQuery } from './__generated__/MarketMarkPrice';
export const useMarketDataMarkPrice = (marketId: string) => {
const memoRef = useRef<MarketMarkPriceQuery | null>(null);
const { data } = useMarketMarkPriceQuery({
pollInterval: 5000,
variables: { marketId },
skip: !marketId,
});
return useMemo(() => {
if (
data &&
data.market?.data?.markPrice !== memoRef.current?.market?.data?.markPrice
) {
memoRef.current = data;
}
return memoRef.current;
}, [data, memoRef]);
};

View File

@ -1,60 +1,23 @@
import { renderHook } from '@testing-library/react'; import { renderHook } from '@testing-library/react';
import { MockedProvider } from '@apollo/client/testing';
import { useMarketPositions } from './use-market-positions'; import { useMarketPositions } from './use-market-positions';
let mockNotEmptyData = { jest.mock('@vegaprotocol/wallet', () => ({
party: { ...jest.requireActual('@vegaprotocol/wallet'),
accountsConnection: { useVegaWallet: jest.fn().mockReturnValue('wallet-pub-key'),
edges: [ }));
{ let mockMarketAccountBalance: {
node: { accountBalance: string;
balance: '50001000000', accountDecimals: number | null;
asset: { } = { accountBalance: '50001000000', accountDecimals: 5 };
decimals: 5, jest.mock('@vegaprotocol/accounts', () => ({
}, ...jest.requireActual('@vegaprotocol/accounts'),
market: { useMarketAccountBalance: jest.fn(() => mockMarketAccountBalance),
id: 'marketId', }));
},
},
},
{
node: {
balance: '700000000000000000000000000000',
asset: {
decimals: 5,
},
market: {
id: 'someOtherMarketId',
},
},
},
],
},
positionsConnection: {
edges: [
{
node: {
openVolume: '100002',
market: {
id: 'marketId',
},
},
},
{
node: {
openVolume: '3',
market: {
id: 'someOtherMarketId',
},
},
},
],
},
},
};
jest.mock('@apollo/client', () => ({ jest.mock('@vegaprotocol/positions', () => ({
...jest.requireActual('@apollo/client'), ...jest.requireActual('@vegaprotocol/positions'),
useQuery: jest.fn(() => ({ data: mockNotEmptyData })), useMarketPositionOpenVolume: jest.fn(() => '100002'),
})); }));
describe('useOrderPosition Hook', () => { describe('useOrderPosition Hook', () => {
@ -62,85 +25,28 @@ describe('useOrderPosition Hook', () => {
jest.clearAllMocks(); jest.clearAllMocks();
}); });
it('should return proper positive value', () => { it('should return proper positive value', () => {
const { result } = renderHook(() => const { result } = renderHook(
useMarketPositions({ marketId: 'marketId', partyId: 'partyId' }) () => useMarketPositions({ marketId: 'marketId' }),
{ wrapper: MockedProvider }
); );
expect(result.current?.openVolume.toNumber()).toEqual(100002); expect(result.current?.openVolume).toEqual('100002');
expect(result.current?.balance.toString()).toEqual('50001000000'); expect(result.current?.balance).toEqual('50001000000');
}); });
it('if balance equal 0 return null', () => { it('if balance equal 0 return null', () => {
mockNotEmptyData = { mockMarketAccountBalance = { accountBalance: '0', accountDecimals: 5 };
party: { const { result } = renderHook(
accountsConnection: { () => useMarketPositions({ marketId: 'marketId' }),
edges: [ { wrapper: MockedProvider }
{
node: {
balance: '0',
asset: {
decimals: 5,
},
market: {
id: 'marketId',
},
},
},
],
},
positionsConnection: {
edges: [
{
node: {
openVolume: '2',
market: {
id: 'marketId',
},
},
},
],
},
},
};
const { result } = renderHook(() =>
useMarketPositions({ marketId: 'marketId', partyId: 'partyId' })
); );
expect(result.current).toBeNull(); expect(result.current).toBeNull();
}); });
it('if no markets return null', () => { it('if no markets return null', () => {
mockNotEmptyData = { mockMarketAccountBalance = { accountBalance: '', accountDecimals: null };
party: { const { result } = renderHook(
accountsConnection: { () => useMarketPositions({ marketId: 'marketId' }),
edges: [ { wrapper: MockedProvider }
{
node: {
balance: '33330',
asset: {
decimals: 5,
},
market: {
id: 'otherMarketId',
},
},
},
],
},
positionsConnection: {
edges: [
{
node: {
openVolume: '2',
market: {
id: 'otherMarketId',
},
},
},
],
},
},
};
const { result } = renderHook(() =>
useMarketPositions({ marketId: 'marketId', partyId: 'partyId' })
); );
expect(result.current).toBeNull(); expect(result.current).toBeNull();
}); });

View File

@ -1,48 +1,34 @@
import { useMemo } from 'react';
import { BigNumber } from 'bignumber.js'; import { BigNumber } from 'bignumber.js';
import { useMarketPositionsQuery } from './__generated__/MarketPositions'; import { useMarketAccountBalance } from '@vegaprotocol/accounts';
import { removePaginationWrapper } from '@vegaprotocol/react-helpers'; import { useMarketPositionOpenVolume } from '@vegaprotocol/positions';
interface Props { interface Props {
marketId: string; marketId: string;
partyId: string;
} }
export type PositionMargin = { export type PositionMargin = {
openVolume: BigNumber; openVolume: string;
balance: BigNumber; balance: string;
balanceDecimals?: number; balanceDecimals?: number;
} | null; } | null;
export const useMarketPositions = ({ export const useMarketPositions = ({ marketId }: Props): PositionMargin => {
marketId, const { accountBalance, accountDecimals } = useMarketAccountBalance(marketId);
partyId, const openVolume = useMarketPositionOpenVolume(marketId);
}: Props): PositionMargin => {
const { data } = useMarketPositionsQuery({
pollInterval: 5000,
variables: { partyId },
fetchPolicy: 'no-cache',
});
const accounts = removePaginationWrapper( return useMemo(() => {
data?.party?.accountsConnection?.edges if (accountBalance && accountDecimals) {
); const balance = new BigNumber(accountBalance);
const account = accounts.find((nodes) => nodes.market?.id === marketId); const volume = new BigNumber(openVolume);
if (!balance.isZero() && !volume.isZero()) {
if (account) { return {
const positionConnectionNode = balance: accountBalance,
data?.party?.positionsConnection?.edges?.find( balanceDecimals: accountDecimals,
(nodes) => nodes.node.market.id === marketId openVolume,
); };
const balance = new BigNumber(account.balance || 0); }
const openVolume = new BigNumber(
positionConnectionNode?.node.openVolume || 0
);
if (!balance.isZero() && !openVolume.isZero()) {
return {
balance,
balanceDecimals: account?.asset.decimals,
openVolume,
};
} }
} return null;
return null; }, [accountBalance, accountDecimals, openVolume]);
}; };

View File

@ -1,31 +1,31 @@
import { renderHook } from '@testing-library/react'; import { renderHook } from '@testing-library/react';
import { MockedProvider } from '@apollo/client/testing';
import * as Schema from '@vegaprotocol/types'; import * as Schema from '@vegaprotocol/types';
import type { PositionMargin } from './use-market-positions';
import { BigNumber } from 'bignumber.js';
import { useMaximumPositionSize } from './use-maximum-position-size';
import type { AccountFragment as Account } from './__generated__/PartyBalance';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet'; import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import type { PositionMargin } from './use-market-positions';
import { useMaximumPositionSize } from './use-maximum-position-size';
jest.mock('@vegaprotocol/wallet', () => ({
...jest.requireActual('@vegaprotocol/wallet'),
useVegaWallet: jest.fn().mockReturnValue('wallet-pub-key'),
}));
let mockAccountBalance: {
accountBalance: string;
accountDecimals: number | null;
} = { accountBalance: '200000', accountDecimals: 5 };
jest.mock('@vegaprotocol/accounts', () => ({
...jest.requireActual('@vegaprotocol/accounts'),
useAccountBalance: jest.fn(() => mockAccountBalance),
}));
const defaultMockMarketPositions = { const defaultMockMarketPositions = {
openVolume: new BigNumber(1), openVolume: '1',
balance: new BigNumber(100000), balance: '100000',
}; };
let mockMarketPositions: PositionMargin | null = defaultMockMarketPositions; let mockMarketPositions: PositionMargin | null = defaultMockMarketPositions;
const mockAccount: Account = {
__typename: 'AccountBalance',
type: Schema.AccountType.ACCOUNT_TYPE_GENERAL,
balance: '200000',
asset: {
__typename: 'Asset',
id: '5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c',
symbol: 'tBTC',
name: 'tBTC TEST',
decimals: 5,
},
};
const mockOrder: OrderSubmissionBody['orderSubmission'] = { const mockOrder: OrderSubmissionBody['orderSubmission'] = {
type: Schema.OrderType.TYPE_MARKET, type: Schema.OrderType.TYPE_MARKET,
size: '1', size: '1',
@ -34,12 +34,6 @@ const mockOrder: OrderSubmissionBody['orderSubmission'] = {
marketId: 'market-id', marketId: 'market-id',
}; };
jest.mock('./use-settlement-account', () => {
return {
useSettlementAccount: jest.fn(() => mockAccount),
};
});
jest.mock('./use-market-positions', () => ({ jest.mock('./use-market-positions', () => ({
useMarketPositions: ({ useMarketPositions: ({
marketId, marketId,
@ -55,15 +49,15 @@ describe('useMaximumPositionSize', () => {
mockMarketPositions = null; mockMarketPositions = null;
const price = '50'; const price = '50';
const expected = 4000; const expected = 4000;
const { result } = renderHook(() => const { result } = renderHook(
useMaximumPositionSize({ () =>
marketId: '', useMaximumPositionSize({
partyId: '', marketId: '',
price, price,
settlementAssetId: '', settlementAssetId: '',
order: mockOrder, order: mockOrder,
accounts: [mockAccount], }),
}) { wrapper: MockedProvider }
); );
expect(result.current).toBe(expected); expect(result.current).toBe(expected);
}); });
@ -72,15 +66,15 @@ describe('useMaximumPositionSize', () => {
const price = '50'; const price = '50';
mockMarketPositions = defaultMockMarketPositions; mockMarketPositions = defaultMockMarketPositions;
const expected = 3999; const expected = 3999;
const { result } = renderHook(() => const { result } = renderHook(
useMaximumPositionSize({ () =>
marketId: '', useMaximumPositionSize({
partyId: '', marketId: '',
price, price,
settlementAssetId: '', settlementAssetId: '',
order: mockOrder, order: mockOrder,
accounts: [mockAccount], }),
}) { wrapper: MockedProvider }
); );
expect(result.current).toBe(expected); expect(result.current).toBe(expected);
}); });
@ -90,33 +84,36 @@ describe('useMaximumPositionSize', () => {
mockOrder.side = Schema.Side.SIDE_SELL; mockOrder.side = Schema.Side.SIDE_SELL;
mockMarketPositions = defaultMockMarketPositions; mockMarketPositions = defaultMockMarketPositions;
const expected = 4001; const expected = 4001;
const { result } = renderHook(() => const { result } = renderHook(
useMaximumPositionSize({ () =>
marketId: '', useMaximumPositionSize({
partyId: '', marketId: '',
price, price,
settlementAssetId: '', settlementAssetId: '',
order: mockOrder, order: mockOrder,
accounts: [mockAccount], }),
}) { wrapper: MockedProvider }
); );
expect(result.current).toBe(expected); expect(result.current).toBe(expected);
}); });
it('should return zero if no account balance', () => { it('should return zero if no account balance', () => {
mockAccount.balance = '0'; mockAccountBalance = {
accountBalance: '0',
accountDecimals: 5,
};
const price = '50'; const price = '50';
mockMarketPositions = defaultMockMarketPositions; mockMarketPositions = defaultMockMarketPositions;
const expected = 0; const expected = 0;
const { result } = renderHook(() => const { result } = renderHook(
useMaximumPositionSize({ () =>
marketId: '', useMaximumPositionSize({
partyId: '', marketId: '',
price, price,
settlementAssetId: '', settlementAssetId: '',
order: mockOrder, order: mockOrder,
accounts: [], }),
}) { wrapper: MockedProvider }
); );
expect(result.current).toBe(expected); expect(result.current).toBe(expected);
}); });

View File

@ -1,13 +1,10 @@
import { useMarketPositions } from './use-market-positions';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import { useSettlementAccount } from './use-settlement-account';
import * as Schema from '@vegaprotocol/types'; import * as Schema from '@vegaprotocol/types';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import { useAccountBalance } from '@vegaprotocol/accounts';
import { BigNumber } from 'bignumber.js'; import { BigNumber } from 'bignumber.js';
import type { AccountFragment as Account } from './__generated__/PartyBalance'; import { useMarketPositions } from './use-market-positions';
interface Props { interface Props {
partyId: string;
accounts: Account[];
marketId: string; marketId: string;
price?: string; price?: string;
settlementAssetId: string; settlementAssetId: string;
@ -19,37 +16,26 @@ const getSize = (balance: string, price: string) =>
export const useMaximumPositionSize = ({ export const useMaximumPositionSize = ({
marketId, marketId,
accounts,
partyId,
price, price,
settlementAssetId, settlementAssetId,
order, order,
}: Props): number => { }: Props): number => {
const settlementAccount = useSettlementAccount( const { accountBalance } = useAccountBalance(settlementAssetId) || {};
settlementAssetId, const marketPositions = useMarketPositions({ marketId: marketId });
accounts, if (!accountBalance || new BigNumber(accountBalance || 0).isZero()) {
Schema.AccountType.ACCOUNT_TYPE_GENERAL
);
const marketPositions = useMarketPositions({ marketId: marketId, partyId });
if (
!settlementAccount?.balance ||
new BigNumber(settlementAccount?.balance || 0).isZero()
) {
return 0; return 0;
} }
const size = getSize(settlementAccount.balance, price || ''); const size = getSize(accountBalance, price || '');
if (!marketPositions) { if (!marketPositions) {
return size.toNumber() || 0; return size.toNumber() || 0;
} }
const isSameSide = const isSameSide =
(marketPositions.openVolume.isPositive() && (new BigNumber(marketPositions.openVolume).isPositive() &&
order.side === Schema.Side.SIDE_BUY) || order.side === Schema.Side.SIDE_BUY) ||
(marketPositions.openVolume.isNegative() && (new BigNumber(marketPositions.openVolume).isNegative() &&
order.side === Schema.Side.SIDE_SELL); order.side === Schema.Side.SIDE_SELL);
const adjustedForVolume = new BigNumber(size)[isSameSide ? 'minus' : 'plus']( const adjustedForVolume = new BigNumber(size)[isSameSide ? 'minus' : 'plus'](

View File

@ -1,15 +1,18 @@
import * as React from 'react';
import { renderHook } from '@testing-library/react'; import { renderHook } from '@testing-library/react';
import { MockedProvider } from '@apollo/client/testing'; import { MockedProvider } from '@apollo/client/testing';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet'; import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import type { MarketDealTicket } from '@vegaprotocol/market-list'; import type { MarketDealTicket } from '@vegaprotocol/market-list';
import type { PartyBalanceQuery } from './__generated__/PartyBalance';
import { useOrderCloseOut } from './use-order-closeout'; import { useOrderCloseOut } from './use-order-closeout';
jest.mock('@vegaprotocol/wallet', () => ({ jest.mock('@vegaprotocol/wallet', () => ({
...jest.requireActual('@vegaprotocol/wallet'), ...jest.requireActual('@vegaprotocol/wallet'),
useVegaWallet: jest.fn().mockReturnValue('wallet-pub-key'), useVegaWallet: jest.fn().mockReturnValue('wallet-pub-key'),
})); }));
let mockMarketMargin: string | undefined = undefined;
jest.mock('@vegaprotocol/positions', () => ({
...jest.requireActual('@vegaprotocol/positions'),
useMarketMargin: () => mockMarketMargin,
}));
describe('useOrderCloseOut', () => { describe('useOrderCloseOut', () => {
const order = { size: '2', side: 'SIDE_BUY' }; const order = { size: '2', side: 'SIDE_BUY' };
@ -29,43 +32,32 @@ describe('useOrderCloseOut', () => {
}, },
}, },
}, },
}; data: {
const partyData = { markPrice: 100000,
party: {
accountsConnection: {
edges: [
{
node: {
balance: '200000',
asset: {
id: 'assetId',
decimals: 5,
},
},
},
],
},
}, },
}; } as unknown as MarketDealTicket;
beforeEach(() => {
jest.clearAllMocks();
});
it('should return proper null value', () => { it('should return proper null value', () => {
mockMarketMargin = '-1';
const { result } = renderHook( const { result } = renderHook(
() => () =>
useOrderCloseOut({ useOrderCloseOut({
order: order as OrderSubmissionBody['orderSubmission'], order: order as OrderSubmissionBody['orderSubmission'],
market: market as MarketDealTicket, market: { ...market, data: { ...market.data, markPrice: '0' } },
partyData: partyData as PartyBalanceQuery,
}), }),
{ {
wrapper: ({ children }: { children: React.ReactNode }) => ( wrapper: MockedProvider,
<MockedProvider mocks={[]}>{children}</MockedProvider>
),
} }
); );
expect(result.current).toEqual(null); expect(result.current).toEqual(null);
}); });
it('should return proper sell value', () => { it('should return proper sell value', () => {
mockMarketMargin = '0';
const { result } = renderHook( const { result } = renderHook(
() => () =>
useOrderCloseOut({ useOrderCloseOut({
@ -73,13 +65,10 @@ describe('useOrderCloseOut', () => {
...order, ...order,
side: 'SIDE_SELL', side: 'SIDE_SELL',
} as OrderSubmissionBody['orderSubmission'], } as OrderSubmissionBody['orderSubmission'],
market: market as MarketDealTicket, market: market,
partyData: partyData as PartyBalanceQuery,
}), }),
{ {
wrapper: ({ children }: { children: React.ReactNode }) => ( wrapper: MockedProvider,
<MockedProvider mocks={[]}>{children}</MockedProvider>
),
} }
); );
expect(result.current).toEqual('1.00'); expect(result.current).toEqual('1.00');
@ -93,12 +82,10 @@ describe('useOrderCloseOut', () => {
...order, ...order,
side: 'SIDE_SELL', side: 'SIDE_SELL',
} as OrderSubmissionBody['orderSubmission'], } as OrderSubmissionBody['orderSubmission'],
market: market as MarketDealTicket, market: { ...market, data: { ...market.data, markPrice: '0' } },
}), }),
{ {
wrapper: ({ children }: { children: React.ReactNode }) => ( wrapper: MockedProvider,
<MockedProvider mocks={[]}>{children}</MockedProvider>
),
} }
); );
expect(result.current).toEqual('0.00'); expect(result.current).toEqual('0.00');

View File

@ -1,85 +1,47 @@
import { BigNumber } from 'bignumber.js'; import { BigNumber } from 'bignumber.js';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet'; import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import { useVegaWallet } from '@vegaprotocol/wallet'; import { addDecimal, formatNumber } from '@vegaprotocol/react-helpers';
import {
addDecimal,
formatNumber,
removePaginationWrapper,
} from '@vegaprotocol/react-helpers';
import { useMarketPositions } from './use-market-positions';
import { useMarketDataMarkPrice } from './use-market-data-mark-price';
import { usePartyMarketDataQuery } from './__generated__/PartyMarketData';
import * as Schema from '@vegaprotocol/types'; import * as Schema from '@vegaprotocol/types';
import type { PartyBalanceQuery } from './__generated__/PartyBalance';
import { useSettlementAccount } from './use-settlement-account';
import type { MarketDealTicket } from '@vegaprotocol/market-list'; import type { MarketDealTicket } from '@vegaprotocol/market-list';
import {
useAccountBalance,
useMarketAccountBalance,
} from '@vegaprotocol/accounts';
import { useMarketMargin } from '@vegaprotocol/positions';
import { useMarketPositions } from './use-market-positions';
interface Props { interface Props {
order: OrderSubmissionBody['orderSubmission']; order: OrderSubmissionBody['orderSubmission'];
market: MarketDealTicket; market: MarketDealTicket;
partyData?: PartyBalanceQuery;
} }
export const useOrderCloseOut = ({ export const useOrderCloseOut = ({ order, market }: Props): string | null => {
order, const { accountBalance, accountDecimals } = useAccountBalance(
market, market.tradableInstrument.instrument.product.settlementAsset.id
partyData,
}: Props): string | null => {
const { pubKey } = useVegaWallet();
const accounts = removePaginationWrapper(
partyData?.party?.accountsConnection?.edges
); );
const account = useSettlementAccount( const { accountBalance: positionBalance, accountDecimals: positionDecimals } =
market.tradableInstrument.instrument.product.settlementAsset.id, useMarketAccountBalance(market.id);
accounts const maintenanceLevel = useMarketMargin(market.id);
);
const { data } = usePartyMarketDataQuery({
pollInterval: 5000,
variables: { partyId: pubKey || '' },
skip: !pubKey,
});
const markPriceData = useMarketDataMarkPrice(market.id);
const marketPositions = useMarketPositions({
marketId: market.id,
partyId: pubKey || '',
});
const marginMaintenanceLevel = new BigNumber( const marginMaintenanceLevel = new BigNumber(
addDecimal( addDecimal(maintenanceLevel || 0, market.decimalPlaces)
data?.party?.marginsConnection?.edges?.find(
(nodes) => nodes.node.market.id === market.id
)?.node.maintenanceLevel || 0,
market.decimalPlaces
)
);
const dataAccounts = removePaginationWrapper(
data?.party?.accountsConnection?.edges
);
const positionAccount = dataAccounts.find(
(account) => account.market?.id === market.id
); );
const positionAccountBalance = new BigNumber( const positionAccountBalance = new BigNumber(
addDecimal( addDecimal(positionBalance || 0, positionDecimals || 0)
positionAccount?.balance || 0,
positionAccount?.asset?.decimals || 0
)
); );
const generalAccountBalance = new BigNumber( const generalAccountBalance = new BigNumber(
addDecimal(account?.balance || 0, account?.asset.decimals || 0) addDecimal(accountBalance || 0, accountDecimals || 0)
); );
const { openVolume } =
useMarketPositions({
marketId: market.id,
}) || {};
const volume = new BigNumber( const volume = new BigNumber(
addDecimal( addDecimal(openVolume || '0', market.positionDecimalPlaces)
marketPositions?.openVolume.toString() || '0',
market.positionDecimalPlaces
)
)[order.side === Schema.Side.SIDE_BUY ? 'plus' : 'minus'](order.size); )[order.side === Schema.Side.SIDE_BUY ? 'plus' : 'minus'](order.size);
const markPrice = new BigNumber( const markPrice = new BigNumber(
addDecimal( addDecimal(market.data.markPrice || 0, market.decimalPlaces || 0)
markPriceData?.market?.data?.markPrice || 0,
markPriceData?.market?.decimalPlaces || 0
)
); );
// regarding formula (marginMaintenanceLevel - positionAccountBalance - generalAccountBalance) / volume + markPrice // regarding formula (marginMaintenanceLevel - positionAccountBalance - generalAccountBalance) / volume + markPrice
const marginDifference = marginMaintenanceLevel const marginDifference = marginMaintenanceLevel

View File

@ -1,7 +1,6 @@
import { useMemo } from 'react'; import { useMemo } from 'react';
import { useVegaWallet } from '@vegaprotocol/wallet'; import { useVegaWallet } from '@vegaprotocol/wallet';
import { toBigNum } from '@vegaprotocol/react-helpers'; import { toBigNum } from '@vegaprotocol/react-helpers';
import type { OrderMargin } from './use-order-margin';
import { useAccountBalance } from '@vegaprotocol/accounts'; import { useAccountBalance } from '@vegaprotocol/accounts';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet'; import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import { useOrderMargin } from './use-order-margin'; import { useOrderMargin } from './use-order-margin';
@ -14,7 +13,7 @@ interface Props {
export const useOrderMarginValidation = ({ market, order }: Props) => { export const useOrderMarginValidation = ({ market, order }: Props) => {
const { pubKey } = useVegaWallet(); const { pubKey } = useVegaWallet();
const estMargin: OrderMargin | null = useOrderMargin({ const estMargin = useOrderMargin({
order, order,
market, market,
partyId: pubKey || '', partyId: pubKey || '',

View File

@ -26,8 +26,8 @@ jest.mock('@apollo/client', () => ({
})); }));
let mockMarketPositions: PositionMargin = { let mockMarketPositions: PositionMargin = {
openVolume: new BigNumber(1), openVolume: '1',
balance: new BigNumber(100000), balance: '100000',
}; };
jest.mock('./use-market-positions', () => ({ jest.mock('./use-market-positions', () => ({

View File

@ -1,8 +1,8 @@
import { useMemo } from 'react';
import { BigNumber } from 'bignumber.js'; import { BigNumber } from 'bignumber.js';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet'; import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import { removeDecimal } from '@vegaprotocol/react-helpers'; import { removeDecimal } from '@vegaprotocol/react-helpers';
import { useMarketPositions } from './use-market-positions'; import { useMarketPositions } from './use-market-positions';
import type { EstimateOrderQuery } from './__generated__/EstimateOrder';
import { useEstimateOrderQuery } from './__generated__/EstimateOrder'; import { useEstimateOrderQuery } from './__generated__/EstimateOrder';
import type { MarketDealTicket } from '@vegaprotocol/market-list'; import type { MarketDealTicket } from '@vegaprotocol/market-list';
import { getDerivedPrice } from '../utils/get-price'; import { getDerivedPrice } from '../utils/get-price';
@ -14,12 +14,6 @@ export interface Props {
derivedPrice?: string; derivedPrice?: string;
} }
const addFees = (feeObj: EstimateOrderQuery['estimateOrder']['fee']) => {
return new BigNumber(feeObj.makerFee)
.plus(feeObj.liquidityFee)
.plus(feeObj.infrastructureFee);
};
export interface OrderMargin { export interface OrderMargin {
margin: string; margin: string;
totalFees: string | null; totalFees: string | null;
@ -36,7 +30,7 @@ export const useOrderMargin = ({
partyId, partyId,
derivedPrice, derivedPrice,
}: Props): OrderMargin | null => { }: Props): OrderMargin | null => {
const marketPositions = useMarketPositions({ marketId: market.id, partyId }); const { balance } = useMarketPositions({ marketId: market.id }) || {};
const priceForEstimate = derivedPrice || getDerivedPrice(order, market); const priceForEstimate = derivedPrice || getDerivedPrice(order, market);
const { data } = useEstimateOrderQuery({ const { data } = useEstimateOrderQuery({
@ -51,29 +45,29 @@ export const useOrderMargin = ({
}, },
skip: !partyId || !market.id || !order.size || !priceForEstimate, skip: !partyId || !market.id || !order.size || !priceForEstimate,
}); });
const { makerFee, liquidityFee, infrastructureFee } = data?.estimateOrder
if (data?.estimateOrder.marginLevels.initialLevel) { .fee || { makerFee: '', liquidityFee: '', infrastructureFee: '' };
const fees = const { initialLevel } = data?.estimateOrder.marginLevels ?? {};
data?.estimateOrder?.fee && addFees(data.estimateOrder.fee).toString(); return useMemo(() => {
const margin = BigNumber.maximum( if (initialLevel) {
0, const margin = BigNumber.maximum(
new BigNumber(data.estimateOrder.marginLevels.initialLevel).minus( 0,
marketPositions?.balance || 0 new BigNumber(initialLevel).minus(balance || 0)
) ).toString();
).toString(); const fees = new BigNumber(makerFee)
.plus(liquidityFee)
const { makerFee, liquidityFee, infrastructureFee } = .plus(infrastructureFee)
data.estimateOrder.fee; .toString();
return {
return { margin,
margin, totalFees: fees,
totalFees: fees, fees: {
fees: { makerFee,
makerFee, liquidityFee,
liquidityFee, infrastructureFee,
infrastructureFee, },
}, };
}; }
} return null;
return null; }, [initialLevel, makerFee, liquidityFee, infrastructureFee, balance]);
}; };

View File

@ -1,90 +0,0 @@
import { renderHook } from '@testing-library/react';
import { useSettlementAccount } from './use-settlement-account';
import * as Schema from '@vegaprotocol/types';
import type { AccountFragment as Account } from './__generated__/PartyBalance';
describe('useSettlementAccount Hook', () => {
it('should filter accounts by settlementAssetId', () => {
const accounts: Account[] = [
{
__typename: 'AccountBalance',
type: Schema.AccountType.ACCOUNT_TYPE_GENERAL,
balance: '2000000000000000000000',
asset: {
__typename: 'Asset',
id: '5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c',
symbol: 'tBTC',
name: 'tBTC TEST',
decimals: 5,
},
},
{
__typename: 'AccountBalance',
type: Schema.AccountType.ACCOUNT_TYPE_GENERAL,
balance: '1000000000',
asset: {
__typename: 'Asset',
id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
symbol: 'tDAI',
name: 'tDAI TEST',
decimals: 5,
},
},
{
__typename: 'AccountBalance',
type: Schema.AccountType.ACCOUNT_TYPE_GENERAL,
balance: '5000000000000000000',
asset: {
__typename: 'Asset',
id: 'fc7fd956078fb1fc9db5c19b88f0874c4299b2a7639ad05a47a28c0aef291b55',
symbol: 'VEGA',
name: 'Vega (testnet)',
decimals: 18,
},
},
{
__typename: 'AccountBalance',
type: Schema.AccountType.ACCOUNT_TYPE_MARGIN,
balance: '5000000000000000000',
asset: {
__typename: 'Asset',
id: 'fc7fd956078fb1fc9db5c19b88f0874c4299b2a7639ad05a47a28c0aef291b55',
symbol: 'VEGA',
name: 'Vega (testnet)',
decimals: 18,
},
},
];
const tDAI =
'6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61';
const vega =
'fc7fd956078fb1fc9db5c19b88f0874c4299b2a7639ad05a47a28c0aef291b55';
const { result: resultDai } = renderHook(() =>
useSettlementAccount(tDAI, accounts)
);
expect(resultDai.current?.balance).toBe(accounts[1].balance);
expect(resultDai.current?.asset).toEqual(accounts[1].asset);
const { result: resultVega } = renderHook(() =>
useSettlementAccount(
vega,
accounts,
Schema.AccountType.ACCOUNT_TYPE_MARGIN
)
);
expect(resultVega.current?.balance).toBe(accounts[3].balance);
expect(resultVega.current?.asset).toEqual(accounts[3].asset);
});
it('should return null if no accounts', () => {
const accounts: Account[] = [];
const settlementAssetId =
'6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61';
const { result } = renderHook(() =>
useSettlementAccount(settlementAssetId, accounts)
);
expect(result.current).toBe(null);
});
});

View File

@ -1,20 +0,0 @@
import type * as Schema from '@vegaprotocol/types';
import { useMemo } from 'react';
import type { AccountFragment as Account } from './__generated__/PartyBalance';
export const useSettlementAccount = (
settlementAssetId: string,
accounts: Account[],
type?: Schema.AccountType
): Account | null => {
const callback = () =>
accounts.find((account) => {
if (type) {
return account.asset.id === settlementAssetId && account.type === type;
}
return account.asset.id === settlementAssetId;
});
const account = useMemo(callback, [accounts, settlementAssetId, type]);
return account || null;
};

View File

@ -4,3 +4,5 @@ export * from './lib/positions-data-providers';
export * from './lib/positions-table'; export * from './lib/positions-table';
export * from './lib/use-close-position'; export * from './lib/use-close-position';
export * from './lib/use-positions-data'; export * from './lib/use-positions-data';
export * from './lib/use-market-position-open-volume';
export * from './lib/use-market-margin';

View File

@ -0,0 +1,51 @@
import { useCallback, useMemo, useState } from 'react';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { useDataProvider } from '@vegaprotocol/react-helpers';
import { marginsDataProvider } from './margin-data-provider';
import type {
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) => {
const { pubKey } = useVegaWallet();
const [marginLevel, setMarginLevel] = useState<string>('');
const variables = useMemo(() => {
return { partyId: pubKey || '' };
}, [pubKey]);
const update = useCallback(
({ data }: { data: MarginsQuery['party'] | null }) => {
const marginMarketPosition = getMarketMarginPosition({ data, marketId });
if (marginLevel !== marginMarketPosition?.maintenanceLevel) {
setMarginLevel(marginMarketPosition?.maintenanceLevel || '');
}
return true;
},
[marginLevel, setMarginLevel, marketId]
);
useDataProvider<
MarginsQuery['party'],
MarginsSubscriptionSubscription['margins']
>({
dataProvider: marginsDataProvider,
variables,
skip: !pubKey || !marketId,
update,
});
return marginLevel;
};

View File

@ -0,0 +1,50 @@
import { useCallback, useMemo, useState } from 'react';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { positionsDataProvider } from './positions-data-providers';
import { useDataProvider } from '@vegaprotocol/react-helpers';
import type {
PositionsQuery,
PositionsSubscriptionSubscription,
} 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) => {
const { pubKey } = useVegaWallet();
const [openVolume, setOpenVolume] = useState<string>('');
const variables = useMemo(() => {
return { partyId: pubKey || '' };
}, [pubKey]);
const update = useCallback(
({ data }: { data: PositionsQuery['party'] | undefined }) => {
const position = getMarketPosition({ data, marketId });
if (openVolume !== position?.openVolume) {
setOpenVolume(position?.openVolume || '');
}
return true;
},
[openVolume, setOpenVolume, marketId]
);
useDataProvider<
PositionsQuery['party'],
PositionsSubscriptionSubscription['positions']
>({
dataProvider: positionsDataProvider,
variables,
skip: !pubKey || !marketId,
update,
});
return openVolume;
};