From 2ba0e9a1b2369aa7fd0ded2a82336905abefee6d Mon Sep 17 00:00:00 2001
From: "m.ray" <16125548+MadalinaRaicu@users.noreply.github.com>
Date: Wed, 7 Jun 2023 13:49:50 +0300
Subject: [PATCH] chore(trading): add quantum formatting to deal ticket (#4030)
---
.../trading-deal-ticket-order.cy.ts | 3 +-
.../deal-ticket/deal-ticket-fee-details.tsx | 43 ++++++----
.../use-fee-deal-ticket-details.spec.tsx | 68 ++++++++++++++++
.../src/hooks/use-fee-deal-ticket-details.tsx | 79 ++++++++++++++++---
libs/deal-ticket/src/test-helpers.ts | 1 +
libs/fills/src/lib/test-helpers.ts | 1 +
libs/markets/src/lib/__generated__/markets.ts | 5 +-
libs/markets/src/lib/markets.graphql | 1 +
libs/markets/src/lib/markets.mock.ts | 1 +
.../lib/components/mocks/generate-orders.ts | 1 +
libs/utils/src/lib/format/number.spec.ts | 23 ++++++
libs/utils/src/lib/format/number.ts | 12 +++
.../src/lib/withdraw-form-container.spec.tsx | 1 +
13 files changed, 206 insertions(+), 33 deletions(-)
create mode 100644 libs/deal-ticket/src/hooks/use-fee-deal-ticket-details.spec.tsx
diff --git a/apps/trading-e2e/src/integration/trading-deal-ticket-order.cy.ts b/apps/trading-e2e/src/integration/trading-deal-ticket-order.cy.ts
index 00d4f1c9d..5ac9b5133 100644
--- a/apps/trading-e2e/src/integration/trading-deal-ticket-order.cy.ts
+++ b/apps/trading-e2e/src/integration/trading-deal-ticket-order.cy.ts
@@ -100,9 +100,8 @@ describe('deal ticker order validation', { tags: '@smoke' }, () => {
.within(() => {
cy.get('[data-state="closed"]').should(
'have.text',
- 'Total margin available'
+ 'Total margin available100,000.01 tDAI'
);
- cy.get('.text-neutral-500').should('have.text', '100,000.01 tDAI');
});
});
});
diff --git a/libs/deal-ticket/src/components/deal-ticket/deal-ticket-fee-details.tsx b/libs/deal-ticket/src/components/deal-ticket/deal-ticket-fee-details.tsx
index 52969be14..4309d0069 100644
--- a/libs/deal-ticket/src/components/deal-ticket/deal-ticket-fee-details.tsx
+++ b/libs/deal-ticket/src/components/deal-ticket/deal-ticket-fee-details.tsx
@@ -33,24 +33,35 @@ export const DealTicketFeeDetails = (props: FeeDetails) => {
const details = getFeeDetailsValues(props);
return (
- {details.map(({ label, value, labelDescription, symbol, indent }) => (
-
-
-
- {label}
+ {details.map(
+ ({
+ label,
+ value,
+ labelDescription,
+ symbol,
+ indent,
+ formattedValue,
+ }) => (
+
+
+
+ {`${
+ formattedValue ?? '-'
+ } ${symbol || ''}`}
- {`${
- value ?? '-'
- } ${symbol || ''}`}
-
- ))}
+ )
+ )}
);
};
diff --git a/libs/deal-ticket/src/hooks/use-fee-deal-ticket-details.spec.tsx b/libs/deal-ticket/src/hooks/use-fee-deal-ticket-details.spec.tsx
new file mode 100644
index 000000000..f5a899fbf
--- /dev/null
+++ b/libs/deal-ticket/src/hooks/use-fee-deal-ticket-details.spec.tsx
@@ -0,0 +1,68 @@
+import { formatRange, formatValue } from './use-fee-deal-ticket-details';
+
+describe('useFeeDealTicketDetails', () => {
+ it.each([
+ { v: 123000, d: 5, o: '1.23' },
+ { v: 123000, d: 3, o: '123.00' },
+ { v: 123000, d: 1, o: '12,300.0' },
+ { v: 123001000, d: 2, o: '1,230,010.00' },
+ { v: 123001, d: 2, o: '1,230.01' },
+ {
+ v: '123456789123456789',
+ d: 10,
+ o: '12,345,678.91234568',
+ },
+ ])('formats values correctly', ({ v, d, o }) => {
+ expect(formatValue(v, d)).toStrictEqual(o);
+ });
+
+ it.each([
+ { v: 123000, d: 5, o: '1.23', q: '0.1' },
+ { v: 123000, d: 3, o: '123.00', q: '0.1' },
+ { v: 123000, d: 1, o: '12,300.00', q: '0.1' },
+ { v: 123001000, d: 2, o: '1,230,010.00', q: '0.1' },
+ { v: 123001, d: 2, o: '1,230', q: '100' },
+ { v: 123001, d: 2, o: '1,230.01', q: '0.1' },
+ {
+ v: '123456789123456789',
+ d: 10,
+ o: '12,345,678.9123457',
+ q: '0.00003846',
+ },
+ ])(
+ 'formats with formatValue with quantum given number correctly',
+ ({ v, d, o, q }) => {
+ expect(formatValue(v.toString(), d, q)).toStrictEqual(o);
+ }
+ );
+
+ it.each([
+ { min: 123000, max: 12300011111, d: 5, o: '1.23 - 123,000.111', q: '0.1' },
+ {
+ min: 123000,
+ max: 12300011111,
+ d: 3,
+ o: '123.00 - 12,300,011.111',
+ q: '0.1',
+ },
+ {
+ min: 123000,
+ max: 12300011111,
+ d: 1,
+ o: '12,300.00 - 1,230,001,111.10',
+ q: '0.1',
+ },
+ {
+ min: 123001000,
+ max: 12300011111,
+ d: 2,
+ o: '1,230,010 - 123,000,111',
+ q: '100',
+ },
+ ])(
+ 'formats with formatValue with quantum given number correctly',
+ ({ min, max, d, o, q }) => {
+ expect(formatRange(min, max, d, q)).toStrictEqual(o);
+ }
+ );
+});
diff --git a/libs/deal-ticket/src/hooks/use-fee-deal-ticket-details.tsx b/libs/deal-ticket/src/hooks/use-fee-deal-ticket-details.tsx
index df295e562..735c2b54f 100644
--- a/libs/deal-ticket/src/hooks/use-fee-deal-ticket-details.tsx
+++ b/libs/deal-ticket/src/hooks/use-fee-deal-ticket-details.tsx
@@ -1,5 +1,9 @@
import { FeesBreakdown } from '@vegaprotocol/markets';
-import { addDecimalsFormatNumber, isNumeric } from '@vegaprotocol/utils';
+import {
+ addDecimalsFormatNumber,
+ addDecimalsFormatNumberQuantum,
+ isNumeric,
+} from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
import { useVegaWallet } from '@vegaprotocol/wallet';
import type { Market } from '@vegaprotocol/markets';
@@ -52,21 +56,25 @@ export interface FeeDetails {
}
const emptyValue = '-';
-const formatValue = (
+
+export const formatValue = (
value: string | number | null | undefined,
- formatDecimals: number
+ formatDecimals: number,
+ quantum?: string
): string => {
- return isNumeric(value)
- ? addDecimalsFormatNumber(value, formatDecimals)
- : emptyValue;
+ if (!isNumeric(value)) return emptyValue;
+ if (!quantum) return addDecimalsFormatNumber(value, formatDecimals);
+ return addDecimalsFormatNumberQuantum(value, formatDecimals, quantum);
};
-const formatRange = (
+
+export const formatRange = (
min: string | number | null | undefined,
max: string | number | null | undefined,
- formatDecimals: number
+ formatDecimals: number,
+ quantum?: string
) => {
- const minFormatted = formatValue(min, formatDecimals);
- const maxFormatted = formatValue(max, formatDecimals);
+ const minFormatted = formatValue(min, formatDecimals, quantum);
+ const maxFormatted = formatValue(max, formatDecimals, quantum);
if (minFormatted !== maxFormatted) {
return `${minFormatted} - ${maxFormatted}`;
}
@@ -93,9 +101,12 @@ export const getFeeDetailsValues = ({
BigInt(generalAccountBalance || '0') + BigInt(marginAccountBalance || '0');
const assetDecimals =
market.tradableInstrument.instrument.product.settlementAsset.decimals;
+ const quantum =
+ market.tradableInstrument.instrument.product.settlementAsset.quantum;
const details: {
label: string;
value?: string | null;
+ formattedValue?: string | null;
symbol: string;
indent?: boolean;
labelDescription?: React.ReactNode;
@@ -103,6 +114,7 @@ export const getFeeDetailsValues = ({
{
label: t('Notional'),
value: formatValue(notionalSize, assetDecimals),
+ formattedValue: formatValue(notionalSize, assetDecimals, quantum),
symbol: assetSymbol,
labelDescription: NOTIONAL_SIZE_TOOLTIP_TEXT(assetSymbol),
},
@@ -111,6 +123,9 @@ export const getFeeDetailsValues = ({
value:
feeEstimate?.totalFeeAmount &&
`~${formatValue(feeEstimate?.totalFeeAmount, assetDecimals)}`,
+ formattedValue:
+ feeEstimate?.totalFeeAmount &&
+ `~${formatValue(feeEstimate?.totalFeeAmount, assetDecimals, quantum)}`,
labelDescription: (
<>
@@ -154,6 +169,12 @@ export const getFeeDetailsValues = ({
}
details.push({
label: t('Margin required'),
+ formattedValue: formatRange(
+ marginRequiredBestCase,
+ marginRequiredWorstCase,
+ assetDecimals,
+ quantum
+ ),
value: formatRange(
marginRequiredBestCase,
marginRequiredWorstCase,
@@ -172,12 +193,13 @@ export const getFeeDetailsValues = ({
details.push({
indent: true,
label: t('Total margin available'),
+ formattedValue: formatValue(totalMarginAvailable, assetDecimals, quantum),
value: formatValue(totalMarginAvailable, assetDecimals),
symbol: assetSymbol,
labelDescription: TOTAL_MARGIN_AVAILABLE(
- formatValue(generalAccountBalance, assetDecimals),
- formatValue(marginAccountBalance, assetDecimals),
- formatValue(currentMaintenanceMargin, assetDecimals),
+ formatValue(generalAccountBalance, assetDecimals, quantum),
+ formatValue(marginAccountBalance, assetDecimals, quantum),
+ formatValue(currentMaintenanceMargin, assetDecimals, quantum),
assetSymbol
),
});
@@ -203,6 +225,16 @@ export const getFeeDetailsValues = ({
: '0',
assetDecimals
),
+ formattedValue: formatRange(
+ deductionFromCollateralBestCase > 0
+ ? deductionFromCollateralBestCase.toString()
+ : '0',
+ deductionFromCollateralWorstCase > 0
+ ? deductionFromCollateralWorstCase.toString()
+ : '0',
+ assetDecimals,
+ quantum
+ ),
symbol: assetSymbol,
labelDescription: DEDUCTION_FROM_COLLATERAL_TOOLTIP_TEXT(assetSymbol),
});
@@ -214,6 +246,12 @@ export const getFeeDetailsValues = ({
marginEstimate?.worstCase.initialLevel,
assetDecimals
),
+ formattedValue: formatRange(
+ marginEstimate?.bestCase.initialLevel,
+ marginEstimate?.worstCase.initialLevel,
+ assetDecimals,
+ quantum
+ ),
symbol: assetSymbol,
labelDescription: EST_TOTAL_MARGIN_TOOLTIP_TEXT,
});
@@ -223,9 +261,11 @@ export const getFeeDetailsValues = ({
value: formatValue(marginAccountBalance, assetDecimals),
symbol: assetSymbol,
labelDescription: MARGIN_ACCOUNT_TOOLTIP_TEXT,
+ formattedValue: formatValue(marginAccountBalance, assetDecimals, quantum),
});
let liquidationPriceEstimate = emptyValue;
+ let liquidationPriceEstimateFormatted;
if (liquidationEstimate) {
const liquidationEstimateBestCaseIncludingBuyOrders = BigInt(
@@ -262,11 +302,24 @@ export const getFeeDetailsValues = ({
).toString(),
assetDecimals
);
+ liquidationPriceEstimateFormatted = formatRange(
+ (liquidationEstimateBestCase < liquidationEstimateWorstCase
+ ? liquidationEstimateBestCase
+ : liquidationEstimateWorstCase
+ ).toString(),
+ (liquidationEstimateBestCase > liquidationEstimateWorstCase
+ ? liquidationEstimateBestCase
+ : liquidationEstimateWorstCase
+ ).toString(),
+ assetDecimals,
+ quantum
+ );
}
details.push({
label: t('Liquidation price estimate'),
value: liquidationPriceEstimate,
+ formattedValue: liquidationPriceEstimateFormatted,
symbol: assetSymbol,
labelDescription: LIQUIDATION_PRICE_ESTIMATE_TOOLTIP_TEXT,
});
diff --git a/libs/deal-ticket/src/test-helpers.ts b/libs/deal-ticket/src/test-helpers.ts
index a332ade69..1081752f8 100644
--- a/libs/deal-ticket/src/test-helpers.ts
+++ b/libs/deal-ticket/src/test-helpers.ts
@@ -32,6 +32,7 @@ export function generateMarket(override?: PartialDeep): Market {
symbol: 'tDAI',
name: 'tDAI',
decimals: 5,
+ quantum: '1',
__typename: 'Asset',
},
dataSourceSpecForTradingTermination: {
diff --git a/libs/fills/src/lib/test-helpers.ts b/libs/fills/src/lib/test-helpers.ts
index 3d815b355..1654dabb5 100644
--- a/libs/fills/src/lib/test-helpers.ts
+++ b/libs/fills/src/lib/test-helpers.ts
@@ -75,6 +75,7 @@ export const generateFill = (override?: PartialDeep) => {
name: 'assset-id',
symbol: 'SYM',
decimals: 18,
+ quantum: '1',
},
quoteName: '',
dataSourceSpecForTradingTermination: {
diff --git a/libs/markets/src/lib/__generated__/markets.ts b/libs/markets/src/lib/__generated__/markets.ts
index 2e3432339..addf669a7 100644
--- a/libs/markets/src/lib/__generated__/markets.ts
+++ b/libs/markets/src/lib/__generated__/markets.ts
@@ -7,12 +7,12 @@ export type DataSourceFilterFragment = { __typename?: 'Filter', key: { __typenam
export type DataSourceSpecFragment = { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } };
-export type MarketFieldsFragment = { __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 | null }, product: { __typename?: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } } }, dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } } }, marketTimestamps: { __typename?: 'MarketTimestamps', open: any, close: any } };
+export type MarketFieldsFragment = { __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 | null }, product: { __typename?: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number, quantum: string }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } } }, dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } } }, marketTimestamps: { __typename?: 'MarketTimestamps', open: any, close: any } };
export type MarketsQueryVariables = Types.Exact<{ [key: string]: never; }>;
-export type MarketsQuery = { __typename?: 'Query', marketsConnection?: { __typename?: 'MarketConnection', edges: Array<{ __typename?: 'MarketEdge', node: { __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 | null }, product: { __typename?: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } } }, dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } } }, marketTimestamps: { __typename?: 'MarketTimestamps', open: any, close: any } } }> } | null };
+export type MarketsQuery = { __typename?: 'Query', marketsConnection?: { __typename?: 'MarketConnection', edges: Array<{ __typename?: 'MarketEdge', node: { __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 | null }, product: { __typename?: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number, quantum: string }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } } }, dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } } }, marketTimestamps: { __typename?: 'MarketTimestamps', open: any, close: any } } }> } | null };
export const DataSourceFilterFragmentDoc = gql`
fragment DataSourceFilter on Filter {
@@ -77,6 +77,7 @@ export const MarketFieldsFragmentDoc = gql`
symbol
name
decimals
+ quantum
}
quoteName
dataSourceSpecForTradingTermination {
diff --git a/libs/markets/src/lib/markets.graphql b/libs/markets/src/lib/markets.graphql
index 74ae46100..84e25a6e2 100644
--- a/libs/markets/src/lib/markets.graphql
+++ b/libs/markets/src/lib/markets.graphql
@@ -58,6 +58,7 @@ fragment MarketFields on Market {
symbol
name
decimals
+ quantum
}
quoteName
dataSourceSpecForTradingTermination {
diff --git a/libs/markets/src/lib/markets.mock.ts b/libs/markets/src/lib/markets.mock.ts
index b634bd0d5..44ff183fe 100644
--- a/libs/markets/src/lib/markets.mock.ts
+++ b/libs/markets/src/lib/markets.mock.ts
@@ -60,6 +60,7 @@ export const createMarketFragment = (
symbol: 'tDAI',
name: 'tDAI',
decimals: 5,
+ quantum: '1',
__typename: 'Asset',
},
dataSourceSpecForTradingTermination: {
diff --git a/libs/orders/src/lib/components/mocks/generate-orders.ts b/libs/orders/src/lib/components/mocks/generate-orders.ts
index 1be8e2774..60ef14bf4 100644
--- a/libs/orders/src/lib/components/mocks/generate-orders.ts
+++ b/libs/orders/src/lib/components/mocks/generate-orders.ts
@@ -47,6 +47,7 @@ export const generateOrder = (partialOrder?: PartialDeep) => {
decimals: 1,
symbol: 'XYZ',
name: 'XYZ',
+ quantum: '1',
},
dataSourceSpecForTradingTermination: {
__typename: 'DataSourceSpec',
diff --git a/libs/utils/src/lib/format/number.spec.ts b/libs/utils/src/lib/format/number.spec.ts
index 3c2024d38..621b1decd 100644
--- a/libs/utils/src/lib/format/number.spec.ts
+++ b/libs/utils/src/lib/format/number.spec.ts
@@ -2,6 +2,7 @@ import BigNumber from 'bignumber.js';
import {
addDecimalsFormatNumber,
+ addDecimalsFormatNumberQuantum,
formatNumber,
formatNumberPercentage,
isNumeric,
@@ -23,6 +24,28 @@ describe('number utils', () => {
}
);
+ it.each([
+ { v: new BigNumber(123000), d: 5, o: '1.23', q: 0.1 },
+ { v: new BigNumber(123000), d: 3, o: '123.00', q: 0.1 },
+ { v: new BigNumber(123000), d: 1, o: '12,300.00', q: 0.1 },
+ { v: new BigNumber(123001000), d: 2, o: '1,230,010.00', q: 0.1 },
+ { v: new BigNumber(123001), d: 2, o: '1,230', q: 100 },
+ { v: new BigNumber(123001), d: 2, o: '1,230.01', q: 0.1 },
+ {
+ v: BigNumber('123456789123456789'),
+ d: 10,
+ o: '12,345,678.9123457',
+ q: '0.00003846',
+ },
+ ])(
+ 'formats with addDecimalsFormatNumberQuantum given number correctly',
+ ({ v, d, o, q }) => {
+ expect(addDecimalsFormatNumberQuantum(v.toString(), d, q)).toStrictEqual(
+ o
+ );
+ }
+ );
+
it.each([
{ v: new BigNumber(123), d: 3, o: '123.00' },
{ v: new BigNumber(123.123), d: 3, o: '123.123' },
diff --git a/libs/utils/src/lib/format/number.ts b/libs/utils/src/lib/format/number.ts
index 3cbf5a402..55e34cb1c 100644
--- a/libs/utils/src/lib/format/number.ts
+++ b/libs/utils/src/lib/format/number.ts
@@ -90,6 +90,18 @@ export const formatNumberFixed = (
return getFixedNumberFormat(formatDecimals).format(Number(rawValue));
};
+export const addDecimalsFormatNumberQuantum = (
+ rawValue: string | number,
+ decimalPlaces: number,
+ quantum: number | string
+) => {
+ if (isNaN(Number(quantum))) {
+ return addDecimalsFormatNumber(rawValue, decimalPlaces);
+ }
+ const numberDP = Math.max(0, Math.log10(100 / Number(quantum)));
+ return addDecimalsFormatNumber(rawValue, decimalPlaces, Math.ceil(numberDP));
+};
+
export const addDecimalsFormatNumber = (
rawValue: string | number,
decimalPlaces: number,
diff --git a/libs/withdraws/src/lib/withdraw-form-container.spec.tsx b/libs/withdraws/src/lib/withdraw-form-container.spec.tsx
index 69545b756..78ee7d7e4 100644
--- a/libs/withdraws/src/lib/withdraw-form-container.spec.tsx
+++ b/libs/withdraws/src/lib/withdraw-form-container.spec.tsx
@@ -165,6 +165,7 @@ describe('WithdrawFormContainer', () => {
name: 'asset-id',
symbol: 'tUSDC',
decimals: 5,
+ quantum: '1',
},
dataSourceSpecForTradingTermination: {
__typename: 'DataSourceSpec',