fix: estimate order margin query asset decimal places fix (#2029)

* fix: estimate margin and fees update fix - use asset dp and normalize

* fix: update styling in fees breakdown component

* fix: fix cypress tests

* fix: format with asset dp only in react components

* fix: fix number formattingcd

* fix: remove comment

* fix: rename getMaximumDigitsNumberFormat

* fix: fix console-lite cypress tests
This commit is contained in:
m.ray 2022-11-11 14:44:53 +00:00 committed by GitHub
parent d3cb3896f4
commit 011ea97d23
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 87 additions and 49 deletions

View File

@ -266,10 +266,7 @@ describe('Market trade', { tags: '@smoke' }, () => {
.find('dt') .find('dt')
.eq(3) .eq(3)
.should('have.text', 'Est. Fees (tDAI)'); .should('have.text', 'Est. Fees (tDAI)');
cy.get('#step-2-panel') cy.get('#step-2-panel').find('dd').eq(3).should('have.text', '3 (3.03%)');
.find('dd')
.eq(3)
.should('have.text', '3.00000 (3.03%)');
} }
}); });
@ -291,10 +288,7 @@ describe('Market trade', { tags: '@smoke' }, () => {
cy.get('#step-3-panel').find('dd').eq(2).should('have.text', '98.93006'); cy.get('#step-3-panel').find('dd').eq(2).should('have.text', '98.93006');
cy.get('#step-3-panel') cy.get('#step-3-panel').find('dd').eq(3).should('have.text', '3 (3.03%)');
.find('dd')
.eq(3)
.should('have.text', '3.00000 (3.03%)');
cy.get('#step-3-panel').find('dd').eq(4).should('have.text', ' - '); cy.get('#step-3-panel').find('dd').eq(4).should('have.text', ' - ');

View File

@ -26,6 +26,9 @@ import {
toDecimal, toDecimal,
removeDecimal, removeDecimal,
addDecimalsFormatNumber, addDecimalsFormatNumber,
addDecimalsNormalizeNumber,
addDecimal,
formatNumber,
} from '@vegaprotocol/react-helpers'; } from '@vegaprotocol/react-helpers';
import { import {
useOrderSubmit, useOrderSubmit,
@ -142,6 +145,9 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
return null; return null;
}, [market.decimalPlaces, order.size, price]); }, [market.decimalPlaces, order.size, price]);
const assetDecimals =
market.tradableInstrument.instrument.product.settlementAsset.decimals;
const fees = useMemo(() => { const fees = useMemo(() => {
if (estMargin?.totalFees && notionalSize) { if (estMargin?.totalFees && notionalSize) {
const percentage = new BigNumber(estMargin?.totalFees) const percentage = new BigNumber(estMargin?.totalFees)
@ -150,11 +156,14 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
.decimalPlaces(2) .decimalPlaces(2)
.toString(); .toString();
return `${estMargin.totalFees} (${percentage}%)`; return `${addDecimalsNormalizeNumber(
estMargin.totalFees,
assetDecimals
)} (${formatNumber(addDecimal(percentage, assetDecimals), 2)}%)`;
} }
return null; return null;
}, [estMargin?.totalFees, notionalSize]); }, [assetDecimals, estMargin?.totalFees, notionalSize]);
const max = useMemo(() => { const max = useMemo(() => {
return new BigNumber(maxTrade) return new BigNumber(maxTrade)

View File

@ -25,13 +25,15 @@ export const useOrderMarginValidation = ({ market, estMargin }: Props) => {
partyBalance?.party?.accounts || [], partyBalance?.party?.accounts || [],
AccountType.ACCOUNT_TYPE_GENERAL AccountType.ACCOUNT_TYPE_GENERAL
); );
const assetDecimals =
market.tradableInstrument.instrument.product.settlementAsset.decimals;
const balance = settlementAccount const balance = settlementAccount
? toBigNum( ? toBigNum(
settlementAccount.balance || 0, settlementAccount.balance || 0,
settlementAccount.asset.decimals || 0 settlementAccount.asset.decimals || 0
) )
: toBigNum('0', 0); : toBigNum('0', assetDecimals);
const margin = toBigNum(estMargin?.margin || 0, 0); const margin = toBigNum(estMargin?.margin || 0, assetDecimals);
const { id, symbol, decimals } = const { id, symbol, decimals } =
market.tradableInstrument.instrument.product.settlementAsset; market.tradableInstrument.instrument.product.settlementAsset;
const balanceString = balance.toString(); const balanceString = balance.toString();

View File

@ -1,5 +1,9 @@
import { FeesBreakdown } from '@vegaprotocol/market-info'; import { FeesBreakdown } from '@vegaprotocol/market-info';
import { normalizeFormatNumber, t } from '@vegaprotocol/react-helpers'; import {
addDecimalsNormalizeNumber,
normalizeFormatNumber,
t,
} from '@vegaprotocol/react-helpers';
import { Schema } from '@vegaprotocol/types'; 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';
@ -96,6 +100,8 @@ export const getFeeDetailsValues = ({
estCloseOut, estCloseOut,
market, market,
}: FeeDetails) => { }: FeeDetails) => {
const assetDecimals =
market.tradableInstrument.instrument.product.settlementAsset.decimals;
const formatValueWithMarketDp = ( const formatValueWithMarketDp = (
value: string | number | null | undefined value: string | number | null | undefined
): string => { ): string => {
@ -107,10 +113,7 @@ export const getFeeDetailsValues = ({
value: string | number | null | undefined value: string | number | null | undefined
): string => { ): string => {
return value && !isNaN(Number(value)) return value && !isNaN(Number(value))
? normalizeFormatNumber( ? addDecimalsNormalizeNumber(value, assetDecimals)
value,
market.tradableInstrument.instrument.product.settlementAsset.decimals
)
: '-'; : '-';
}; };
return [ return [
@ -136,6 +139,7 @@ export const getFeeDetailsValues = ({
fees={estMargin?.fees} fees={estMargin?.fees}
feeFactors={market.fees.factors} feeFactors={market.fees.factors}
quoteName={quoteName} quoteName={quoteName}
decimals={assetDecimals}
/> />
</> </>
), ),

View File

@ -52,6 +52,15 @@ describe('useOrderMargin', () => {
price: '1000000', price: '1000000',
}, },
}, },
tradableInstrument: {
instrument: {
product: {
settlementAsset: {
decimals: 5,
},
},
},
},
}; };
const partyId = 'partyId'; const partyId = 'partyId';

View File

@ -1,7 +1,7 @@
import { BigNumber } from 'bignumber.js'; 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 { addDecimal, removeDecimal } from '@vegaprotocol/react-helpers'; import { removeDecimal } from '@vegaprotocol/react-helpers';
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';
@ -37,6 +37,7 @@ export const useOrderMargin = ({
}: Props): OrderMargin | null => { }: Props): OrderMargin | null => {
const marketPositions = useMarketPositions({ marketId: market.id, partyId }); const marketPositions = useMarketPositions({ marketId: market.id, partyId });
const markPriceData = useMarketDataMarkPrice(market.id); const markPriceData = useMarketDataMarkPrice(market.id);
const { data } = useEstimateOrderQuery({ const { data } = useEstimateOrderQuery({
variables: { variables: {
marketId: market.id, marketId: market.id,
@ -79,12 +80,12 @@ export const useOrderMargin = ({
const { makerFee, liquidityFee, infrastructureFee } = const { makerFee, liquidityFee, infrastructureFee } =
data.estimateOrder.fee; data.estimateOrder.fee;
return { return {
margin: addDecimal(margin, market.decimalPlaces), margin,
totalFees: addDecimal(fees, market.decimalPlaces), totalFees: fees,
fees: { fees: {
makerFee: addDecimal(makerFee, market.decimalPlaces), makerFee,
liquidityFee: addDecimal(liquidityFee, market.decimalPlaces), liquidityFee,
infrastructureFee: addDecimal(infrastructureFee, market.decimalPlaces), infrastructureFee,
}, },
}; };
} }

View File

@ -1,5 +1,9 @@
import { totalFeesPercentage } from '@vegaprotocol/market-list'; import { totalFeesPercentage } from '@vegaprotocol/market-list';
import { formatNumberPercentage, t } from '@vegaprotocol/react-helpers'; import {
addDecimalsNormalizeNumber,
formatNumberPercentage,
t,
} from '@vegaprotocol/react-helpers';
import { Tooltip } from '@vegaprotocol/ui-toolkit'; import { Tooltip } from '@vegaprotocol/ui-toolkit';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
@ -48,6 +52,7 @@ export const FeesBreakdown = ({
fees, fees,
feeFactors, feeFactors,
quoteName, quoteName,
decimals,
}: { }: {
fees?: { fees?: {
infrastructureFee: string; infrastructureFee: string;
@ -56,53 +61,61 @@ export const FeesBreakdown = ({
}; };
feeFactors?: Market['fees']['factors']; feeFactors?: Market['fees']['factors'];
quoteName?: string; quoteName?: string;
decimals: number;
}) => { }) => {
if (!fees) return null; if (!fees) return null;
const totalFees = new BigNumber(fees.makerFee) const totalFees = new BigNumber(fees.makerFee)
.plus(fees.infrastructureFee) .plus(fees.infrastructureFee)
.plus(fees.liquidityFee) .plus(fees.liquidityFee)
.toString(); .toString();
const formatValue = (value: string | number | null | undefined): string => {
return value && !isNaN(Number(value))
? addDecimalsNormalizeNumber(value, decimals)
: '-';
};
return ( return (
<dl className="grid grid-cols-3 gap-x-3"> <dl className="grid grid-cols-5">
<dt>{t('Infrastructure fee')}</dt> <dt className="col-span-2">{t('Infrastructure fee')}</dt>
{feeFactors && ( {feeFactors && (
<dd className="text-right"> <dd className="text-right col-span-1">
{formatNumberPercentage( {formatNumberPercentage(
new BigNumber(feeFactors.infrastructureFee).times(100) new BigNumber(feeFactors.infrastructureFee).times(100)
)} )}
</dd> </dd>
)} )}
<dd className="text-right"> <dd className="text-right col-span-2">
{fees.infrastructureFee} {quoteName || ''} {formatValue(fees.infrastructureFee)} {quoteName || ''}
</dd> </dd>
<dt>{t('Liquidity fee')}</dt> <dt className="col-span-2">{t('Liquidity fee')}</dt>
{feeFactors && ( {feeFactors && (
<dd className="text-right"> <dd className="text-right col-span-1">
{formatNumberPercentage( {formatNumberPercentage(
new BigNumber(feeFactors.liquidityFee).times(100) new BigNumber(feeFactors.liquidityFee).times(100)
)} )}
</dd> </dd>
)} )}
<dd className="text-right"> <dd className="text-right col-span-2">
{fees.liquidityFee} {quoteName || ''} {formatValue(fees.liquidityFee)} {quoteName || ''}
</dd> </dd>
<dt>{t('Maker fee')}</dt> <dt className="col-span-2">{t('Maker fee')}</dt>
{feeFactors && ( {feeFactors && (
<dd className="text-right"> <dd className="text-right col-span-1">
{formatNumberPercentage( {formatNumberPercentage(
new BigNumber(feeFactors.makerFee).times(100) new BigNumber(feeFactors.makerFee).times(100)
)} )}
</dd> </dd>
)} )}
<dd className="text-right"> <dd className="text-right col-span-2">
{fees.makerFee} {quoteName || ''} {formatValue(fees.makerFee)} {quoteName || ''}
</dd> </dd>
<dt>{t('Total fees')}</dt> <dt className="col-span-2">{t('Total fees')}</dt>
{feeFactors && ( {feeFactors && (
<dd className="text-right">{totalFeesPercentage(feeFactors)}</dd> <dd className="text-right col-span-1">
{totalFeesPercentage(feeFactors)}
</dd>
)} )}
<dd className="text-right"> <dd className="text-right col-span-2">
{totalFees} {quoteName || ''} {formatValue(totalFees)} {quoteName || ''}
</dd> </dd>
</dl> </dl>
); );

View File

@ -14,9 +14,9 @@ describe('number react-helpers', () => {
it.each([ it.each([
{ v: new BigNumber(123000), d: 5, o: '1.23' }, { v: new BigNumber(123000), d: 5, o: '1.23' },
{ v: new BigNumber(123000), d: 3, o: '123' }, { v: new BigNumber(123000), d: 3, o: '123' },
{ v: new BigNumber(123000), d: 1, o: '12,300.0' }, { v: new BigNumber(123000), d: 1, o: '12,300' },
{ v: new BigNumber(123001), d: 2, o: '1,230.01' }, { v: new BigNumber(123001), d: 2, o: '1,230.01' },
{ v: new BigNumber(123001000), d: 2, o: '1,230,010.00' }, { v: new BigNumber(123001000), d: 2, o: '1,230,010' },
])( ])(
'formats with addDecimalsNormalizeNumber given number correctly', 'formats with addDecimalsNormalizeNumber given number correctly',
({ v, d, o }) => { ({ v, d, o }) => {

View File

@ -49,6 +49,15 @@ export const getNumberFormat = memoize((digits: number) => {
}); });
}); });
export const getMaximumDigitsNumberFormat = memoize((digits: number) => {
if (isNil(digits) || digits < 0) {
return new Intl.NumberFormat(getUserLocale());
}
return new Intl.NumberFormat(getUserLocale(), {
maximumFractionDigits: Math.min(Math.max(0, digits), MAX_FRACTION_DIGITS),
});
});
export const getDecimalSeparator = memoize( export const getDecimalSeparator = memoize(
() => () =>
getNumberFormat(1) getNumberFormat(1)
@ -75,13 +84,10 @@ export const normalizeFormatNumber = (
rawValue: string | number | BigNumber, rawValue: string | number | BigNumber,
formatDecimals = 0 formatDecimals = 0
): string => { ): string => {
const numberToFormat = getNumberFormat(formatDecimals).format( const numberToFormat = getMaximumDigitsNumberFormat(formatDecimals).format(
Number(rawValue) new BigNumber(rawValue).toNumber()
); );
// Multiplying by 1 safely removes the insignificant trailing zeros from the formatted number return numberToFormat;
return !isNaN(Number(numberToFormat))
? (Number(numberToFormat) * 1).toString()
: numberToFormat;
}; };
export const addDecimalsFormatNumber = ( export const addDecimalsFormatNumber = (