chore(2071): deal ticket data update fixing (#2169)

* chore: update of deal ticket data

* chore: update of deal ticket data

* chore: update of deal ticket data - fix re-render loop

* chore: update of deal ticket data - add marketDealTicketProvider

* chore: update of deal ticket data - add marketDealTicketProvider

* chore: update of deal ticket data - adjust console-lite to the changes

* chore: update of deal ticket data - fix failing unit tests

* chore: update of deal ticket data - fix failing unit tests

* chore: update of deal ticket data - fix linter failings

* chore: update of deal ticket data - adjust console-lite-e2e

* chore: update of deal ticket data - fix build-spec failings

* chore: update of deal ticket data - fix failing e2e tests

* chore: update of deal ticket data - fix failing e2e tests

* chore: update of deal ticket data - fix failing e2e tests

* chore: update of deal ticket data - remove unnecessary gqls

* chore: update of deal ticket data - remove unnecessary gqls

* chore: update of deal ticket data - remove unnecessary gqls

* chore: update of deal ticket data - fix failings build

* chore: update of deal ticket data - remove redundant data provider

* chore: update of deal ticket data - remove redundant data provider

* chore: update of deal ticket data - fix some types
This commit is contained in:
macqbat 2022-11-22 09:31:26 +01:00 committed by GitHub
parent a5aed85b43
commit b749a05736
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
51 changed files with 576 additions and 625 deletions

View File

@ -1,11 +1,12 @@
import { connectVegaWallet } from '../support/vega-wallet'; import { connectVegaWallet } from '../support/vega-wallet';
import { aliasQuery } from '@vegaprotocol/cypress'; import { aliasQuery } from '@vegaprotocol/cypress';
import { import {
generateMarket,
generateMarketData,
generateMarketsCandles, generateMarketsCandles,
generateMarketsData, generateMarketsData,
generateSimpleMarkets, generateSimpleMarkets,
} from '../support/mocks/generate-markets'; } from '../support/mocks/generate-markets';
import { generateDealTicket } from '../support/mocks/generate-deal-ticket';
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 { generateMarketPositions } from '../support/mocks/generate-market-positions';
import { generateEstimateOrder } from '../support/mocks/generate-estimate-order'; import { generateEstimateOrder } from '../support/mocks/generate-estimate-order';
@ -27,7 +28,8 @@ describe('market selector', { tags: '@smoke' }, () => {
aliasQuery(req, 'Markets', generateSimpleMarkets()); aliasQuery(req, 'Markets', generateSimpleMarkets());
aliasQuery(req, 'MarketsCandles', generateMarketsCandles()); aliasQuery(req, 'MarketsCandles', generateMarketsCandles());
aliasQuery(req, 'MarketsData', generateMarketsData()); aliasQuery(req, 'MarketsData', generateMarketsData());
aliasQuery(req, 'DealTicket', generateDealTicket()); aliasQuery(req, 'MarketData', generateMarketData());
aliasQuery(req, 'Market', generateMarket());
aliasQuery(req, 'MarketTags', generateMarketTags()); aliasQuery(req, 'MarketTags', generateMarketTags());
aliasQuery(req, 'MarketPositions', generateMarketPositions()); aliasQuery(req, 'MarketPositions', generateMarketPositions());
aliasQuery(req, 'EstimateOrder', generateEstimateOrder()); aliasQuery(req, 'EstimateOrder', generateEstimateOrder());

View File

@ -5,8 +5,8 @@ import {
generateMarketsCandles, generateMarketsCandles,
generateMarketsData, generateMarketsData,
generateMarket, generateMarket,
generateMarketData,
} from '../support/mocks/generate-markets'; } from '../support/mocks/generate-markets';
import { generateDealTicket } from '../support/mocks/generate-deal-ticket';
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 { generateMarketPositions } from '../support/mocks/generate-market-positions';
import { generateEstimateOrder } from '../support/mocks/generate-estimate-order'; import { generateEstimateOrder } from '../support/mocks/generate-estimate-order';
@ -28,7 +28,6 @@ describe('Market trade', { tags: '@smoke' }, () => {
aliasQuery(req, 'MarketsCandles', generateMarketsCandles()); aliasQuery(req, 'MarketsCandles', generateMarketsCandles());
aliasQuery(req, 'MarketsData', generateMarketsData()); aliasQuery(req, 'MarketsData', generateMarketsData());
aliasQuery(req, 'SimpleMarkets', generateSimpleMarkets()); aliasQuery(req, 'SimpleMarkets', generateSimpleMarkets());
aliasQuery(req, 'DealTicket', generateDealTicket());
aliasQuery(req, 'MarketTags', generateMarketTags()); aliasQuery(req, 'MarketTags', generateMarketTags());
aliasQuery(req, 'MarketPositions', generateMarketPositions()); aliasQuery(req, 'MarketPositions', generateMarketPositions());
aliasQuery(req, 'EstimateOrder', generateEstimateOrder()); aliasQuery(req, 'EstimateOrder', generateEstimateOrder());
@ -37,6 +36,7 @@ describe('Market trade', { tags: '@smoke' }, () => {
aliasQuery(req, 'MarketMarkPrice', generateMarketMarkPrice()); aliasQuery(req, 'MarketMarkPrice', generateMarketMarkPrice());
aliasQuery(req, 'MarketDepth', generateMarketDepth()); aliasQuery(req, 'MarketDepth', generateMarketDepth());
aliasQuery(req, 'Market', generateMarket()); aliasQuery(req, 'Market', generateMarket());
aliasQuery(req, 'MarketData', generateMarketData());
}); });
cy.visit('/markets'); cy.visit('/markets');
cy.wait('@Markets').then((response) => { cy.wait('@Markets').then((response) => {

View File

@ -144,4 +144,8 @@ export const singleMarket: SingleMarketFieldsFragment = {
}, },
}, },
}, },
depth: {
__typename: 'MarketDepth',
lastTrade: { price: '9893006', __typename: 'Trade' },
},
}; };

View File

@ -1,52 +0,0 @@
import type { DealTicketQuery } from '@vegaprotocol/deal-ticket';
import { Schema } from '@vegaprotocol/types';
import merge from 'lodash/merge';
import type { PartialDeep } from 'type-fest';
export const generateDealTicket = (
override?: PartialDeep<DealTicketQuery>
): DealTicketQuery => {
const defaultResult: DealTicketQuery = {
market: {
id: 'ca7768f6de84bf86a21bbb6b0109d9659c81917b0e0339b2c262566c9b581a15',
decimalPlaces: 5,
positionDecimalPlaces: 0,
state: Schema.MarketState.STATE_ACTIVE,
tradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
tradableInstrument: {
instrument: {
id: 'c9f5acd348796011c075077e4d58d9b7f1689b7c1c8e030a5e886b83aa96923d',
name: 'AAVEDAI Monthly (30 Jun 2022)',
product: {
quoteName: 'DAI',
settlementAsset: {
id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
symbol: 'tDAI',
name: 'tDAI TEST',
decimals: 5,
__typename: 'Asset',
},
__typename: 'Future',
},
__typename: 'Instrument',
},
__typename: 'TradableInstrument',
},
depth: {
lastTrade: { price: '9893006', __typename: 'Trade' },
__typename: 'MarketDepth',
},
fees: {
factors: {
makerFee: '0.0002',
infrastructureFee: '0.0005',
liquidityFee: '0.001',
__typename: 'FeeFactors',
},
__typename: 'Fees',
},
__typename: 'Market',
},
};
return merge(defaultResult, override);
};

View File

