From b4e98e285e3a2d32fb7f2de345938591a879c28a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20G=C5=82ownia?= Date: Tue, 6 Feb 2024 08:42:11 +0100 Subject: [PATCH] feat(deal-ticket): update fields in margin details (#5722) --- ...test_trading_deal_ticket_submit_account.py | 2 +- .../deal-ticket-margin-details.tsx | 296 +++--------------- .../components/deal-ticket/deal-ticket.tsx | 24 +- .../src/components/deal-ticket/key-value.tsx | 7 +- .../deal-ticket/margin-mode-selector.tsx | 111 ++++--- .../utils/map-form-values-to-submission.ts | 2 +- ...c.ts => time-in-force-persistence.spec.ts} | 6 +- ...stance.ts => time-in-force-persistence.ts} | 0 libs/positions/src/lib/Positions.graphql | 20 -- .../src/lib/__generated__/Positions.ts | 22 +- .../src/lib/estimate-position.mock.ts | 21 -- .../src/lib/liquidation-price.spec.tsx | 20 -- 12 files changed, 123 insertions(+), 408 deletions(-) rename libs/deal-ticket/src/utils/{time-in-force-persistance.spec.ts => time-in-force-persistence.spec.ts} (90%) rename libs/deal-ticket/src/utils/{time-in-force-persistance.ts => time-in-force-persistence.ts} (100%) diff --git a/apps/trading/e2e/tests/deal_ticket/test_trading_deal_ticket_submit_account.py b/apps/trading/e2e/tests/deal_ticket/test_trading_deal_ticket_submit_account.py index fc94d69b6..971c730c2 100644 --- a/apps/trading/e2e/tests/deal_ticket/test_trading_deal_ticket_submit_account.py +++ b/apps/trading/e2e/tests/deal_ticket/test_trading_deal_ticket_submit_account.py @@ -33,7 +33,7 @@ def test_should_display_info_and_button_for_deposit(continuous_market, page: Pag "You may not have enough margin available to open this position.") page.get_by_test_id(deal_ticket_warning_margin).hover() expect(page.get_by_test_id("tooltip-content").nth(0)).to_have_text( - "1,661,896.6317 tDAI is currently required.You have only 1,000,000.00.Deposit tDAI") + "1,661,888.12901 tDAI is currently required.You have only 999,991.49731.Deposit tDAI") page.get_by_test_id(deal_ticket_deposit_dialog_button).nth(0).click() expect(page.get_by_test_id("sidebar-content") ).to_contain_text("DepositFrom") diff --git a/libs/deal-ticket/src/components/deal-ticket/deal-ticket-margin-details.tsx b/libs/deal-ticket/src/components/deal-ticket/deal-ticket-margin-details.tsx index a5319e13d..d2fa7a014 100644 --- a/libs/deal-ticket/src/components/deal-ticket/deal-ticket-margin-details.tsx +++ b/libs/deal-ticket/src/components/deal-ticket/deal-ticket-margin-details.tsx @@ -3,27 +3,13 @@ import { getAsset, getQuoteName } from '@vegaprotocol/markets'; import { useVegaWallet } from '@vegaprotocol/wallet'; import { AccountBreakdownDialog } from '@vegaprotocol/accounts'; import { formatRange, formatValue } from '@vegaprotocol/utils'; -import { marketMarginDataProvider } from '@vegaprotocol/accounts'; -import { useDataProvider } from '@vegaprotocol/data-provider'; -import * as AccordionPrimitive from '@radix-ui/react-accordion'; import * as Schema from '@vegaprotocol/types'; import { - MARGIN_DIFF_TOOLTIP_TEXT, - DEDUCTION_FROM_COLLATERAL_TOOLTIP_TEXT, - TOTAL_MARGIN_AVAILABLE, LIQUIDATION_PRICE_ESTIMATE_TOOLTIP_TEXT, - EST_TOTAL_MARGIN_TOOLTIP_TEXT, MARGIN_ACCOUNT_TOOLTIP_TEXT, } from '../../constants'; import { KeyValue } from './key-value'; -import { - Accordion, - AccordionChevron, - AccordionPanel, - ExternalLink, - Tooltip, -} from '@vegaprotocol/ui-toolkit'; -import classNames from 'classnames'; +import { ExternalLink } from '@vegaprotocol/ui-toolkit'; import { useT, ns } from '../../use-t'; import { Trans } from 'react-i18next'; import type { Market } from '@vegaprotocol/markets'; @@ -31,9 +17,9 @@ import { emptyValue } from './deal-ticket-fee-details'; import type { EstimatePositionQuery } from '@vegaprotocol/positions'; export interface DealTicketMarginDetailsProps { - generalAccountBalance?: string; - marginAccountBalance?: string; - orderMarginAccountBalance?: string; + generalAccountBalance: string; + marginAccountBalance: string; + orderMarginAccountBalance: string; market: Market; onMarketClick?: (marketId: string, metaKey?: boolean) => void; assetSymbol: string; @@ -54,25 +40,13 @@ export const DealTicketMarginDetails = ({ const t = useT(); const [breakdownDialog, setBreakdownDialog] = useState(false); const { pubKey: partyId } = useVegaWallet(); - const { data: currentMargins } = useDataProvider({ - dataProvider: marketMarginDataProvider, - variables: { marketId: market.id, partyId: partyId || '' }, - skip: !partyId, - }); - const isInIsolatedMode = - positionEstimate?.margin.bestCase.marginMode === - Schema.MarginMode.MARGIN_MODE_ISOLATED_MARGIN; const liquidationEstimate = positionEstimate?.liquidation; - const marginEstimate = positionEstimate?.margin; const totalMarginAccountBalance = BigInt(marginAccountBalance || '0') + BigInt(orderMarginAccountBalance || '0'); - const totalBalance = - BigInt(generalAccountBalance || '0') + totalMarginAccountBalance; + const asset = getAsset(market); const { decimals: assetDecimals, quantum } = asset; - let marginRequiredBestCase: string | undefined = undefined; - let marginRequiredWorstCase: string | undefined = undefined; const collateralIncreaseEstimateBestCase = BigInt( positionEstimate?.collateralIncreaseEstimate.bestCase ?? '0' @@ -80,102 +54,6 @@ export const DealTicketMarginDetails = ({ const collateralIncreaseEstimateWorstCase = BigInt( positionEstimate?.collateralIncreaseEstimate.worstCase ?? '0' ); - const marginEstimateBestCase = isInIsolatedMode - ? totalMarginAccountBalance + collateralIncreaseEstimateBestCase - : BigInt(marginEstimate?.bestCase.initialLevel ?? 0); - const marginEstimateWorstCase = isInIsolatedMode - ? totalMarginAccountBalance + collateralIncreaseEstimateWorstCase - : BigInt(marginEstimate?.worstCase.initialLevel ?? 0); - if (isInIsolatedMode) { - marginRequiredBestCase = collateralIncreaseEstimateBestCase.toString(); - marginRequiredWorstCase = collateralIncreaseEstimateWorstCase.toString(); - } else if (marginEstimate) { - if (currentMargins) { - const currentMargin = BigInt(currentMargins.initialLevel); - marginRequiredBestCase = ( - marginEstimateBestCase - currentMargin - ).toString(); - if (marginRequiredBestCase.startsWith('-')) { - marginRequiredBestCase = '0'; - } - - marginRequiredWorstCase = ( - marginEstimateWorstCase - currentMargin - ).toString(); - - if (marginRequiredWorstCase.startsWith('-')) { - marginRequiredWorstCase = '0'; - } - } else { - marginRequiredBestCase = marginEstimateBestCase.toString(); - marginRequiredWorstCase = marginEstimateWorstCase.toString(); - } - } - - const totalMarginAvailable = ( - currentMargins - ? totalBalance - BigInt(currentMargins.maintenanceLevel) - : totalBalance - ).toString(); - - let deductionFromCollateral = null; - let projectedMargin = null; - if (totalMarginAccountBalance) { - const deductionFromCollateralBestCase = - marginEstimateBestCase - totalMarginAccountBalance; - - const deductionFromCollateralWorstCase = - marginEstimateWorstCase - totalMarginAccountBalance; - - deductionFromCollateral = ( - 0 - ? deductionFromCollateralBestCase.toString() - : '0', - deductionFromCollateralWorstCase > 0 - ? deductionFromCollateralWorstCase.toString() - : '0', - assetDecimals - )} - formattedValue={formatValue( - deductionFromCollateralWorstCase > 0 - ? deductionFromCollateralWorstCase.toString() - : '0', - assetDecimals, - quantum - )} - symbol={assetSymbol} - labelDescription={t( - 'DEDUCTION_FROM_COLLATERAL_TOOLTIP_TEXT', - DEDUCTION_FROM_COLLATERAL_TOOLTIP_TEXT, - { assetSymbol } - )} - /> - ); - projectedMargin = ( - - ); - } let liquidationPriceEstimate = emptyValue; let liquidationPriceEstimateRange = emptyValue; @@ -232,128 +110,50 @@ export const DealTicketMarginDetails = ({ const quoteName = getQuoteName(market); return ( -
- - -
-
- - {t('Margin required')} - - - -
- -
- {formatValue( - marginRequiredWorstCase, - assetDecimals, - quantum - )}{' '} - {assetSymbol || ''} -
-
-
- - } - > -
- - {deductionFromCollateral} - setBreakdownDialog(true) - : undefined - } - value={formatValue( - totalMarginAccountBalance.toString(), - assetDecimals - )} - symbol={assetSymbol} - labelDescription={t( - 'MARGIN_ACCOUNT_TOOLTIP_TEXT', - MARGIN_ACCOUNT_TOOLTIP_TEXT - )} - formattedValue={formatValue( - totalMarginAccountBalance.toString(), - assetDecimals, - quantum - )} - /> -
-
-
- {projectedMargin} +
setBreakdownDialog(true) : undefined + } + value={formatValue(totalMarginAccountBalance.toString(), assetDecimals)} + symbol={assetSymbol} + labelDescription={t( + 'MARGIN_ACCOUNT_TOOLTIP_TEXT', + MARGIN_ACCOUNT_TOOLTIP_TEXT + )} + formattedValue={formatValue( + totalMarginAccountBalance.toString(), + assetDecimals, + quantum + )} + /> + + + { @@ -43,10 +41,7 @@ export const KeyValue = ({ : id }`} key={typeof label === 'string' ? label : 'value-dropdown'} - className={classnames( - 'text-xs flex justify-between items-center gap-4 flex-wrap text-right', - { 'ml-2': indent } - )} + className="text-xs flex justify-between items-center gap-4 flex-wrap text-right" >
{label}
diff --git a/libs/deal-ticket/src/components/deal-ticket/margin-mode-selector.tsx b/libs/deal-ticket/src/components/deal-ticket/margin-mode-selector.tsx index 6abae606b..1f5fc1bda 100644 --- a/libs/deal-ticket/src/components/deal-ticket/margin-mode-selector.tsx +++ b/libs/deal-ticket/src/components/deal-ticket/margin-mode-selector.tsx @@ -29,6 +29,7 @@ import { usePositionEstimate } from '../../hooks/use-position-estimate'; import { addDecimalsFormatNumber } from '@vegaprotocol/utils'; import { getAsset, useMarket } from '@vegaprotocol/markets'; import { NoWalletWarning } from './deal-ticket'; +import { DealTicketMarginDetails } from './deal-ticket-margin-details'; const defaultLeverage = 10; @@ -93,66 +94,78 @@ export const MarginChange = ({ }, skip ); - if ( - !asset || - !estimateMargin?.estimatePosition?.collateralIncreaseEstimate.worstCase || - estimateMargin.estimatePosition.collateralIncreaseEstimate.worstCase === '0' - ) { + if (!asset || !estimateMargin?.estimatePosition) { return null; } const collateralIncreaseEstimate = BigInt( estimateMargin.estimatePosition.collateralIncreaseEstimate.worstCase ); - if (!collateralIncreaseEstimate) { - return null; - } + let positionWarning = ''; - if (orders?.length && openVolume !== '0') { - positionWarning = t( - 'youHaveOpenPositionAndOrders', - 'You have an existing position and open orders on this market.', - { - count: orders.length, - } - ); - } else if (!orders?.length) { - positionWarning = t('You have an existing position on this market.'); - } else { - positionWarning = t( - 'youHaveOpenOrders', - 'You have open orders on this market.', - { - count: orders.length, - } - ); - } let marginChangeWarning = ''; - const amount = addDecimalsFormatNumber( - collateralIncreaseEstimate.toString(), - asset?.decimals - ); - const { symbol } = asset; - const interpolation = { amount, symbol }; - if (marginMode === Schema.MarginMode.MARGIN_MODE_CROSS_MARGIN) { - marginChangeWarning = t( - 'Changing the margin mode will move {{amount}} {{symbol}} from your general account to fund the position.', - interpolation - ); - } else { - marginChangeWarning = t( - 'Changing the margin mode and leverage will move {{amount}} {{symbol}} from your general account to fund the position.', - interpolation + if (collateralIncreaseEstimate) { + if (orders?.length && openVolume !== '0') { + positionWarning = t( + 'youHaveOpenPositionAndOrders', + 'You have an existing position and open orders on this market.', + { + count: orders.length, + } + ); + } else if (!orders?.length) { + positionWarning = t('You have an existing position on this market.'); + } else { + positionWarning = t( + 'youHaveOpenOrders', + 'You have open orders on this market.', + { + count: orders.length, + } + ); + } + + const amount = addDecimalsFormatNumber( + collateralIncreaseEstimate.toString(), + asset?.decimals ); + const { symbol } = asset; + const interpolation = { amount, symbol }; + if (marginMode === Schema.MarginMode.MARGIN_MODE_CROSS_MARGIN) { + marginChangeWarning = t( + 'Changing the margin mode will move {{amount}} {{symbol}} from your general account to fund the position.', + interpolation + ); + } else { + marginChangeWarning = t( + 'Changing the margin mode and leverage will move {{amount}} {{symbol}} from your general account to fund the position.', + interpolation + ); + } } return (
- -

{positionWarning}

-

{marginChangeWarning}

- + {positionWarning && marginChangeWarning && ( + +

{positionWarning}

+

{marginChangeWarning}

+ + } + /> + )} +
diff --git a/libs/deal-ticket/src/utils/map-form-values-to-submission.ts b/libs/deal-ticket/src/utils/map-form-values-to-submission.ts index 6d9e690b3..12a5e2bd2 100644 --- a/libs/deal-ticket/src/utils/map-form-values-to-submission.ts +++ b/libs/deal-ticket/src/utils/map-form-values-to-submission.ts @@ -9,7 +9,7 @@ import type { } from '../hooks/use-form-values'; import * as Schema from '@vegaprotocol/types'; import { removeDecimal, toNanoSeconds } from '@vegaprotocol/utils'; -import { isPersistentOrder } from './time-in-force-persistance'; +import { isPersistentOrder } from './time-in-force-persistence'; export const mapFormValuesToOrderSubmission = ( order: OrderFormValues, diff --git a/libs/deal-ticket/src/utils/time-in-force-persistance.spec.ts b/libs/deal-ticket/src/utils/time-in-force-persistence.spec.ts similarity index 90% rename from libs/deal-ticket/src/utils/time-in-force-persistance.spec.ts rename to libs/deal-ticket/src/utils/time-in-force-persistence.spec.ts index ce4a783fe..881358fc9 100644 --- a/libs/deal-ticket/src/utils/time-in-force-persistance.spec.ts +++ b/libs/deal-ticket/src/utils/time-in-force-persistence.spec.ts @@ -2,9 +2,9 @@ import { OrderTimeInForce } from '@vegaprotocol/types'; import { isNonPersistentOrder, isPersistentOrder, -} from './time-in-force-persistance'; +} from './time-in-force-persistence'; -it('isNonPeristentOrder', () => { +it('isNonPersistentOrder', () => { expect(isNonPersistentOrder(OrderTimeInForce.TIME_IN_FORCE_FOK)).toBe(true); expect(isNonPersistentOrder(OrderTimeInForce.TIME_IN_FORCE_IOC)).toBe(true); expect(isNonPersistentOrder(OrderTimeInForce.TIME_IN_FORCE_GTC)).toBe(false); @@ -13,7 +13,7 @@ it('isNonPeristentOrder', () => { expect(isNonPersistentOrder(OrderTimeInForce.TIME_IN_FORCE_GFN)).toBe(false); }); -it('isPeristentOrder', () => { +it('isPersistentOrder', () => { expect(isPersistentOrder(OrderTimeInForce.TIME_IN_FORCE_FOK)).toBe(false); expect(isPersistentOrder(OrderTimeInForce.TIME_IN_FORCE_IOC)).toBe(false); expect(isPersistentOrder(OrderTimeInForce.TIME_IN_FORCE_GTC)).toBe(true); diff --git a/libs/deal-ticket/src/utils/time-in-force-persistance.ts b/libs/deal-ticket/src/utils/time-in-force-persistence.ts similarity index 100% rename from libs/deal-ticket/src/utils/time-in-force-persistance.ts rename to libs/deal-ticket/src/utils/time-in-force-persistence.ts diff --git a/libs/positions/src/lib/Positions.graphql b/libs/positions/src/lib/Positions.graphql index 02eb53c20..e90d486a9 100644 --- a/libs/positions/src/lib/Positions.graphql +++ b/libs/positions/src/lib/Positions.graphql @@ -67,26 +67,6 @@ query EstimatePosition( # we can set this variable to true so that we can format with market.decimalPlaces scaleLiquidationPriceToMarketDecimals: true ) { - margin { - worstCase { - maintenanceLevel - searchLevel - initialLevel - collateralReleaseLevel - marginMode - marginFactor - orderMarginLevel - } - bestCase { - maintenanceLevel - searchLevel - initialLevel - collateralReleaseLevel - marginMode - marginFactor - orderMarginLevel - } - } collateralIncreaseEstimate { worstCase bestCase diff --git a/libs/positions/src/lib/__generated__/Positions.ts b/libs/positions/src/lib/__generated__/Positions.ts index b1391a4bb..4c08dabcb 100644 --- a/libs/positions/src/lib/__generated__/Positions.ts +++ b/libs/positions/src/lib/__generated__/Positions.ts @@ -33,7 +33,7 @@ export type EstimatePositionQueryVariables = Types.Exact<{ }>; -export type EstimatePositionQuery = { __typename?: 'Query', estimatePosition?: { __typename?: 'PositionEstimate', margin: { __typename?: 'MarginEstimate', worstCase: { __typename?: 'MarginLevels', maintenanceLevel: string, searchLevel: string, initialLevel: string, collateralReleaseLevel: string, marginMode: Types.MarginMode, marginFactor: string, orderMarginLevel: string }, bestCase: { __typename?: 'MarginLevels', maintenanceLevel: string, searchLevel: string, initialLevel: string, collateralReleaseLevel: string, marginMode: Types.MarginMode, marginFactor: string, orderMarginLevel: string } }, collateralIncreaseEstimate: { __typename?: 'CollateralIncreaseEstimate', worstCase: string, bestCase: string }, liquidation?: { __typename?: 'LiquidationEstimate', worstCase: { __typename?: 'LiquidationPrice', open_volume_only: string, including_buy_orders: string, including_sell_orders: string }, bestCase: { __typename?: 'LiquidationPrice', open_volume_only: string, including_buy_orders: string, including_sell_orders: string } } | null } | null }; +export type EstimatePositionQuery = { __typename?: 'Query', estimatePosition?: { __typename?: 'PositionEstimate', collateralIncreaseEstimate: { __typename?: 'CollateralIncreaseEstimate', worstCase: string, bestCase: string }, liquidation?: { __typename?: 'LiquidationEstimate', worstCase: { __typename?: 'LiquidationPrice', open_volume_only: string, including_buy_orders: string, including_sell_orders: string }, bestCase: { __typename?: 'LiquidationPrice', open_volume_only: string, including_buy_orders: string, including_sell_orders: string } } | null } | null }; export const PositionFieldsFragmentDoc = gql` fragment PositionFields on Position { @@ -144,26 +144,6 @@ export const EstimatePositionDocument = gql` includeCollateralIncreaseInAvailableCollateral: $includeCollateralIncreaseInAvailableCollateral scaleLiquidationPriceToMarketDecimals: true ) { - margin { - worstCase { - maintenanceLevel - searchLevel - initialLevel - collateralReleaseLevel - marginMode - marginFactor - orderMarginLevel - } - bestCase { - maintenanceLevel - searchLevel - initialLevel - collateralReleaseLevel - marginMode - marginFactor - orderMarginLevel - } - } collateralIncreaseEstimate { worstCase bestCase diff --git a/libs/positions/src/lib/estimate-position.mock.ts b/libs/positions/src/lib/estimate-position.mock.ts index b1af23637..b2ed4a3f6 100644 --- a/libs/positions/src/lib/estimate-position.mock.ts +++ b/libs/positions/src/lib/estimate-position.mock.ts @@ -1,7 +1,6 @@ import type { PartialDeep } from 'type-fest'; import merge from 'lodash/merge'; import type { EstimatePositionQuery } from './__generated__/Positions'; -import { MarginMode } from '@vegaprotocol/types'; export const estimatePositionQuery = ( override?: PartialDeep @@ -9,26 +8,6 @@ export const estimatePositionQuery = ( const defaultResult: EstimatePositionQuery = { estimatePosition: { __typename: 'PositionEstimate', - margin: { - bestCase: { - collateralReleaseLevel: '1000000', - initialLevel: '500000', - maintenanceLevel: '200000', - searchLevel: '300000', - marginFactor: '1', - orderMarginLevel: '0', - marginMode: MarginMode.MARGIN_MODE_CROSS_MARGIN, - }, - worstCase: { - collateralReleaseLevel: '1100000', - initialLevel: '600000', - maintenanceLevel: '300000', - searchLevel: '400000', - marginFactor: '1', - orderMarginLevel: '0', - marginMode: MarginMode.MARGIN_MODE_CROSS_MARGIN, - }, - }, collateralIncreaseEstimate: { bestCase: '0', worstCase: '0', diff --git a/libs/positions/src/lib/liquidation-price.spec.tsx b/libs/positions/src/lib/liquidation-price.spec.tsx index d57bfac4c..7e02d693d 100644 --- a/libs/positions/src/lib/liquidation-price.spec.tsx +++ b/libs/positions/src/lib/liquidation-price.spec.tsx @@ -30,26 +30,6 @@ describe('LiquidationPrice', () => { result: { data: { estimatePosition: { - margin: { - worstCase: { - maintenanceLevel: '100', - searchLevel: '100', - initialLevel: '100', - collateralReleaseLevel: '100', - orderMarginLevel: '0', - marginFactor: '0', - marginMode: MarginMode.MARGIN_MODE_CROSS_MARGIN, - }, - bestCase: { - maintenanceLevel: '100', - searchLevel: '100', - initialLevel: '100', - collateralReleaseLevel: '100', - orderMarginLevel: '0', - marginFactor: '0', - marginMode: MarginMode.MARGIN_MODE_CROSS_MARGIN, - }, - }, collateralIncreaseEstimate: { bestCase: '0', worstCase: '0',