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:
parent
a5aed85b43
commit
b749a05736
@ -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());
|
||||||
|
@ -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) => {
|
||||||
|
@ -144,4 +144,8 @@ export const singleMarket: SingleMarketFieldsFragment = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
depth: {
|
||||||
|
__typename: 'MarketDepth',
|
||||||
|
lastTrade: { price: '9893006', __typename: 'Trade' },
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
@ -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);
|
|
||||||
};
|
|
@ -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',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
@ -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,
|
||||||
|
@ -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[] = [
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
|
@ -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>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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'];
|
||||||
|
@ -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(
|
||||||
|
@ -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 };
|
||||||
|
@ -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')
|
||||||
|
@ -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',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
|
||||||
};
|
|
@ -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' },
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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());
|
||||||
|
|
||||||
|
@ -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;
|
||||||
},
|
},
|
||||||
|
15
libs/accounts/src/lib/get-settlement-account.ts
Normal file
15
libs/accounts/src/lib/get-settlement-account.ts
Normal 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;
|
@ -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';
|
||||||
|
43
libs/accounts/src/lib/use-account-balance.tsx
Normal file
43
libs/accounts/src/lib/use-account-balance.tsx
Normal 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]
|
||||||
|
);
|
||||||
|
};
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
@ -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>;
|
|
@ -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;
|
||||||
|
@ -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>
|
||||||
|
@ -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 }) => (
|
||||||
|
@ -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[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
}`
|
}`
|
||||||
);
|
);
|
||||||
|
@ -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
|
||||||
|
@ -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';
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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'] = [];
|
||||||
|
@ -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;
|
||||||
|
11
libs/deal-ticket/src/hooks/use-has-no-balance.tsx
Normal file
11
libs/deal-ticket/src/hooks/use-has-no-balance.tsx
Normal 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();
|
||||||
|
};
|
@ -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 }) => (
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
|
||||||
};
|
};
|
||||||
|
@ -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,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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]
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -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,
|
||||||
|
@ -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 ===
|
||||||
|
@ -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 =
|
||||||
|
@ -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`
|
||||||
|
@ -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,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
@ -39,6 +39,11 @@ fragment SingleMarketFields on Market {
|
|||||||
open
|
open
|
||||||
close
|
close
|
||||||
}
|
}
|
||||||
|
depth {
|
||||||
|
lastTrade {
|
||||||
|
price
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
query Market($marketId: ID!) {
|
query Market($marketId: ID!) {
|
||||||
|
Loading…
Reference in New Issue
Block a user