@ -11,6 +11,7 @@ import type {
import { protoMarket, protoCandles, singleMarket } from './commons'; import { protoMarket, protoCandles, singleMarket } from './commons';
import type { PartialDeep } from 'type-fest'; import type { PartialDeep } from 'type-fest';
import type { MarketQuery } from '@vegaprotocol/market-list'; import type { MarketQuery } from '@vegaprotocol/market-list';
import type { MarketDataQuery } from '@vegaprotocol/market-list';
export const generateSimpleMarkets = (): MarketsQuery => { export const generateSimpleMarkets = (): MarketsQuery => {
const markets: Market[] = [ const markets: Market[] = [
@ -1139,52 +1140,51 @@ export const generateFillsMarkets = () => {
}; };
}; };
const markets = [
{
data: {
market: {
id: 'c9f5acd348796011c075077e4d58d9b7f1689b7c1c8e030a5e886b83aa96923d',
__typename: 'Market',
},
marketTradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
staticMidPrice: '0',
indicativePrice: '0',
bestStaticBidPrice: '0',
bestStaticOfferPrice: '0',
indicativeVolume: '0',
bestBidPrice: '0',
bestOfferPrice: '0',
markPrice: '17588787',
trigger: Schema.AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED,
__typename: 'MarketData',
},
__typename: 'Market',
},
{
data: {
market: {
id: '5a4b0b9e9c0629f0315ec56fcb7bd444b0c6e4da5ec7677719d502626658a376',
__typename: 'Market',
},
marketTradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
staticMidPrice: '0',
indicativePrice: '0',
bestStaticBidPrice: '0',
bestStaticOfferPrice: '0',
indicativeVolume: '0',
bestBidPrice: '0',
bestOfferPrice: '0',
markPrice: '84377569',
trigger: Schema.AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED,
__typename: 'MarketData',
},
__typename: 'Market',
},
];
export const generateMarketsData = ( export const generateMarketsData = (
override?: PartialDeep<MarketsDataQuery> override?: PartialDeep<MarketsDataQuery>
): MarketsDataQuery => { ): MarketsDataQuery => {
const markets = [
{
data: {
market: {
id: 'c9f5acd348796011c075077e4d58d9b7f1689b7c1c8e030a5e886b83aa96923d',
__typename: 'Market',
},
marketTradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
staticMidPrice: '0',
indicativePrice: '0',
bestStaticBidPrice: '0',
bestStaticOfferPrice: '0',
indicativeVolume: '0',
bestBidPrice: '0',
bestOfferPrice: '0',
markPrice: '17588787',
trigger: Schema.AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED,
__typename: 'MarketData',
},
__typename: 'Market',
},
{
data: {
market: {
id: '5a4b0b9e9c0629f0315ec56fcb7bd444b0c6e4da5ec7677719d502626658a376',
__typename: 'Market',
},
marketTradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
staticMidPrice: '0',
indicativePrice: '0',
bestStaticBidPrice: '0',
bestStaticOfferPrice: '0',
indicativeVolume: '0',
bestBidPrice: '0',
bestOfferPrice: '0',
markPrice: '84377569',
trigger: Schema.AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED,
__typename: 'MarketData',
},
__typename: 'Market',
},
];
const defaultResult: MarketsDataQuery = { const defaultResult: MarketsDataQuery = {
marketsConnection: { marketsConnection: {
__typename: 'MarketConnection', __typename: 'MarketConnection',
@ -1382,3 +1382,34 @@ export const generateMarket = (): MarketQuery => {
}, },
}; };
}; };
export const generateMarketData = (): MarketDataQuery => {
return {
marketsConnection: {
edges: [
{
node: {
data: {
market: {
id: protoMarket.id,
__typename: 'Market',
},
marketTradingMode:
Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
staticMidPrice: '0',
indicativePrice: '0',
bestStaticBidPrice: '0',
bestStaticOfferPrice: '0',
indicativeVolume: '0',
bestBidPrice: '0',
bestOfferPrice: '0',
markPrice: '17588787',
trigger: Schema.AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED,
__typename: 'MarketData',
},
},
},
],
},
};
};

View File

@ -17,7 +17,7 @@ export const generatePartyBalance = (
balance: '88474051', balance: '88474051',
type: Types.AccountType.ACCOUNT_TYPE_GENERAL, type: Types.AccountType.ACCOUNT_TYPE_GENERAL,
asset: { asset: {
id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61', id: 'dai-id',
symbol: 'tDAI', symbol: 'tDAI',
name: 'tDAI TEST', name: 'tDAI TEST',
decimals: 5, decimals: 5,
@ -47,7 +47,7 @@ export const generatePartyBalance = (
balance: '3412867', balance: '3412867',
type: Types.AccountType.ACCOUNT_TYPE_GENERAL, type: Types.AccountType.ACCOUNT_TYPE_GENERAL,
asset: { asset: {
id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61', id: 'dai-id',
symbol: 'tDAI', symbol: 'tDAI',
name: 'tDAI TEST', name: 'tDAI TEST',
decimals: 5, decimals: 5,
@ -62,7 +62,7 @@ export const generatePartyBalance = (
balance: '70007', balance: '70007',
type: Types.AccountType.ACCOUNT_TYPE_GENERAL, type: Types.AccountType.ACCOUNT_TYPE_GENERAL,
asset: { asset: {
id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61', id: 'dai-id',
symbol: 'tDAI', symbol: 'tDAI',
name: 'tDAI TEST', name: 'tDAI TEST',
decimals: 5, decimals: 5,

View File

@ -1,20 +1,17 @@
import React from 'react'; import React from 'react';
import { render } from '@testing-library/react'; import { render } from '@testing-library/react';
import type { import type { AccountFragment } from '@vegaprotocol/deal-ticket';
AccountFragment,
DealTicketMarketFragment,
} from '@vegaprotocol/deal-ticket';
import { DealTicketBalance } from './deal-ticket-balance'; import { DealTicketBalance } from './deal-ticket-balance';
import { Schema } from '@vegaprotocol/types'; import { Schema } from '@vegaprotocol/types';
import type { MarketDealTicketAsset } from '@vegaprotocol/market-list';
const tDAI: DealTicketMarketFragment['tradableInstrument']['instrument']['product']['settlementAsset'] = const tDAI: MarketDealTicketAsset = {
{ __typename: 'Asset',
__typename: 'Asset', id: '1',
id: '1', symbol: 'tDAI',
symbol: 'tDAI', name: 'TDAI',
name: 'TDAI', decimals: 2,
decimals: 2, };
};
const accounts: AccountFragment[] = [ const accounts: AccountFragment[] = [
{ {

View File

@ -1,14 +1,12 @@
import classNames from 'classnames'; import classNames from 'classnames';
import { addDecimalsFormatNumber, t } from '@vegaprotocol/react-helpers'; import { addDecimalsFormatNumber, t } from '@vegaprotocol/react-helpers';
import { Schema } from '@vegaprotocol/types'; import { Schema } from '@vegaprotocol/types';
import type { import type { AccountFragment } from '@vegaprotocol/deal-ticket';
AccountFragment, import type { MarketDealTicket } from '@vegaprotocol/market-list';
DealTicketMarketFragment,
} from '@vegaprotocol/deal-ticket';
import { useSettlementAccount } from '@vegaprotocol/deal-ticket'; import { useSettlementAccount } from '@vegaprotocol/deal-ticket';
interface DealTicketBalanceProps { interface DealTicketBalanceProps {
settlementAsset: DealTicketMarketFragment['tradableInstrument']['instrument']['product']['settlementAsset']; settlementAsset: MarketDealTicket['tradableInstrument']['instrument']['product']['settlementAsset'];
accounts: AccountFragment[]; accounts: AccountFragment[];
isWalletConnected: boolean; isWalletConnected: boolean;
className?: string; className?: string;

View File

@ -2,16 +2,21 @@ import { useParams } from 'react-router-dom';
import compact from 'lodash/compact'; import compact from 'lodash/compact';
import { import {
DealTicketManager, DealTicketManager,
DealTicketContainer as Container,
usePartyBalanceQuery, usePartyBalanceQuery,
} from '@vegaprotocol/deal-ticket'; } from '@vegaprotocol/deal-ticket';
import { Loader } from '@vegaprotocol/ui-toolkit'; import { Loader, Splash } from '@vegaprotocol/ui-toolkit';
import { t } from '@vegaprotocol/react-helpers'; import { t, useDataProvider } 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';
import Baubles from './baubles-decor'; import Baubles from './baubles-decor';
import ConnectWallet from '../wallet-connector'; import ConnectWallet from '../wallet-connector';
import { useMemo } from 'react';
import type {
MarketDataUpdateFieldsFragment,
MarketDealTicket,
} from '@vegaprotocol/market-list';
import { marketDealTicketProvider } from '@vegaprotocol/market-list';
const tempEmptyText = ( const tempEmptyText = (
<p>{t('Please select a market from the markets page')}</p> <p>{t('Please select a market from the markets page')}</p>
@ -21,52 +26,64 @@ export const DealTicketContainer = () => {
const { marketId } = useParams<{ marketId: string }>(); const { marketId } = useParams<{ marketId: string }>();
const { pubKey } = useVegaWallet(); const { pubKey } = useVegaWallet();
const { data: partyData, loading } = usePartyBalanceQuery({ const { data: partyData } = usePartyBalanceQuery({
variables: { partyId: pubKey || '' }, variables: { partyId: pubKey || '' },
skip: !pubKey, skip: !pubKey,
}); });
const variables = useMemo(
() => ({
marketId: marketId || '',
}),
[marketId]
);
const { data, loading } = useDataProvider<
MarketDealTicket,
MarketDataUpdateFieldsFragment
>({
dataProvider: marketDealTicketProvider,
variables,
skip: !marketId,
});
const accounts = compact(partyData?.party?.accountsConnection?.edges).map(
(e) => e.node
);
const loader = <Loader />; const loader = <Loader />;
if (marketId && data) {
const container = marketId ? ( const balance = (
<Container marketId={marketId}> <DealTicketBalance
{(data) => { className="mb-4"
if (!data.market) { settlementAsset={
return null as unknown as JSX.Element; data.tradableInstrument.instrument.product?.settlementAsset
} }
accounts={accounts || []}
isWalletConnected={!!pubKey}
/>
);
const accounts = compact( const container = (
partyData?.party?.accountsConnection?.edges <DealTicketManager market={data}>
).map((e) => e.node); {loading ? loader : balance}
const balance = ( <DealTicketSteps market={data} />
<DealTicketBalance </DealTicketManager>
className="mb-4" );
settlementAsset={
data.market.tradableInstrument.instrument.product?.settlementAsset
}
accounts={accounts || []}
isWalletConnected={!!pubKey}
/>
);
return ( return (
<DealTicketManager market={data.market}> <section className="flex p-4 md:p-6">
{loading ? loader : balance} <section className="w-full md:w-1/2 md:min-w-[500px]">
<DealTicketSteps market={data.market} /> {pubKey ? container : <ConnectWallet />}
</DealTicketManager> </section>
); <Baubles />
}} </section>
</Container> );
}
return marketId ? (
<Splash>
<p>{t('Could not load market')}</p>
</Splash>
) : ( ) : (
tempEmptyText tempEmptyText
); );
return (
<section className="flex p-4 md:p-6">
<section className="w-full md:w-1/2 md:min-w-[500px]">
{pubKey ? container : <ConnectWallet />}
</section>
<Baubles />
</section>
);
}; };

View File

@ -3,7 +3,6 @@ import { useNavigate } from 'react-router-dom';
import { useForm, Controller } from 'react-hook-form'; import { useForm, Controller } from 'react-hook-form';
import compact from 'lodash/compact'; import compact from 'lodash/compact';
import { Stepper } from '../stepper'; import { Stepper } from '../stepper';
import type { DealTicketMarketFragment } from '@vegaprotocol/deal-ticket';
import { import {
getDefaultOrder, getDefaultOrder,
useOrderCloseOut, useOrderCloseOut,
@ -42,9 +41,10 @@ import ReviewTrade from './review-trade';
import { Schema } from '@vegaprotocol/types'; import { Schema } from '@vegaprotocol/types';
import { DealTicketSlippage } from './deal-ticket-slippage'; import { DealTicketSlippage } from './deal-ticket-slippage';
import { useOrderValidation } from './use-order-validation'; import { useOrderValidation } from './use-order-validation';
import type { MarketDealTicket } from '@vegaprotocol/market-list';
interface DealTicketMarketProps { interface DealTicketMarketProps {
market: DealTicketMarketFragment; market: MarketDealTicket;
} }
export const DealTicketSteps = ({ market }: DealTicketMarketProps) => { export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
@ -78,10 +78,8 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
}); });
const { message: invalidText, isDisabled } = useOrderValidation({ const { message: invalidText, isDisabled } = useOrderValidation({
market, market,
orderType: order.type, order,
orderTimeInForce: order.timeInForce,
fieldErrors: errors, fieldErrors: errors,
estMargin,
}); });
const { submit, transaction, finalizedOrder, Dialog } = useOrderSubmit(); const { submit, transaction, finalizedOrder, Dialog } = useOrderSubmit();

View File

@ -5,17 +5,17 @@ import {
KeyValueTableRow, KeyValueTableRow,
} from '@vegaprotocol/ui-toolkit'; } from '@vegaprotocol/ui-toolkit';
import classNames from 'classnames'; import classNames from 'classnames';
import type { DealTicketMarketFragment } from '@vegaprotocol/deal-ticket';
import { DealTicketEstimates } from '@vegaprotocol/deal-ticket'; import { DealTicketEstimates } from '@vegaprotocol/deal-ticket';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet'; import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import { SIDE_NAMES } from './side-selector'; import { SIDE_NAMES } from './side-selector';
import { gql, useQuery } from '@apollo/client'; import { gql, useQuery } from '@apollo/client';
import { Schema } from '@vegaprotocol/types';
import { MarketExpires } from '@vegaprotocol/market-info';
import type { MarketDealTicket } from '@vegaprotocol/market-list';
import type { import type {
MarketTags, MarketTags,
MarketTagsVariables, MarketTagsVariables,
} from './__generated__/MarketTags'; } from './__generated__/MarketTags';
import { Schema } from '@vegaprotocol/types';
import { MarketExpires } from '@vegaprotocol/market-info';
export const MARKET_TAGS_QUERY = gql` export const MARKET_TAGS_QUERY = gql`
query MarketTags($marketId: ID!) { query MarketTags($marketId: ID!) {
@ -32,7 +32,7 @@ export const MARKET_TAGS_QUERY = gql`
`; `;
interface Props { interface Props {
market: DealTicketMarketFragment; market: MarketDealTicket;
isDisabled: boolean; isDisabled: boolean;
transactionStatus?: string; transactionStatus?: string;
order: OrderSubmissionBody['orderSubmission']; order: OrderSubmissionBody['orderSubmission'];

View File

@ -3,12 +3,15 @@ import { renderHook } from '@testing-library/react';
import { useVegaWallet } from '@vegaprotocol/wallet'; import { useVegaWallet } from '@vegaprotocol/wallet';
import { MockedProvider } from '@apollo/client/testing'; import { MockedProvider } from '@apollo/client/testing';
import type { VegaWalletContextShape } from '@vegaprotocol/wallet'; import type { VegaWalletContextShape } from '@vegaprotocol/wallet';
import { MarketStateMapping, Schema } from '@vegaprotocol/types'; import {
MarketStateMapping,
Schema as Types,
Schema,
} from '@vegaprotocol/types';
import type { ValidationProps } from './use-order-validation'; import type { ValidationProps } from './use-order-validation';
import { marketTranslations, useOrderValidation } from './use-order-validation'; import { marketTranslations, useOrderValidation } from './use-order-validation';
import type { DealTicketMarketFragment } from '@vegaprotocol/deal-ticket'; import type { MarketDealTicket } from '@vegaprotocol/market-list';
import * as DealTicket from '@vegaprotocol/deal-ticket'; import * as DealTicket from '@vegaprotocol/deal-ticket';
import BigNumber from 'bignumber.js';
jest.mock('@vegaprotocol/wallet'); jest.mock('@vegaprotocol/wallet');
jest.mock('@vegaprotocol/deal-ticket', () => { jest.mock('@vegaprotocol/deal-ticket', () => {
@ -19,7 +22,7 @@ jest.mock('@vegaprotocol/deal-ticket', () => {
}); });
type SettlementAsset = type SettlementAsset =
DealTicketMarketFragment['tradableInstrument']['instrument']['product']['settlementAsset']; MarketDealTicket['tradableInstrument']['instrument']['product']['settlementAsset'];
const asset: SettlementAsset = { const asset: SettlementAsset = {
__typename: 'Asset', __typename: 'Asset',
id: 'asset-id', id: 'asset-id',
@ -28,7 +31,7 @@ const asset: SettlementAsset = {
decimals: 2, decimals: 2,
}; };
const market: DealTicketMarketFragment = { const market: MarketDealTicket = {
id: 'market-id', id: 'market-id',
decimalPlaces: 2, decimalPlaces: 2,
positionDecimalPlaces: 1, positionDecimalPlaces: 1,
@ -40,10 +43,17 @@ const market: DealTicketMarketFragment = {
__typename: 'Instrument', __typename: 'Instrument',
id: 'instrument-id', id: 'instrument-id',
name: 'instrument-name', name: 'instrument-name',
code: 'instriment-code',
metadata: {
tags: [],
},
product: { product: {
__typename: 'Future', __typename: 'Future',
quoteName: 'quote-name', quoteName: 'quote-name',
settlementAsset: asset, settlementAsset: asset,
dataSourceSpecForTradingTermination: {
id: 'dataSource-id',
},
}, },
}, },
}, },
@ -63,6 +73,25 @@ const market: DealTicketMarketFragment = {
liquidityFee: '3', liquidityFee: '3',
}, },
}, },
data: {
__typename: 'MarketData',
bestBidPrice: '1605489971',
bestOfferPrice: '1606823730',
markPrice: '1606823730',
trigger: Types.AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED,
staticMidPrice: '1606156850',
marketTradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
indicativeVolume: '0',
indicativePrice: '0',
bestStaticBidPrice: '1605489971',
bestStaticOfferPrice: '1606823730',
targetStake: '8561302732',
suppliedStake: '727654170336',
auctionStart: null,
auctionEnd: null,
market: { __typename: 'Market', id: 'market-id' },
},
marketTimestamps: {},
}; };
const defaultWalletContext = { const defaultWalletContext = {
@ -75,19 +104,19 @@ const defaultWalletContext = {
connector: null, connector: null,
}; };
const order = {
type: Schema.OrderType.TYPE_MARKET,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_FOK,
marketId: 'market-id',
side: Schema.Side.SIDE_BUY,
size: '0.1',
};
const defaultOrder = { const defaultOrder = {
market, market: { ...market },
step: 0.1, step: 0.1,
orderType: Schema.OrderType.TYPE_MARKET, order: {
orderTimeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_FOK, ...order,
estMargin: {
margin: '0,000001',
totalFees: '0,000006',
fees: {
makerFee: '0,000003',
liquidityFee: '0,000002',
infrastructureFee: '0,000001',
},
}, },
}; };
@ -127,9 +156,9 @@ describe('useOrderValidation', () => {
it('Returns empty string when given valid data', () => { it('Returns empty string when given valid data', () => {
jest.spyOn(DealTicket, 'useOrderMarginValidation').mockReturnValue({ jest.spyOn(DealTicket, 'useOrderMarginValidation').mockReturnValue({
balance: new BigNumber(0), balance: '0',
margin: new BigNumber(100), margin: '100',
asset, balanceError: false,
}); });
const { result } = setup(); const { result } = setup();
@ -142,9 +171,9 @@ describe('useOrderValidation', () => {
it('Returns an error message when no keypair found', () => { it('Returns an error message when no keypair found', () => {
jest.spyOn(DealTicket, 'useOrderMarginValidation').mockReturnValue({ jest.spyOn(DealTicket, 'useOrderMarginValidation').mockReturnValue({
balance: new BigNumber(0), balance: '0',
margin: new BigNumber(100), margin: '100',
asset, balanceError: false,
}); });
const { result } = setup(defaultOrder, { pubKey: null }); const { result } = setup(defaultOrder, { pubKey: null });
expect(result.current).toStrictEqual({ expect(result.current).toStrictEqual({
@ -183,9 +212,10 @@ describe('useOrderValidation', () => {
'Returns an error message for market state suspended or pending', 'Returns an error message for market state suspended or pending',
({ state }) => { ({ state }) => {
jest.spyOn(DealTicket, 'useOrderMarginValidation').mockReturnValue({ jest.spyOn(DealTicket, 'useOrderMarginValidation').mockReturnValue({
balance: new BigNumber(0), balance: '0',
margin: new BigNumber(100), margin: '100',
asset, balanceError: false,
// asset,
}); });
const { result } = setup({ const { result } = setup({
market: { market: {
@ -193,8 +223,11 @@ describe('useOrderValidation', () => {
state, state,
tradingMode: Schema.MarketTradingMode.TRADING_MODE_BATCH_AUCTION, tradingMode: Schema.MarketTradingMode.TRADING_MODE_BATCH_AUCTION,
}, },
orderType: Schema.OrderType.TYPE_LIMIT, order: {
orderTimeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTT, ...order,
type: Schema.OrderType.TYPE_LIMIT,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTT,
},
}); });
expect(result.current).toStrictEqual({ expect(result.current).toStrictEqual({
isDisabled: false, isDisabled: false,
@ -216,7 +249,10 @@ describe('useOrderValidation', () => {
({ tradingMode, errorMessage }) => { ({ tradingMode, errorMessage }) => {
const { result } = setup({ const { result } = setup({
market: { ...defaultOrder.market, tradingMode }, market: { ...defaultOrder.market, tradingMode },
orderType: Schema.OrderType.TYPE_MARKET, order: {
...order,
type: Schema.OrderType.TYPE_MARKET,
},
}); });
expect(result.current.isDisabled).toBeTruthy(); expect(result.current.isDisabled).toBeTruthy();
expect(result.current.message).toBe(errorMessage); expect(result.current.message).toBe(errorMessage);
@ -239,8 +275,11 @@ describe('useOrderValidation', () => {
({ tradingMode, orderTimeInForce, errorMessage }) => { ({ tradingMode, orderTimeInForce, errorMessage }) => {
const { result } = setup({ const { result } = setup({
market: { ...defaultOrder.market, tradingMode }, market: { ...defaultOrder.market, tradingMode },
orderType: Schema.OrderType.TYPE_LIMIT, order: {
orderTimeInForce, ...order,
type: Schema.OrderType.TYPE_LIMIT,
timeInForce: orderTimeInForce,
},
}); });
expect(result.current).toStrictEqual({ expect(result.current).toStrictEqual({
isDisabled: true, isDisabled: true,
@ -261,7 +300,10 @@ describe('useOrderValidation', () => {
({ fieldName, errorType, section, errorMessage }) => { ({ fieldName, errorType, section, errorMessage }) => {
const { result } = setup({ const { result } = setup({
fieldErrors: { [fieldName]: { type: errorType } }, fieldErrors: { [fieldName]: { type: errorType } },
orderType: Schema.OrderType.TYPE_LIMIT, order: {
...order,
type: Schema.OrderType.TYPE_LIMIT,
},
}); });
expect(result.current).toStrictEqual({ expect(result.current).toStrictEqual({
isDisabled: true, isDisabled: true,
@ -300,9 +342,9 @@ describe('useOrderValidation', () => {
it('Returns an error message when the estimated margin is higher than collateral', async () => { it('Returns an error message when the estimated margin is higher than collateral', async () => {
const invalidatedMockValue = { const invalidatedMockValue = {
balance: new BigNumber(100), balance: '100',
margin: new BigNumber(200), margin: '200',
asset, balanceError: true,
}; };
jest jest
@ -315,9 +357,9 @@ describe('useOrderValidation', () => {
const testElement = ( const testElement = (
<DealTicket.MarginWarning <DealTicket.MarginWarning
margin={invalidatedMockValue.margin.toString()} margin={invalidatedMockValue.margin}
balance={invalidatedMockValue.balance.toString()} balance={invalidatedMockValue.balance}
asset={invalidatedMockValue.asset} asset={asset}
/> />
); );
expect((result.current.message as React.ReactElement)?.props).toEqual( expect((result.current.message as React.ReactElement)?.props).toEqual(

View File

@ -6,10 +6,6 @@ import { useVegaWallet } from '@vegaprotocol/wallet';
import { MarketStateMapping, Schema } from '@vegaprotocol/types'; import { MarketStateMapping, Schema } from '@vegaprotocol/types';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet'; import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import { Tooltip } from '@vegaprotocol/ui-toolkit'; import { Tooltip } from '@vegaprotocol/ui-toolkit';
import type {
DealTicketMarketFragment,
OrderMargin,
} from '@vegaprotocol/deal-ticket';
import { import {
MarketDataGrid, MarketDataGrid,
compileGridData, compileGridData,
@ -18,6 +14,7 @@ import {
ERROR_SIZE_DECIMAL, ERROR_SIZE_DECIMAL,
useOrderMarginValidation, useOrderMarginValidation,
} from '@vegaprotocol/deal-ticket'; } from '@vegaprotocol/deal-ticket';
import type { MarketDealTicket } from '@vegaprotocol/market-list';
export const DEAL_TICKET_SECTION = { export const DEAL_TICKET_SECTION = {
TYPE: 'sec-type', TYPE: 'sec-type',
@ -32,11 +29,9 @@ export const ERROR_EXPIRATION_IN_THE_PAST = 'ERROR_EXPIRATION_IN_THE_PAST';
export type ValidationProps = { export type ValidationProps = {
step?: number; step?: number;
market: DealTicketMarketFragment; market: MarketDealTicket;
orderType: Schema.OrderType; order: OrderSubmissionBody['orderSubmission'];
orderTimeInForce: Schema.OrderTimeInForce;
fieldErrors?: FieldErrors<OrderSubmissionBody['orderSubmission']>; fieldErrors?: FieldErrors<OrderSubmissionBody['orderSubmission']>;
estMargin: OrderMargin | null;
}; };
export const marketTranslations = (marketState: Schema.MarketState) => { export const marketTranslations = (marketState: Schema.MarketState) => {
@ -55,9 +50,7 @@ export type DealTicketSection =
export const useOrderValidation = ({ export const useOrderValidation = ({
market, market,
fieldErrors, fieldErrors,
orderType, order,
orderTimeInForce,
estMargin,
}: ValidationProps): { }: ValidationProps): {
message: ReactNode | string; message: ReactNode | string;
isDisabled: boolean; isDisabled: boolean;
@ -65,7 +58,7 @@ export const useOrderValidation = ({
} => { } => {
const { pubKey } = useVegaWallet(); const { pubKey } = useVegaWallet();
const minSize = toDecimal(market.positionDecimalPlaces); const minSize = toDecimal(market.positionDecimalPlaces);
const isInvalidOrderMargin = useOrderMarginValidation({ market, estMargin }); const isInvalidOrderMargin = useOrderMarginValidation({ market, order });
const fieldErrorChecking = useMemo<{ const fieldErrorChecking = useMemo<{
message: ReactNode | string; message: ReactNode | string;
@ -91,7 +84,7 @@ export const useOrderValidation = ({
if ( if (
fieldErrors?.price?.type === 'required' && fieldErrors?.price?.type === 'required' &&
orderType !== Schema.OrderType.TYPE_MARKET order.type !== Schema.OrderType.TYPE_MARKET
) { ) {
return { return {
isDisabled: true, isDisabled: true,
@ -102,7 +95,7 @@ export const useOrderValidation = ({
if ( if (
fieldErrors?.price?.type === 'min' && fieldErrors?.price?.type === 'min' &&
orderType !== Schema.OrderType.TYPE_MARKET order.type !== Schema.OrderType.TYPE_MARKET
) { ) {
return { return {
isDisabled: true, isDisabled: true,
@ -151,7 +144,7 @@ export const useOrderValidation = ({
fieldErrors?.price?.type, fieldErrors?.price?.type,
fieldErrors?.expiresAt?.type, fieldErrors?.expiresAt?.type,
fieldErrors?.expiresAt?.message, fieldErrors?.expiresAt?.message,
orderType, order.type,
minSize, minSize,
market.positionDecimalPlaces, market.positionDecimalPlaces,
]); ]);
@ -210,7 +203,7 @@ export const useOrderValidation = ({
} }
if (isMarketInAuction(market)) { if (isMarketInAuction(market)) {
if (orderType === Schema.OrderType.TYPE_MARKET) { if (order.type === Schema.OrderType.TYPE_MARKET) {
if ( if (
market.tradingMode === market.tradingMode ===
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION && Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION &&
@ -269,12 +262,12 @@ export const useOrderValidation = ({
}; };
} }
if ( if (
orderType === Schema.OrderType.TYPE_LIMIT && order.type === Schema.OrderType.TYPE_LIMIT &&
[ [
Schema.OrderTimeInForce.TIME_IN_FORCE_FOK, Schema.OrderTimeInForce.TIME_IN_FORCE_FOK,
Schema.OrderTimeInForce.TIME_IN_FORCE_IOC, Schema.OrderTimeInForce.TIME_IN_FORCE_IOC,
Schema.OrderTimeInForce.TIME_IN_FORCE_GFN, Schema.OrderTimeInForce.TIME_IN_FORCE_GFN,
].includes(orderTimeInForce) ].includes(order.timeInForce)
) { ) {
if ( if (
market.tradingMode === market.tradingMode ===
@ -343,17 +336,14 @@ export const useOrderValidation = ({
return fieldErrorChecking; return fieldErrorChecking;
} }
if ( if (isInvalidOrderMargin.balanceError) {
isInvalidOrderMargin.balance.isGreaterThan(0) &&
isInvalidOrderMargin.balance.isLessThan(isInvalidOrderMargin.margin)
) {
return { return {
isDisabled: false, isDisabled: false,
message: ( message: (
<MarginWarning <MarginWarning
margin={isInvalidOrderMargin.margin.toString()} margin={isInvalidOrderMargin.margin}
balance={isInvalidOrderMargin.balance.toString()} balance={isInvalidOrderMargin.balance}
asset={isInvalidOrderMargin.asset} asset={market.tradableInstrument.instrument.product.settlementAsset}
/> />
), ),
section: DEAL_TICKET_SECTION.PRICE, section: DEAL_TICKET_SECTION.PRICE,
@ -386,8 +376,8 @@ export const useOrderValidation = ({
market, market,
fieldErrorChecking, fieldErrorChecking,
isInvalidOrderMargin, isInvalidOrderMargin,
orderType, order.type,
orderTimeInForce, order.timeInForce,
]); ]);
return { message, isDisabled, section }; return { message, isDisabled, section };

View File

@ -499,6 +499,7 @@ describe('deal ticket size validation', { tags: '@smoke' }, function () {
describe('limit order validations', { tags: '@smoke' }, () => { describe('limit order validations', { tags: '@smoke' }, () => {
before(() => { before(() => {
cy.mockTradingPage(); cy.mockTradingPage();
cy.mockGQLSubscription();
cy.visit('/#/markets/market-0'); cy.visit('/#/markets/market-0');
connectVegaWallet(); connectVegaWallet();
cy.wait('@Market'); cy.wait('@Market');
@ -634,6 +635,7 @@ describe('suspended market validation', { tags: '@regression' }, () => {
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION, Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY
); );
cy.mockGQLSubscription();
cy.visit('/#/markets/market-0'); cy.visit('/#/markets/market-0');
cy.wait('@Market'); cy.wait('@Market');
connectVegaWallet(); connectVegaWallet();
@ -682,11 +684,15 @@ describe('account validation', { tags: '@regression' }, () => {
'EstimateOrder', 'EstimateOrder',
generateEstimateOrder({ generateEstimateOrder({
estimateOrder: { estimateOrder: {
marginLevels: { __typename: 'MarginLevels', initialLevel: '1000' }, marginLevels: {
__typename: 'MarginLevels',
initialLevel: '1000000000',
},
}, },
}) })
); );
}); });
cy.mockGQLSubscription();
cy.visit('/#/markets/market-0'); cy.visit('/#/markets/market-0');
connectVegaWallet(); connectVegaWallet();
cy.wait('@Market'); cy.wait('@Market');
@ -712,7 +718,7 @@ describe('account validation', { tags: '@regression' }, () => {
); );
cy.getByTestId('dealticket-warning-margin').should( cy.getByTestId('dealticket-warning-margin').should(
'contain.text', 'contain.text',
'0.01 tBTC currently required, 0.001 tBTC available' '10,000 tBTC currently required, 1,000 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

@ -101,6 +101,19 @@ export const generateAccounts = (
}, },
}, },
}, },
{
__typename: 'AccountEdge',
node: {
__typename: 'AccountBalance',
type: Schema.AccountType.ACCOUNT_TYPE_GENERAL,
balance: '100000000',
market: null,
asset: {
__typename: 'Asset',
id: '5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c',
},
},
},
], ],
}, },
}, },

View File

@ -164,6 +164,30 @@ export const generateAssets = (override?: PartialDeep<AssetsQuery>) => {
__typename: 'Asset', __typename: 'Asset',
}, },
}, },
{
node: {
id: '5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c',
symbol: 'tBTC',
decimals: 5,
name: 'tBTC TEST',
source: {
maxFaucetAmountMint: '5000000000',
__typename: 'BuiltinAsset',
},
quantum: '1',
status: Types.AssetStatus.STATUS_ENABLED,
infrastructureFeeAccount: {
balance: '0',
__typename: 'AccountBalance',
},
globalRewardPoolAccount: null,
takerFeeRewardAccount: null,
makerFeeRewardAccount: null,
lpFeeRewardAccount: null,
marketProposerRewardAccount: null,
__typename: 'Asset',
},
},
// NOTE: These assets ids and contract addresses are real assets on Sepolia, this is needed // NOTE: These assets ids and contract addresses are real assets on Sepolia, this is needed
// because we don't currently mock our seplia infura provider. If we change network these will // because we don't currently mock our seplia infura provider. If we change network these will
// need to be updated // need to be updated

View File

@ -1,54 +0,0 @@
import type { DealTicketQuery } from '@vegaprotocol/deal-ticket';
import { Schema } from '@vegaprotocol/types';
import merge from 'lodash/merge';
import type { PartialDeep } from 'type-fest';
export const generateDealTicketQuery = (
override?: PartialDeep<DealTicketQuery>
): DealTicketQuery => {
const defaultResult: DealTicketQuery = {
market: {
__typename: 'Market',
id: 'market-0',
decimalPlaces: 5,
positionDecimalPlaces: 0,
state: Schema.MarketState.STATE_ACTIVE,
tradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
fees: {
factors: {
makerFee: '0.0002',
infrastructureFee: '0.0005',
liquidityFee: '0.0005',
},
},
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
id: 'tBTC TEST',
name: 'ETHBTC Quarterly (30 Jun 2022)',
product: {
__typename: 'Future',
quoteName: 'BTC',
settlementAsset: {
__typename: 'Asset',
id: '5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c',
symbol: 'tBTC',
name: 'tBTC TEST',
decimals: 5,
},
},
},
},
depth: {
__typename: 'MarketDepth',
lastTrade: {
__typename: 'Trade',
price: '100',
},
},
},
};
return merge(defaultResult, override);
};

View File

@ -13,7 +13,7 @@ export const generateMarket = (
const defaultResult: MarketQuery = { const defaultResult: MarketQuery = {
market: { market: {
id: 'market-0', id: 'market-0',
tradingMode: Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION, tradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
state: Schema.MarketState.STATE_ACTIVE, state: Schema.MarketState.STATE_ACTIVE,
decimalPlaces: 5, decimalPlaces: 5,
positionDecimalPlaces: 0, positionDecimalPlaces: 0,
@ -38,12 +38,12 @@ export const generateMarket = (
id: 'd253c16c6a17ab88e098479635c611ab503582a1079752d1a49ac15f656f7e7b', id: 'd253c16c6a17ab88e098479635c611ab503582a1079752d1a49ac15f656f7e7b',
__typename: 'DataSourceSpec', __typename: 'DataSourceSpec',
}, },
quoteName: 'BTCUSD Monthly', quoteName: 'BTC',
settlementAsset: { settlementAsset: {
decimals: 0, decimals: 5,
id: '000', id: '5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c',
symbol: 'USD', symbol: 'tBTC',
name: 'United States Dollar', name: 'tBTC TEST',
__typename: 'Asset', __typename: 'Asset',
}, },
__typename: 'Future', __typename: 'Future',
@ -61,12 +61,16 @@ export const generateMarket = (
__typename: 'Fees', __typename: 'Fees',
factors: { factors: {
__typename: 'FeeFactors', __typename: 'FeeFactors',
makerFee: '', makerFee: '0.0002',
infrastructureFee: '', infrastructureFee: '0.0005',
liquidityFee: '', liquidityFee: '0.0005',
}, },
}, },
__typename: 'Market', __typename: 'Market',
depth: {
__typename: 'MarketDepth',
lastTrade: { price: '100', __typename: 'Trade' },
},
}, },
}; };

View File

@ -6,7 +6,6 @@ import { generateAsset, generateAssets } from './mocks/generate-assets';
import { generateCandles } from './mocks/generate-candles'; import { generateCandles } from './mocks/generate-candles';
import { generateChainId } from './mocks/generate-chain-id'; import { generateChainId } from './mocks/generate-chain-id';
import { generateChart } from './mocks/generate-chart'; import { generateChart } from './mocks/generate-chart';
import { generateDealTicketQuery } from './mocks/generate-deal-ticket-query';
import { generateMarket, generateMarketData } from './mocks/generate-market'; import { generateMarket, generateMarketData } from './mocks/generate-market';
import { generateMarketDepth } from './mocks/generate-market-depth'; import { generateMarketDepth } from './mocks/generate-market-depth';
import { generateMarketInfoQuery } from './mocks/generate-market-info-query'; import { generateMarketInfoQuery } from './mocks/generate-market-info-query';
@ -48,6 +47,7 @@ const mockTradingPage = (
}, },
}, },
state: state, state: state,
tradingMode: tradingMode,
}, },
}) })
); );
@ -69,19 +69,6 @@ const mockTradingPage = (
aliasQuery(req, 'Accounts', generateAccounts()); aliasQuery(req, 'Accounts', generateAccounts());
aliasQuery(req, 'Positions', generatePositions()); aliasQuery(req, 'Positions', generatePositions());
aliasQuery(req, 'Margins', generateMargins()); aliasQuery(req, 'Margins', generateMargins());
aliasQuery(
req,
'DealTicket',
generateDealTicketQuery({
market: {
state,
tradingMode: tradingMode,
data: {
trigger: trigger,
},
},
})
);
aliasQuery(req, 'Assets', generateAssets()); aliasQuery(req, 'Assets', generateAssets());
aliasQuery(req, 'Asset', generateAsset()); aliasQuery(req, 'Asset', generateAsset());

View File

@ -1,6 +1,6 @@
import { useCallback, useMemo, useState } from 'react'; import { useCallback, useMemo, useState } from 'react';
import { t, useDataProvider } from '@vegaprotocol/react-helpers'; import { t, useDataProvider } from '@vegaprotocol/react-helpers';
import type { DealTicketMarketFragment } from '@vegaprotocol/deal-ticket'; import type { MarketDealTicket } from '@vegaprotocol/market-list';
import { compileGridData, TradingModeTooltip } from '@vegaprotocol/deal-ticket'; import { compileGridData, TradingModeTooltip } from '@vegaprotocol/deal-ticket';
import type { Schema as Types } from '@vegaprotocol/types'; import type { Schema as Types } from '@vegaprotocol/types';
import { import {
@ -21,13 +21,11 @@ interface Props {
onSelect?: (marketId: string) => void; onSelect?: (marketId: string) => void;
} }
type TradingModeMarket = Omit<DealTicketMarketFragment, 'depth'>;
export const MarketTradingModeComponent = ({ marketId, onSelect }: Props) => { export const MarketTradingModeComponent = ({ marketId, onSelect }: Props) => {
const [tradingMode, setTradingMode] = const [tradingMode, setTradingMode] =
useState<Types.MarketTradingMode | null>(null); useState<Types.MarketTradingMode | null>(null);
const [trigger, setTrigger] = useState<Types.AuctionTrigger | null>(null); const [trigger, setTrigger] = useState<Types.AuctionTrigger | null>(null);
const [market, setMarket] = useState<TradingModeMarket | null>(null); const [market, setMarket] = useState<MarketDealTicket | null>(null);
const variables = useMemo( const variables = useMemo(
() => ({ () => ({
marketId: marketId, marketId: marketId,
@ -49,7 +47,7 @@ export const MarketTradingModeComponent = ({ marketId, onSelect }: Props) => {
setMarket({ setMarket({
...data, ...data,
data: marketData, data: marketData,
} as TradingModeMarket); } as MarketDealTicket);
} }
return true; return true;
}, },

View File

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

View File

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

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 { getSettlementAccount } from './get-settlement-account';
export const useAccountBalance = (assetId: 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 = getSettlementAccount({ accounts: data, assetId });
if (accountBalance !== account?.balance) {
setAccountBalance(account?.balance || '');
}
if (accountDecimals !== account?.asset.decimals) {
setAccountDecimals(account?.asset.decimals || null);
}
return true;
},
[accountBalance, accountDecimals, assetId]
);
useDataProvider({
dataProvider: accountsDataProvider,
variables,
skip: !pubKey || !assetId,
update,
});
return useMemo(
() => ({
accountBalance,
accountDecimals,
}),
[accountBalance, accountDecimals]
);
};

View File

@ -1,54 +0,0 @@
fragment DealTicketMarket on Market {
id
decimalPlaces
positionDecimalPlaces
state
tradingMode
data {
market {
id
}
indicativePrice
indicativeVolume
targetStake
suppliedStake
auctionStart
auctionEnd
trigger
}
fees {
factors {
makerFee
infrastructureFee
liquidityFee
}
}
tradableInstrument {
instrument {
id
name
product {
... on Future {
quoteName
settlementAsset {
id
symbol
decimals
name
}
}
}
}
}
depth {
lastTrade {
price
}
}
}
query DealTicket($marketId: ID!) {
market(id: $marketId) {
...DealTicketMarket
}
}

View File

@ -1,99 +0,0 @@
import { Schema as Types } from '@vegaprotocol/types';
import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
export type DealTicketMarketFragment = { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradingMode: Types.MarketTradingMode, data?: { __typename?: 'MarketData', indicativePrice: string, indicativeVolume: string, targetStake?: string | null, suppliedStake?: string | null, auctionStart?: string | null, auctionEnd?: string | null, trigger: Types.AuctionTrigger, market: { __typename?: 'Market', id: string } } | null, fees: { __typename?: 'Fees', factors: { __typename?: 'FeeFactors', makerFee: string, infrastructureFee: string, liquidityFee: string } }, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', id: string, name: string, product: { __typename?: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', id: string, symbol: string, decimals: number, name: string } } } }, depth: { __typename?: 'MarketDepth', lastTrade?: { __typename?: 'Trade', price: string } | null } };
export type DealTicketQueryVariables = Types.Exact<{
marketId: Types.Scalars['ID'];
}>;
export type DealTicketQuery = { __typename?: 'Query', market?: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradingMode: Types.MarketTradingMode, data?: { __typename?: 'MarketData', indicativePrice: string, indicativeVolume: string, targetStake?: string | null, suppliedStake?: string | null, auctionStart?: string | null, auctionEnd?: string | null, trigger: Types.AuctionTrigger, market: { __typename?: 'Market', id: string } } | null, fees: { __typename?: 'Fees', factors: { __typename?: 'FeeFactors', makerFee: string, infrastructureFee: string, liquidityFee: string } }, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', id: string, name: string, product: { __typename?: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', id: string, symbol: string, decimals: number, name: string } } } }, depth: { __typename?: 'MarketDepth', lastTrade?: { __typename?: 'Trade', price: string } | null } } | null };
export const DealTicketMarketFragmentDoc = gql`
fragment DealTicketMarket on Market {
id
decimalPlaces
positionDecimalPlaces
state
tradingMode
data {
market {
id
}
indicativePrice
indicativeVolume
targetStake
suppliedStake
auctionStart
auctionEnd
trigger
}
fees {
factors {
makerFee
infrastructureFee
liquidityFee
}
}
tradableInstrument {
instrument {
id
name
product {
... on Future {
quoteName
settlementAsset {
id
symbol
decimals
name
}
}
}
}
}
depth {
lastTrade {
price
}
}
}
`;
export const DealTicketDocument = gql`
query DealTicket($marketId: ID!) {
market(id: $marketId) {
...DealTicketMarket
}
}
${DealTicketMarketFragmentDoc}`;
/**
* __useDealTicketQuery__
*
* To run a query within a React component, call `useDealTicketQuery` and pass it any options that fit your needs.
* When your component renders, `useDealTicketQuery` 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 } = useDealTicketQuery({
* variables: {
* marketId: // value for 'marketId'
* },
* });
*/
export function useDealTicketQuery(baseOptions: Apollo.QueryHookOptions<DealTicketQuery, DealTicketQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<DealTicketQuery, DealTicketQueryVariables>(DealTicketDocument, options);
}
export function useDealTicketLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<DealTicketQuery, DealTicketQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<DealTicketQuery, DealTicketQueryVariables>(DealTicketDocument, options);
}
export type DealTicketQueryHookResult = ReturnType<typeof useDealTicketQuery>;
export type DealTicketLazyQueryHookResult = ReturnType<typeof useDealTicketLazyQuery>;
export type DealTicketQueryResult = Apollo.QueryResult<DealTicketQuery, DealTicketQueryVariables>;

View File

@ -1,13 +1,13 @@
import type { UseFormRegister } from 'react-hook-form'; import type { UseFormRegister } from 'react-hook-form';
import type { MarketDealTicket } from '@vegaprotocol/market-list';
import { DealTicketMarketAmount } from './deal-ticket-market-amount'; import { DealTicketMarketAmount } from './deal-ticket-market-amount';
import { DealTicketLimitAmount } from './deal-ticket-limit-amount'; import { DealTicketLimitAmount } from './deal-ticket-limit-amount';
import type { DealTicketMarketFragment } from './__generated__/DealTicket';
import { Schema } from '@vegaprotocol/types'; import { Schema } from '@vegaprotocol/types';
import type { DealTicketFormFields } from './deal-ticket'; import type { DealTicketFormFields } from './deal-ticket';
export interface DealTicketAmountProps { export interface DealTicketAmountProps {
orderType: Schema.OrderType; orderType: Schema.OrderType;
market: DealTicketMarketFragment; market: MarketDealTicket;
register: UseFormRegister<DealTicketFormFields>; register: UseFormRegister<DealTicketFormFields>;
sizeError?: string; sizeError?: string;
priceError?: string; priceError?: string;

View File

@ -1,30 +1,41 @@
import { useMemo } from 'react';
import { AsyncRenderer, Splash } from '@vegaprotocol/ui-toolkit'; import { AsyncRenderer, Splash } from '@vegaprotocol/ui-toolkit';
import { t, useDataProvider } from '@vegaprotocol/react-helpers';
import type {
MarketDataUpdateFieldsFragment,
MarketDealTicket,
} from '@vegaprotocol/market-list';
import { marketDealTicketProvider } from '@vegaprotocol/market-list';
import { DealTicketManager } from './deal-ticket-manager'; import { DealTicketManager } from './deal-ticket-manager';
import { t } from '@vegaprotocol/react-helpers';
import { useDealTicketQuery } from './__generated__/DealTicket';
import type { DealTicketQuery } from './__generated__/DealTicket';
export interface DealTicketContainerProps { export interface DealTicketContainerProps {
marketId: string; marketId: string;
children?(props: DealTicketQuery): JSX.Element;
} }
export const DealTicketContainer = ({ export const DealTicketContainer = ({ marketId }: DealTicketContainerProps) => {
marketId, const variables = useMemo(
children, () => ({
}: DealTicketContainerProps) => { marketId: marketId || '',
const { data, loading, error } = useDealTicketQuery({ }),
variables: { marketId }, [marketId]
);
const { data, error, loading } = useDataProvider<
MarketDealTicket,
MarketDataUpdateFieldsFragment
>({
dataProvider: marketDealTicketProvider,
variables,
skip: !marketId,
}); });
return ( return (
<AsyncRenderer<DealTicketQuery> data={data} loading={loading} error={error}> <AsyncRenderer<MarketDealTicket>
{data && data.market ? ( data={data || undefined}
children ? ( loading={loading}
children(data) error={error}
) : ( >
<DealTicketManager market={data.market} /> {data ? (
) <DealTicketManager market={data} />
) : ( ) : (
<Splash> <Splash>
<p>{t('Could not load market')}</p> <p>{t('Could not load market')}</p>

View File

@ -1,9 +1,15 @@
import { Tooltip } from '@vegaprotocol/ui-toolkit'; import { Tooltip } from '@vegaprotocol/ui-toolkit';
import type { ReactNode } from 'react'; import type { ReactNode } from 'react';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import type { MarketDealTicket } from '@vegaprotocol/market-list';
import {
getFeeDetailsValues,
useFeeDealTicketDetails,
} from '../../hooks/use-fee-deal-ticket-details';
interface DealTicketFeeDetailsProps { interface DealTicketFeeDetailsProps {
details: DealTicketFeeDetails[]; order: OrderSubmissionBody['orderSubmission'];
market: MarketDealTicket;
} }
export interface DealTicketFeeDetails { export interface DealTicketFeeDetails {
@ -14,8 +20,11 @@ export interface DealTicketFeeDetails {
} }
export const DealTicketFeeDetails = ({ export const DealTicketFeeDetails = ({
details, order,
market,
}: DealTicketFeeDetailsProps) => { }: DealTicketFeeDetailsProps) => {
const feeDetails = useFeeDealTicketDetails(order, market);
const details = getFeeDetailsValues(feeDetails);
return ( return (
<div> <div>
{details.map(({ label, value, labelDescription, quoteName }) => ( {details.map(({ label, value, labelDescription, quoteName }) => (

View File

@ -1,14 +1,14 @@
import type { ReactNode } from 'react'; import type { ReactNode } from 'react';
import { VegaTxStatus } from '@vegaprotocol/wallet'; import { VegaTxStatus } from '@vegaprotocol/wallet';
import { DealTicket } from './deal-ticket'; import { DealTicket } from './deal-ticket';
import type { DealTicketMarketFragment } from './__generated__/DealTicket'; import type { MarketDealTicket } from '@vegaprotocol/market-list';
import { useOrderSubmit, OrderFeedback } from '@vegaprotocol/orders'; import { useOrderSubmit, OrderFeedback } from '@vegaprotocol/orders';
import { Schema } from '@vegaprotocol/types'; import { Schema } from '@vegaprotocol/types';
import { Icon, Intent } from '@vegaprotocol/ui-toolkit'; import { Icon, Intent } from '@vegaprotocol/ui-toolkit';
import { t } from '@vegaprotocol/react-helpers'; import { t } from '@vegaprotocol/react-helpers';
export interface DealTicketManagerProps { export interface DealTicketManagerProps {
market: DealTicketMarketFragment; market: MarketDealTicket;
children?: ReactNode | ReactNode[]; children?: ReactNode | ReactNode[];
} }

View File

@ -34,7 +34,7 @@ export const DealTicketMarketAmount = ({
price = market.data.indicativePrice; price = market.data.indicativePrice;
} }
} else { } else {
price = market.depth.lastTrade?.price; price = market.depth?.lastTrade?.price;
} }
const priceFormatted = price const priceFormatted = price

View File

@ -1,8 +1,8 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import { VegaWalletContext } from '@vegaprotocol/wallet'; import { VegaWalletContext } from '@vegaprotocol/wallet';
import { fireEvent, render, screen, act } from '@testing-library/react'; import { fireEvent, render, screen, act } from '@testing-library/react';
import type { MarketDealTicket } from '@vegaprotocol/market-list';
import { DealTicket } from './deal-ticket'; import { DealTicket } from './deal-ticket';
import type { DealTicketMarketFragment } from './__generated__/DealTicket';
import { Schema } from '@vegaprotocol/types'; import { Schema } from '@vegaprotocol/types';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet'; import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import type { MockedResponse } from '@apollo/client/testing'; import type { MockedResponse } from '@apollo/client/testing';
@ -10,7 +10,7 @@ import { MockedProvider } from '@apollo/client/testing';
import type { ChainIdQuery } from '@vegaprotocol/react-helpers'; import type { ChainIdQuery } from '@vegaprotocol/react-helpers';
import { ChainIdDocument, addDecimal } from '@vegaprotocol/react-helpers'; import { ChainIdDocument, addDecimal } from '@vegaprotocol/react-helpers';
const market: DealTicketMarketFragment = { const market = {
__typename: 'Market', __typename: 'Market',
id: 'market-id', id: 'market-id',
decimalPlaces: 2, decimalPlaces: 2,
@ -50,7 +50,7 @@ const market: DealTicketMarketFragment = {
price: '100', price: '100',
}, },
}, },
}; } as MarketDealTicket;
const submit = jest.fn(); const submit = jest.fn();
const transactionStatus = 'default'; const transactionStatus = 'default';
@ -109,7 +109,7 @@ describe('DealTicket', () => {
// Assert last price is shown // Assert last price is shown
expect(screen.getByTestId('last-price')).toHaveTextContent( expect(screen.getByTestId('last-price')).toHaveTextContent(
// eslint-disable-next-line // eslint-disable-next-line
`~${addDecimal(market.depth.lastTrade!.price, market.decimalPlaces)} ${ `~${addDecimal(market!.depth!.lastTrade!.price, market.decimalPlaces)} ${
market.tradableInstrument.instrument.product.settlementAsset.symbol market.tradableInstrument.instrument.product.settlementAsset.symbol
}` }`
); );

View File

@ -2,11 +2,6 @@ import { removeDecimal, t } from '@vegaprotocol/react-helpers';
import { Schema } from '@vegaprotocol/types'; import { Schema } from '@vegaprotocol/types';
import { memo, useCallback, useEffect } from 'react'; import { memo, useCallback, useEffect } from 'react';
import { Controller, useForm } from 'react-hook-form'; import { Controller, useForm } from 'react-hook-form';
import {
getFeeDetailsValues,
useFeeDealTicketDetails,
} from '../../hooks/use-fee-deal-ticket-details';
import { DealTicketAmount } from './deal-ticket-amount'; import { DealTicketAmount } from './deal-ticket-amount';
import { DealTicketButton } from './deal-ticket-button'; import { DealTicketButton } from './deal-ticket-button';
import { DealTicketFeeDetails } from './deal-ticket-fee-details'; import { DealTicketFeeDetails } from './deal-ticket-fee-details';
@ -14,8 +9,6 @@ import { ExpirySelector } from './expiry-selector';
import { SideSelector } from './side-selector'; import { SideSelector } from './side-selector';
import { TimeInForceSelector } from './time-in-force-selector'; import { TimeInForceSelector } from './time-in-force-selector';
import { TypeSelector } from './type-selector'; import { TypeSelector } from './type-selector';
import type { DealTicketMarketFragment } from './__generated__/DealTicket';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet'; import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import { useVegaWallet } from '@vegaprotocol/wallet'; import { useVegaWallet } from '@vegaprotocol/wallet';
import { InputError } from '@vegaprotocol/ui-toolkit'; import { InputError } from '@vegaprotocol/ui-toolkit';
@ -31,12 +24,13 @@ import {
} from '../../utils'; } from '../../utils';
import { ZeroBalanceError } from '../deal-ticket-validation/zero-balance-error'; import { ZeroBalanceError } from '../deal-ticket-validation/zero-balance-error';
import { AccountValidationType } from '../../constants'; import { AccountValidationType } from '../../constants';
import type BigNumber from 'bignumber.js'; import { useHasNoBalance } from '../../hooks/use-has-no-balance';
import type { MarketDealTicket } from '@vegaprotocol/market-list';
export type TransactionStatus = 'default' | 'pending'; export type TransactionStatus = 'default' | 'pending';
export interface DealTicketProps { export interface DealTicketProps {
market: DealTicketMarketFragment; market: MarketDealTicket;
submit: (order: OrderSubmissionBody['orderSubmission']) => void; submit: (order: OrderSubmissionBody['orderSubmission']) => void;
transactionStatus: TransactionStatus; transactionStatus: TransactionStatus;
defaultOrder?: OrderSubmissionBody['orderSubmission']; defaultOrder?: OrderSubmissionBody['orderSubmission'];
@ -67,17 +61,11 @@ export const DealTicket = ({
}); });
const order = watch(); const order = watch();
const feeDetails = useFeeDealTicketDetails(order, market);
const details = getFeeDetailsValues(feeDetails);
// When order state changes persist it in local storage // When order state changes persist it in local storage
useEffect(() => setPersistedOrder(order), [order, setPersistedOrder]); useEffect(() => setPersistedOrder(order), [order, setPersistedOrder]);
const hasNoBalance = useHasNoBalance(
const accountData = useOrderMarginValidation({ market.tradableInstrument.instrument.product.settlementAsset.id
market, );
estMargin: feeDetails.estMargin,
});
const onSubmit = useCallback( const onSubmit = useCallback(
(order: OrderSubmissionBody['orderSubmission']) => { (order: OrderSubmissionBody['orderSubmission']) => {
if (!pubKey) { if (!pubKey) {
@ -91,7 +79,7 @@ export const DealTicket = ({
return; return;
} }
if (accountData.balance.isZero()) { if (hasNoBalance) {
setError('summary', { message: AccountValidationType.NoCollateral }); setError('summary', { message: AccountValidationType.NoCollateral });
return; return;
} }
@ -117,7 +105,7 @@ export const DealTicket = ({
[ [
submit, submit,
pubKey, pubKey,
accountData, hasNoBalance,
market.positionDecimalPlaces, market.positionDecimalPlaces,
market.decimalPlaces, market.decimalPlaces,
market.state, market.state,
@ -195,9 +183,9 @@ export const DealTicket = ({
<SummaryMessage <SummaryMessage
errorMessage={errors.summary?.message} errorMessage={errors.summary?.message}
market={market} market={market}
accountData={accountData} order={order}
/> />
<DealTicketFeeDetails details={details} /> <DealTicketFeeDetails order={order} market={market} />
</form> </form>
); );
}; };
@ -208,22 +196,18 @@ export const DealTicket = ({
*/ */
interface SummaryMessageProps { interface SummaryMessageProps {
errorMessage?: string; errorMessage?: string;
market: DealTicketMarketFragment; market: MarketDealTicket;
accountData: { order: OrderSubmissionBody['orderSubmission'];
balance: BigNumber;
margin: BigNumber;
asset: {
id: string;
symbol: string;
decimals: number;
name: string;
};
};
} }
const SummaryMessage = memo( const SummaryMessage = memo(
({ errorMessage, market, accountData }: SummaryMessageProps) => { ({ errorMessage, market, order }: SummaryMessageProps) => {
// Specific error UI for if balance is so we can // Specific error UI for if balance is so we can
// render a deposit dialog // render a deposit dialog
const asset = market.tradableInstrument.instrument.product.settlementAsset;
const { balanceError, balance, margin } = useOrderMarginValidation({
market,
order,
});
if (errorMessage === AccountValidationType.NoCollateral) { if (errorMessage === AccountValidationType.NoCollateral) {
return ( return (
<ZeroBalanceError <ZeroBalanceError
@ -246,17 +230,8 @@ const SummaryMessage = memo(
// If there is no blocking error but user doesn't have enough // If there is no blocking error but user doesn't have enough
// balance render the margin warning, but still allow submission // balance render the margin warning, but still allow submission
if ( if (balanceError) {
accountData.balance.isGreaterThan(0) && return <MarginWarning balance={balance} margin={margin} asset={asset} />;
accountData.balance.isLessThan(accountData.margin)
) {
return (
<MarginWarning
balance={accountData.balance.toString()}
margin={accountData.margin.toString()}
asset={accountData.asset}
/>
);
} }
// Show auction mode warning // Show auction mode warning

View File

@ -1,4 +1,3 @@
export * from './__generated__/DealTicket';
export * from './deal-ticket-amount'; export * from './deal-ticket-amount';
export * from './deal-ticket-container'; export * from './deal-ticket-container';
export * from './deal-ticket-limit-amount'; export * from './deal-ticket-limit-amount';

View File

@ -8,7 +8,6 @@ import React, {
} from 'react'; } from 'react';
import * as DialogPrimitives from '@radix-ui/react-dialog'; import * as DialogPrimitives from '@radix-ui/react-dialog';
import classNames from 'classnames'; import classNames from 'classnames';
import type { DealTicketMarketFragment } from './';
import { import {
ButtonLink, ButtonLink,
Icon, Icon,
@ -25,10 +24,11 @@ import {
import { IconNames } from '@blueprintjs/icons'; import { IconNames } from '@blueprintjs/icons';
import { Schema } from '@vegaprotocol/types'; import { Schema } from '@vegaprotocol/types';
import type { Market } from '@vegaprotocol/market-list'; import type { Market } from '@vegaprotocol/market-list';
import type { MarketDealTicket } from '@vegaprotocol/market-list';
import { marketsProvider } from '@vegaprotocol/market-list'; import { marketsProvider } from '@vegaprotocol/market-list';
interface Props { interface Props {
market: DealTicketMarketFragment; market: MarketDealTicket;
setMarket: (marketId: string) => void; setMarket: (marketId: string) => void;
ItemRenderer?: React.FC<{ ItemRenderer?: React.FC<{
market: Market; market: Market;

View File

@ -8,7 +8,7 @@ import {
import { Schema } from '@vegaprotocol/types'; import { Schema } from '@vegaprotocol/types';
import { t } from '@vegaprotocol/react-helpers'; import { t } from '@vegaprotocol/react-helpers';
import { timeInForceLabel } from '@vegaprotocol/orders'; import { timeInForceLabel } from '@vegaprotocol/orders';
import type { DealTicketMarketFragment } from './__generated__/DealTicket'; import type { MarketDealTicket } from '@vegaprotocol/market-list';
import { compileGridData, MarketDataGrid } from '../trading-mode-tooltip'; import { compileGridData, MarketDataGrid } from '../trading-mode-tooltip';
import { MarketModeValidationType } from '../../constants'; import { MarketModeValidationType } from '../../constants';
@ -16,7 +16,7 @@ interface TimeInForceSelectorProps {
value: Schema.OrderTimeInForce; value: Schema.OrderTimeInForce;
orderType: Schema.OrderType; orderType: Schema.OrderType;
onSelect: (tif: Schema.OrderTimeInForce) => void; onSelect: (tif: Schema.OrderTimeInForce) => void;
market: DealTicketMarketFragment; market: MarketDealTicket;
errorMessage?: string; errorMessage?: string;
} }

View File

@ -2,14 +2,14 @@ import { FormGroup, InputError, Tooltip } from '@vegaprotocol/ui-toolkit';
import { t } from '@vegaprotocol/react-helpers'; import { t } from '@vegaprotocol/react-helpers';
import { Schema } from '@vegaprotocol/types'; import { Schema } from '@vegaprotocol/types';
import { Toggle } from '@vegaprotocol/ui-toolkit'; import { Toggle } from '@vegaprotocol/ui-toolkit';
import type { MarketDealTicket } from '@vegaprotocol/market-list';
import { compileGridData, MarketDataGrid } from '../trading-mode-tooltip'; import { compileGridData, MarketDataGrid } from '../trading-mode-tooltip';
import type { DealTicketMarketFragment } from './__generated__/DealTicket';
import { MarketModeValidationType } from '../../constants'; import { MarketModeValidationType } from '../../constants';
interface TypeSelectorProps { interface TypeSelectorProps {
value: Schema.OrderType; value: Schema.OrderType;
onSelect: (type: Schema.OrderType) => void; onSelect: (type: Schema.OrderType) => void;
market: DealTicketMarketFragment; market: MarketDealTicket;
errorMessage?: string; errorMessage?: string;
} }

View File

@ -7,11 +7,11 @@ import { Schema } from '@vegaprotocol/types';
import { Link as UILink } from '@vegaprotocol/ui-toolkit'; import { Link as UILink } from '@vegaprotocol/ui-toolkit';
import type { ReactNode } from 'react'; import type { ReactNode } from 'react';
import type { MarketDataGridProps } from './market-data-grid'; import type { MarketDataGridProps } from './market-data-grid';
import type { DealTicketMarketFragment } from '../deal-ticket/__generated__/DealTicket';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import type { MarketDealTicket } from '@vegaprotocol/market-list';
export const compileGridData = ( export const compileGridData = (
market: Omit<DealTicketMarketFragment, 'depth'>, market: MarketDealTicket,
onSelect?: (id: string) => void onSelect?: (id: string) => void
): { label: ReactNode; value?: ReactNode }[] => { ): { label: ReactNode; value?: ReactNode }[] => {
const grid: MarketDataGridProps['grid'] = []; const grid: MarketDataGridProps['grid'] = [];

View File

@ -8,7 +8,8 @@ import { Schema } from '@vegaprotocol/types';
import { useVegaWallet } from '@vegaprotocol/wallet'; import { useVegaWallet } from '@vegaprotocol/wallet';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import { useMemo } from 'react'; import { useMemo } from 'react';
import type { MarketDealTicket } from '@vegaprotocol/market-list';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import { import {
EST_CLOSEOUT_TOOLTIP_TEXT, EST_CLOSEOUT_TOOLTIP_TEXT,
EST_MARGIN_TOOLTIP_TEXT, EST_MARGIN_TOOLTIP_TEXT,
@ -18,21 +19,18 @@ 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';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import type { DealTicketMarketFragment } from '../components';
import type { OrderMargin } from './use-order-margin'; import type { OrderMargin } from './use-order-margin';
export const useFeeDealTicketDetails = ( export const useFeeDealTicketDetails = (
order: OrderSubmissionBody['orderSubmission'], order: OrderSubmissionBody['orderSubmission'],
market: DealTicketMarketFragment market: MarketDealTicket
) => { ) => {
const { pubKey } = useVegaWallet(); const { pubKey } = useVegaWallet();
const slippage = useCalculateSlippage({ marketId: market.id, order }); const slippage = useCalculateSlippage({ marketId: market.id, order });
const price = useMemo(() => { const price = useMemo(() => {
const estPrice = order.price || market.depth.lastTrade?.price; const estPrice = order.price || market.depth?.lastTrade?.price;
if (estPrice) { if (estPrice) {
if (slippage && parseFloat(slippage) !== 0) { if (slippage && parseFloat(slippage) !== 0) {
const isLong = order.side === Schema.Side.SIDE_BUY; const isLong = order.side === Schema.Side.SIDE_BUY;
@ -44,7 +42,7 @@ export const useFeeDealTicketDetails = (
return order.price; return order.price;
} }
return null; return null;
}, [market.depth.lastTrade?.price, order.price, order.side, slippage]); }, [market.depth?.lastTrade?.price, order.price, order.side, slippage]);
const estMargin: OrderMargin | null = useOrderMargin({ const estMargin: OrderMargin | null = useOrderMargin({
order, order,
@ -72,7 +70,18 @@ export const useFeeDealTicketDetails = (
const quoteName = market.tradableInstrument.instrument.product.quoteName; const quoteName = market.tradableInstrument.instrument.product.quoteName;
return { return useMemo(() => {
return {
market,
quoteName,
notionalSize,
estMargin,
estCloseOut,
slippage,
price,
partyData: partyBalance,
};
}, [
market, market,
quoteName, quoteName,
notionalSize, notionalSize,
@ -80,12 +89,12 @@ export const useFeeDealTicketDetails = (
estCloseOut, estCloseOut,
slippage, slippage,
price, price,
partyData: partyBalance, partyBalance,
}; ]);
}; };
export interface FeeDetails { export interface FeeDetails {
market: DealTicketMarketFragment; market: MarketDealTicket;
quoteName: string; quoteName: string;
notionalSize: string | null; notionalSize: string | null;
estMargin: OrderMargin | null; estMargin: OrderMargin | null;

View File

@ -0,0 +1,11 @@
import { useAccountBalance } from '@vegaprotocol/accounts';
import { toBigNum } from '@vegaprotocol/react-helpers';
export const useHasNoBalance = (assetId: string) => {
const { accountBalance, accountDecimals } = useAccountBalance(assetId);
const balance =
accountBalance && accountDecimals !== null
? toBigNum(accountBalance, accountDecimals)
: toBigNum('0', 0);
return balance.isZero();
};

View File

@ -2,9 +2,9 @@ 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 { PartyBalanceQuery } from './__generated__/PartyBalance'; import type { PartyBalanceQuery } from './__generated__/PartyBalance';
import { useOrderCloseOut } from './use-order-closeout'; import { useOrderCloseOut } from './use-order-closeout';
import type { DealTicketMarketFragment } from '../components/deal-ticket/__generated__/DealTicket';
jest.mock('@vegaprotocol/wallet', () => ({ jest.mock('@vegaprotocol/wallet', () => ({
...jest.requireActual('@vegaprotocol/wallet'), ...jest.requireActual('@vegaprotocol/wallet'),
@ -53,7 +53,7 @@ describe('useOrderCloseOut', () => {
() => () =>
useOrderCloseOut({ useOrderCloseOut({
order: order as OrderSubmissionBody['orderSubmission'], order: order as OrderSubmissionBody['orderSubmission'],
market: market as DealTicketMarketFragment, market: market as MarketDealTicket,
partyData: partyData as PartyBalanceQuery, partyData: partyData as PartyBalanceQuery,
}), }),
{ {
@ -73,7 +73,7 @@ describe('useOrderCloseOut', () => {
...order, ...order,
side: 'SIDE_SELL', side: 'SIDE_SELL',
} as OrderSubmissionBody['orderSubmission'], } as OrderSubmissionBody['orderSubmission'],
market: market as DealTicketMarketFragment, market: market as MarketDealTicket,
partyData: partyData as PartyBalanceQuery, partyData: partyData as PartyBalanceQuery,
}), }),
{ {
@ -93,7 +93,7 @@ describe('useOrderCloseOut', () => {
...order, ...order,
side: 'SIDE_SELL', side: 'SIDE_SELL',
} as OrderSubmissionBody['orderSubmission'], } as OrderSubmissionBody['orderSubmission'],
market: market as DealTicketMarketFragment, market: market as MarketDealTicket,
}), }),
{ {
wrapper: ({ children }: { children: React.ReactNode }) => ( wrapper: ({ children }: { children: React.ReactNode }) => (

View File

@ -7,13 +7,13 @@ import { useMarketPositions } from './use-market-positions';
import { useMarketDataMarkPrice } from './use-market-data-mark-price'; import { useMarketDataMarkPrice } from './use-market-data-mark-price';
import { usePartyMarketDataQuery } from './__generated__/PartyMarketData'; import { usePartyMarketDataQuery } from './__generated__/PartyMarketData';
import { Schema } from '@vegaprotocol/types'; import { Schema } from '@vegaprotocol/types';
import type { DealTicketMarketFragment } from '../components/deal-ticket/__generated__/DealTicket';
import type { PartyBalanceQuery } from './__generated__/PartyBalance'; import type { PartyBalanceQuery } from './__generated__/PartyBalance';
import { useSettlementAccount } from './use-settlement-account'; import { useSettlementAccount } from './use-settlement-account';
import type { MarketDealTicket } from '@vegaprotocol/market-list';
interface Props { interface Props {
order: OrderSubmissionBody['orderSubmission']; order: OrderSubmissionBody['orderSubmission'];
market: DealTicketMarketFragment; market: MarketDealTicket;
partyData?: PartyBalanceQuery; partyData?: PartyBalanceQuery;
} }

View File

@ -1,53 +1,43 @@
import { useMemo } from 'react'; import { useMemo } from 'react';
import compact from 'lodash/compact';
import { useVegaWallet } from '@vegaprotocol/wallet'; import { useVegaWallet } from '@vegaprotocol/wallet';
import { Schema } from '@vegaprotocol/types';
import { toBigNum } from '@vegaprotocol/react-helpers'; import { toBigNum } from '@vegaprotocol/react-helpers';
import type { DealTicketMarketFragment } from '../components/deal-ticket/__generated__/DealTicket';
import type { OrderMargin } from './use-order-margin'; import type { OrderMargin } from './use-order-margin';
import { usePartyBalanceQuery } from './__generated__/PartyBalance'; import { useAccountBalance } from '@vegaprotocol/accounts';
import { useSettlementAccount } from './use-settlement-account'; import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import { useOrderMargin } from './use-order-margin';
import type { MarketDealTicket } from '@vegaprotocol/market-list';
interface Props { interface Props {
market: DealTicketMarketFragment; market: MarketDealTicket;
estMargin: OrderMargin | null; order: OrderSubmissionBody['orderSubmission'];
} }
export const useOrderMarginValidation = ({ market, estMargin }: Props) => { export const useOrderMarginValidation = ({ market, order }: Props) => {
const { pubKey } = useVegaWallet(); const { pubKey } = useVegaWallet();
const estMargin: OrderMargin | null = useOrderMargin({
const { data: partyBalance } = usePartyBalanceQuery({ order,
variables: { partyId: pubKey || '' }, market,
skip: !pubKey, partyId: pubKey || '',
fetchPolicy: 'no-cache',
}); });
const { id: assetId, decimals: assetDecimals } =
market.tradableInstrument.instrument.product.settlementAsset;
const accounts = compact(partyBalance?.party?.accountsConnection?.edges).map( const { accountBalance, accountDecimals } = useAccountBalance(assetId);
(e) => e.node const balance =
); accountBalance && accountDecimals !== null
const settlementAccount = useSettlementAccount( ? toBigNum(accountBalance, accountDecimals)
market.tradableInstrument.instrument.product.settlementAsset.id, : toBigNum('0', assetDecimals);
accounts,
Schema.AccountType.ACCOUNT_TYPE_GENERAL
);
const assetDecimals =
market.tradableInstrument.instrument.product.settlementAsset.decimals;
const balance = settlementAccount
? toBigNum(
settlementAccount.balance || 0,
settlementAccount.asset.decimals || 0
)
: toBigNum('0', assetDecimals);
const margin = toBigNum(estMargin?.margin || 0, assetDecimals); const margin = toBigNum(estMargin?.margin || 0, assetDecimals);
const asset = market.tradableInstrument.instrument.product.settlementAsset;
const memoizedValue = useMemo(() => { // return only simple types (bool, string) for make memo sensible
const balanceError = balance.isGreaterThan(0) && balance.isLessThan(margin);
const balanceAsString = balance.toString();
const marginAsString = margin.toString();
return useMemo(() => {
return { return {
balance, balance: balanceAsString,
margin, margin: marginAsString,
asset, balanceError,
}; };
}, [balance, margin, asset]); }, [balanceAsString, marginAsString, balanceError]);
return memoizedValue;
}; };

View File

@ -2,9 +2,9 @@ import { renderHook } from '@testing-library/react';
import { useQuery } from '@apollo/client'; import { useQuery } from '@apollo/client';
import { BigNumber } from 'bignumber.js'; import { BigNumber } from 'bignumber.js';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet'; import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import type { MarketDealTicket } from '@vegaprotocol/market-list';
import type { PositionMargin } from './use-market-positions'; import type { PositionMargin } from './use-market-positions';
import { useOrderMargin } from './use-order-margin'; import { useOrderMargin } from './use-order-margin';
import type { DealTicketMarketFragment } from '../components/deal-ticket/__generated__/DealTicket';
let mockEstimateData = { let mockEstimateData = {
estimateOrder: { estimateOrder: {
@ -72,7 +72,7 @@ describe('useOrderMargin', () => {
const { result } = renderHook(() => const { result } = renderHook(() =>
useOrderMargin({ useOrderMargin({
order: order as OrderSubmissionBody['orderSubmission'], order: order as OrderSubmissionBody['orderSubmission'],
market: market as DealTicketMarketFragment, market: market as MarketDealTicket,
partyId, partyId,
}) })
); );
@ -86,7 +86,7 @@ describe('useOrderMargin', () => {
const { result } = renderHook(() => const { result } = renderHook(() =>
useOrderMargin({ useOrderMargin({
order: order as OrderSubmissionBody['orderSubmission'], order: order as OrderSubmissionBody['orderSubmission'],
market: market as DealTicketMarketFragment, market: market as MarketDealTicket,
partyId, partyId,
}) })
); );
@ -98,7 +98,7 @@ describe('useOrderMargin', () => {
const { result } = renderHook(() => const { result } = renderHook(() =>
useOrderMargin({ useOrderMargin({
order: order as OrderSubmissionBody['orderSubmission'], order: order as OrderSubmissionBody['orderSubmission'],
market: market as DealTicketMarketFragment, market: market as MarketDealTicket,
partyId, partyId,
}) })
); );
@ -125,7 +125,7 @@ describe('useOrderMargin', () => {
const { result } = renderHook(() => const { result } = renderHook(() =>
useOrderMargin({ useOrderMargin({
order: order as OrderSubmissionBody['orderSubmission'], order: order as OrderSubmissionBody['orderSubmission'],
market: market as DealTicketMarketFragment, market: market as MarketDealTicket,
partyId, partyId,
}) })
); );

View File

@ -2,15 +2,15 @@ import { BigNumber } from 'bignumber.js';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet'; import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import { Schema } from '@vegaprotocol/types'; import { Schema } from '@vegaprotocol/types';
import { removeDecimal } from '@vegaprotocol/react-helpers'; import { removeDecimal } from '@vegaprotocol/react-helpers';
import type { MarketDealTicket } from '@vegaprotocol/market-list';
import { useMarketPositions } from './use-market-positions'; import { useMarketPositions } from './use-market-positions';
import { useMarketDataMarkPrice } from './use-market-data-mark-price'; import { useMarketDataMarkPrice } from './use-market-data-mark-price';
import type { EstimateOrderQuery } from './__generated__/EstimateOrder'; import type { EstimateOrderQuery } from './__generated__/EstimateOrder';
import { useEstimateOrderQuery } from './__generated__/EstimateOrder'; import { useEstimateOrderQuery } from './__generated__/EstimateOrder';
import type { DealTicketMarketFragment } from '../components/deal-ticket/__generated__/DealTicket';
interface Props { interface Props {
order: OrderSubmissionBody['orderSubmission']; order: OrderSubmissionBody['orderSubmission'];
market: DealTicketMarketFragment; market: MarketDealTicket;
partyId: string; partyId: string;
} }

View File

@ -1,6 +1,6 @@
import { useLocalStorage } from '@vegaprotocol/react-helpers'; import { useLocalStorage } from '@vegaprotocol/react-helpers';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet'; import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import { useMemo } from 'react'; import { useCallback, useMemo } from 'react';
type OrderData = OrderSubmissionBody['orderSubmission'] | null; type OrderData = OrderSubmissionBody['orderSubmission'] | null;
@ -9,8 +9,12 @@ export const usePersistedOrder = (market: {
}): [OrderData, (value: OrderData) => void] => { }): [OrderData, (value: OrderData) => void] => {
const [value, setValue] = useLocalStorage(`deal-ticket-order-${market.id}`); const [value, setValue] = useLocalStorage(`deal-ticket-order-${market.id}`);
const order = value != null ? (JSON.parse(value) as OrderData) : null; const order = value != null ? (JSON.parse(value) as OrderData) : null;
const setOrder = useCallback(
(order: OrderData) => setValue(JSON.stringify(order)),
[setValue]
);
return useMemo<[OrderData, (value: OrderData) => void]>( return useMemo<[OrderData, (value: OrderData) => void]>(
() => [order, (order: OrderData) => setValue(JSON.stringify(order))], () => [order, setOrder],
[order, setValue] [order, setOrder]
); );
}; };

View File

@ -1,7 +1,7 @@
import { Schema } from '@vegaprotocol/types'; import { Schema } from '@vegaprotocol/types';
import type { DealTicketMarketFragment } from '../components'; import type { MarketDealTicket } from '@vegaprotocol/market-list';
export const isMarketInAuction = (market: DealTicketMarketFragment) => { export const isMarketInAuction = (market: MarketDealTicket) => {
return [ return [
Schema.MarketTradingMode.TRADING_MODE_BATCH_AUCTION, Schema.MarketTradingMode.TRADING_MODE_BATCH_AUCTION,
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION, Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,

View File

@ -1,9 +1,9 @@
import { Schema } from '@vegaprotocol/types'; import { Schema } from '@vegaprotocol/types';
import type { DealTicketMarketFragment } from '../components';
import { MarketModeValidationType } from '../constants'; import { MarketModeValidationType } from '../constants';
import { isMarketInAuction } from './is-market-in-auction'; import { isMarketInAuction } from './is-market-in-auction';
import type { MarketDealTicket } from '@vegaprotocol/market-list';
export const validateTimeInForce = (market: DealTicketMarketFragment) => { export const validateTimeInForce = (market: MarketDealTicket) => {
return (value: Schema.OrderTimeInForce) => { return (value: Schema.OrderTimeInForce) => {
const isMonitoringAuction = const isMonitoringAuction =
market.tradingMode === market.tradingMode ===

View File

@ -1,9 +1,9 @@
import { Schema } from '@vegaprotocol/types'; import { Schema } from '@vegaprotocol/types';
import type { DealTicketMarketFragment } from '../components';
import { MarketModeValidationType } from '../constants'; import { MarketModeValidationType } from '../constants';
import { isMarketInAuction } from './is-market-in-auction'; import { isMarketInAuction } from './is-market-in-auction';
import type { MarketDealTicket } from '@vegaprotocol/market-list';
export const validateType = (market: DealTicketMarketFragment) => { export const validateType = (market: MarketDealTicket) => {
return (value: Schema.OrderType) => { return (value: Schema.OrderType) => {
if (isMarketInAuction(market) && value === Schema.OrderType.TYPE_MARKET) { if (isMarketInAuction(market) && value === Schema.OrderType.TYPE_MARKET) {
const isMonitoringAuction = const isMonitoringAuction =

View File

@ -3,14 +3,14 @@ import { Schema as Types } from '@vegaprotocol/types';
import { gql } from '@apollo/client'; import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client'; import * as Apollo from '@apollo/client';
const defaultOptions = {} as const; const defaultOptions = {} as const;
export type SingleMarketFieldsFragment = { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradingMode: Types.MarketTradingMode, fees: { __typename?: 'Fees', factors: { __typename?: 'FeeFactors', makerFee: string, infrastructureFee: string, liquidityFee: string } }, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', id: string, name: string, code: string, metadata: { __typename?: 'InstrumentMetadata', tags?: Array<string> | null }, product: { __typename?: 'Future', quoteName: string, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string }, settlementAsset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number } } } }, marketTimestamps: { __typename?: 'MarketTimestamps', open?: string | null, close?: string | null } }; export type SingleMarketFieldsFragment = { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradingMode: Types.MarketTradingMode, fees: { __typename?: 'Fees', factors: { __typename?: 'FeeFactors', makerFee: string, infrastructureFee: string, liquidityFee: string } }, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', id: string, name: string, code: string, metadata: { __typename?: 'InstrumentMetadata', tags?: Array<string> | null }, product: { __typename?: 'Future', quoteName: string, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string }, settlementAsset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number } } } }, marketTimestamps: { __typename?: 'MarketTimestamps', open?: string | null, close?: string | null }, depth: { __typename?: 'MarketDepth', lastTrade?: { __typename?: 'Trade', price: string } | null } };
export type MarketQueryVariables = Types.Exact<{ export type MarketQueryVariables = Types.Exact<{
marketId: Types.Scalars['ID']; marketId: Types.Scalars['ID'];
}>; }>;
export type MarketQuery = { __typename?: 'Query', market?: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradingMode: Types.MarketTradingMode, fees: { __typename?: 'Fees', factors: { __typename?: 'FeeFactors', makerFee: string, infrastructureFee: string, liquidityFee: string } }, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', id: string, name: string, code: string, metadata: { __typename?: 'InstrumentMetadata', tags?: Array<string> | null }, product: { __typename?: 'Future', quoteName: string, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string }, settlementAsset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number } } } }, marketTimestamps: { __typename?: 'MarketTimestamps', open?: string | null, close?: string | null } } | null }; export type MarketQuery = { __typename?: 'Query', market?: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradingMode: Types.MarketTradingMode, fees: { __typename?: 'Fees', factors: { __typename?: 'FeeFactors', makerFee: string, infrastructureFee: string, liquidityFee: string } }, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', id: string, name: string, code: string, metadata: { __typename?: 'InstrumentMetadata', tags?: Array<string> | null }, product: { __typename?: 'Future', quoteName: string, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string }, settlementAsset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number } } } }, marketTimestamps: { __typename?: 'MarketTimestamps', open?: string | null, close?: string | null }, depth: { __typename?: 'MarketDepth', lastTrade?: { __typename?: 'Trade', price: string } | null } } | null };
export const SingleMarketFieldsFragmentDoc = gql` export const SingleMarketFieldsFragmentDoc = gql`
fragment SingleMarketFields on Market { fragment SingleMarketFields on Market {
@ -54,6 +54,11 @@ export const SingleMarketFieldsFragmentDoc = gql`
open open
close close
} }
depth {
lastTrade {
price
}
}
} }
`; `;
export const MarketDocument = gql` export const MarketDocument = gql`

View File

@ -1,9 +1,14 @@
import { makeDataProvider } from '@vegaprotocol/react-helpers'; import {
makeDataProvider,
makeDerivedDataProvider,
} from '@vegaprotocol/react-helpers';
import { MarketDocument } from './__generated___/market'; import { MarketDocument } from './__generated___/market';
import type { import type {
MarketQuery, MarketQuery,
SingleMarketFieldsFragment, SingleMarketFieldsFragment,
} from './__generated___/market'; } from './__generated___/market';
import type { MarketData } from './market-data-provider';
import { marketDataProvider } from './market-data-provider';
const getData = ( const getData = (
responseData: MarketQuery responseData: MarketQuery
@ -18,3 +23,19 @@ export const marketProvider = makeDataProvider<
query: MarketDocument, query: MarketDocument,
getData, getData,
}); });
export type MarketDealTicket = SingleMarketFieldsFragment & {
data: MarketData;
};
export type MarketDealTicketAsset =
MarketDealTicket['tradableInstrument']['instrument']['product']['settlementAsset'];
export const marketDealTicketProvider = makeDerivedDataProvider<
MarketDealTicket,
never
>([marketProvider, marketDataProvider], ([market, marketData]) => {
return {
...market,
data: marketData,
};
});

View File

@ -39,6 +39,11 @@ fragment SingleMarketFields on Market {
open open
close close
} }
depth {
lastTrade {
price
}
}
} }
query Market($marketId: ID!) { query Market($marketId: ID!) {