feat(deal-ticket): calculate fees and discount base on volumeDiscountStats and referralSetStats (#5147)

Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
This commit is contained in:
Bartłomiej Głownia 2023-10-31 02:13:26 +01:00 committed by GitHub
parent 3072b7824f
commit 4c95db5fb3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 368 additions and 101 deletions

View File

@ -26,11 +26,7 @@ import {
EST_TOTAL_MARGIN_TOOLTIP_TEXT, EST_TOTAL_MARGIN_TOOLTIP_TEXT,
MARGIN_ACCOUNT_TOOLTIP_TEXT, MARGIN_ACCOUNT_TOOLTIP_TEXT,
} from '../../constants'; } from '../../constants';
import { import { useEstimateFees } from '../../hooks/use-estimate-fees';
sumFees,
sumFeesDiscounts,
useEstimateFees,
} from '../../hooks/use-estimate-fees';
import { KeyValue } from './key-value'; import { KeyValue } from './key-value';
import { import {
Accordion, Accordion,
@ -44,6 +40,7 @@ import {
import classNames from 'classnames'; import classNames from 'classnames';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import { FeesBreakdown } from '../fees-breakdown'; import { FeesBreakdown } from '../fees-breakdown';
import { getTotalDiscountFactor, getDiscountedFee } from '../discounts';
const emptyValue = '-'; const emptyValue = '-';
@ -63,48 +60,49 @@ export const DealTicketFeeDetails = ({
const feeEstimate = useEstimateFees(order, isMarketInAuction); const feeEstimate = useEstimateFees(order, isMarketInAuction);
const asset = getAsset(market); const asset = getAsset(market);
const { decimals: assetDecimals, quantum } = asset; const { decimals: assetDecimals, quantum } = asset;
const totalFees = feeEstimate?.fees && sumFees(feeEstimate?.fees);
const feesDiscounts =
feeEstimate?.fees && sumFeesDiscounts(feeEstimate?.fees);
const totalPercentageDiscount = const totalDiscountFactor = getTotalDiscountFactor(feeEstimate);
feesDiscounts && const totalDiscountedFeeAmount =
totalFees && feeEstimate?.totalFeeAmount &&
feesDiscounts.total !== '0' && getDiscountedFee(
totalFees !== '0' && feeEstimate.totalFeeAmount,
new BigNumber(feesDiscounts.total) feeEstimate.referralDiscountFactor,
.dividedBy(BigNumber.sum(totalFees, feesDiscounts.total)) feeEstimate.volumeDiscountFactor
.times(100); ).discountedFee;
return ( return (
<KeyValue <KeyValue
label={t('Fees')} label={t('Fees')}
value={ value={
feeEstimate?.totalFeeAmount && totalDiscountedFeeAmount &&
`~${formatValue(feeEstimate?.totalFeeAmount, assetDecimals)}` `~${formatValue(totalDiscountedFeeAmount, assetDecimals)}`
} }
formattedValue={ formattedValue={
<> <>
{totalPercentageDiscount && ( {totalDiscountFactor && (
<Pill size="xxs" intent={Intent.Warning} className="mr-1"> <Pill size="xxs" intent={Intent.Warning} className="mr-1">
-{formatNumberPercentage(totalPercentageDiscount, 2)} -
{formatNumberPercentage(
new BigNumber(totalDiscountFactor).multipliedBy(100),
2
)}
</Pill> </Pill>
)} )}
{feeEstimate?.totalFeeAmount && {totalDiscountedFeeAmount &&
`~${formatValue( `~${formatValue(totalDiscountedFeeAmount, assetDecimals, quantum)}`}
feeEstimate?.totalFeeAmount,
assetDecimals,
quantum
)}`}
</> </>
} }
labelDescription={ labelDescription={
<> <>
<span> <p className="mb-2">
{t( {t(
`An estimate of the most you would be expected to pay in fees, in the market's settlement asset ${assetSymbol}. Fees estimated are "taker" fees and will only be payable if the order trades aggressively. Rebate equal to the maker portion will be paid to the trader if the order trades passively.` `An estimate of the most you would be expected to pay in fees, in the market's settlement asset ${assetSymbol}. Fees estimated are "taker" fees and will only be payable if the order trades aggressively. Rebate equal to the maker portion will be paid to the trader if the order trades passively.`
)} )}
</span> </p>
<FeesBreakdown <FeesBreakdown
totalFeeAmount={feeEstimate?.totalFeeAmount}
referralDiscountFactor={feeEstimate?.referralDiscountFactor}
volumeDiscountFactor={feeEstimate?.volumeDiscountFactor}
fees={feeEstimate?.fees} fees={feeEstimate?.fees}
feeFactors={market.fees.factors} feeFactors={market.fees.factors}
symbol={assetSymbol} symbol={assetSymbol}

View File

@ -0,0 +1,66 @@
import { getDiscountedFee, getTotalDiscountFactor } from './discounts';
describe('getDiscountedFee', () => {
it('calculates values if volumeDiscount or referralDiscount is undefined', () => {
expect(getDiscountedFee('100')).toEqual({
discountedFee: '100',
volumeDiscount: '0',
referralDiscount: '0',
});
expect(getDiscountedFee('100', undefined, '0.1')).toEqual({
discountedFee: '90',
volumeDiscount: '10',
referralDiscount: '0',
});
expect(getDiscountedFee('100', '0.1', undefined)).toEqual({
discountedFee: '90',
volumeDiscount: '0',
referralDiscount: '10',
});
});
it('calculates values using volumeDiscount or referralDiscount', () => {
expect(getDiscountedFee('', '0.1', '0.2')).toEqual({
discountedFee: '',
volumeDiscount: '0',
referralDiscount: '0',
});
});
});
describe('getTotalDiscountFactor', () => {
it('returns 0 if discounts are 0', () => {
expect(
getTotalDiscountFactor({
volumeDiscountFactor: '0',
referralDiscountFactor: '0',
})
).toEqual(0);
});
it('returns volumeDiscountFactor if referralDiscountFactor is 0', () => {
expect(
getTotalDiscountFactor({
volumeDiscountFactor: '0.1',
referralDiscountFactor: '0',
})
).toEqual(0.1);
});
it('returns referralDiscountFactor if volumeDiscountFactor is 0', () => {
expect(
getTotalDiscountFactor({
volumeDiscountFactor: '0',
referralDiscountFactor: '0.1',
})
).toEqual(0.1);
});
it('calculates discount using referralDiscountFactor and volumeDiscountFactor', () => {
expect(
getTotalDiscountFactor({
volumeDiscountFactor: '0.2',
referralDiscountFactor: '0.1',
})
).toBeCloseTo(0.28);
});
});

View File

@ -0,0 +1,54 @@
import BigNumber from 'bignumber.js';
export const getDiscountedFee = (
feeAmount: string,
referralDiscountFactor?: string,
volumeDiscountFactor?: string
) => {
if (
((!referralDiscountFactor || referralDiscountFactor === '0') &&
(!volumeDiscountFactor || volumeDiscountFactor === '0')) ||
!feeAmount ||
feeAmount === '0'
) {
return {
discountedFee: feeAmount,
volumeDiscount: '0',
referralDiscount: '0',
};
}
const referralDiscount = new BigNumber(referralDiscountFactor || '0')
.multipliedBy(feeAmount)
.toFixed(0, BigNumber.ROUND_FLOOR);
const volumeDiscount = new BigNumber(volumeDiscountFactor || '0')
.multipliedBy((BigInt(feeAmount) - BigInt(referralDiscount)).toString())
.toFixed(0, BigNumber.ROUND_FLOOR);
const discountedFee = (
BigInt(feeAmount || '0') -
BigInt(referralDiscount) -
BigInt(volumeDiscount)
).toString();
return {
referralDiscount,
volumeDiscount,
discountedFee,
};
};
export const getTotalDiscountFactor = (feeEstimate?: {
volumeDiscountFactor?: string;
referralDiscountFactor?: string;
}) => {
if (!feeEstimate) {
return 0;
}
const volumeFactor = Number(feeEstimate?.volumeDiscountFactor) || 0;
const referralFactor = Number(feeEstimate?.referralDiscountFactor) || 0;
if (!volumeFactor) {
return referralFactor;
}
if (!referralFactor) {
return volumeFactor;
}
return 1 - (1 - volumeFactor) * (1 - referralFactor);
};

View File

@ -6,7 +6,7 @@ import {
} from '@vegaprotocol/utils'; } from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import { sumFees, sumFeesDiscounts } from '../../hooks'; import { getDiscountedFee } from '../discounts';
const formatValue = ( const formatValue = (
value: string | number | null | undefined, value: string | number | null | undefined,
@ -24,7 +24,7 @@ const FeesBreakdownItem = ({
decimals, decimals,
}: { }: {
label: string; label: string;
factor?: BigNumber; factor?: string;
value: string; value: string;
symbol?: string; symbol?: string;
decimals: number; decimals: number;
@ -43,76 +43,86 @@ const FeesBreakdownItem = ({
); );
export const FeesBreakdown = ({ export const FeesBreakdown = ({
totalFeeAmount,
fees, fees,
feeFactors, feeFactors,
symbol, symbol,
decimals, decimals,
referralDiscountFactor,
volumeDiscountFactor,
}: { }: {
totalFeeAmount?: string;
fees?: TradeFee; fees?: TradeFee;
feeFactors?: FeeFactors; feeFactors?: FeeFactors;
symbol?: string; symbol?: string;
decimals: number; decimals: number;
referralDiscountFactor?: string;
volumeDiscountFactor?: string;
}) => { }) => {
if (!fees) return null; if (!fees || !totalFeeAmount || totalFeeAmount === '0') return null;
const totalFees = sumFees(fees);
const { const { discountedFee: discountedInfrastructureFee } = getDiscountedFee(
total: totalDiscount, fees.infrastructureFee,
referral: referralDiscount, referralDiscountFactor,
volume: volumeDiscount, volumeDiscountFactor
} = sumFeesDiscounts(fees); );
if (totalFees === '0') return null;
const { discountedFee: discountedLiquidityFee } = getDiscountedFee(
fees.liquidityFee,
referralDiscountFactor,
volumeDiscountFactor
);
const { discountedFee: discountedMakerFee } = getDiscountedFee(
fees.makerFee,
referralDiscountFactor,
volumeDiscountFactor
);
const { volumeDiscount, referralDiscount } = getDiscountedFee(
totalFeeAmount,
referralDiscountFactor,
volumeDiscountFactor
);
return ( return (
<dl className="grid grid-cols-6"> <dl className="grid grid-cols-6">
<FeesBreakdownItem <FeesBreakdownItem
label={t('Infrastructure fee')} label={t('Infrastructure fee')}
factor={ factor={feeFactors?.infrastructureFee}
feeFactors?.infrastructureFee value={discountedInfrastructureFee}
? new BigNumber(feeFactors?.infrastructureFee)
: undefined
}
value={fees.infrastructureFee}
symbol={symbol} symbol={symbol}
decimals={decimals} decimals={decimals}
/> />
<FeesBreakdownItem <FeesBreakdownItem
label={t('Liquidity fee')} label={t('Liquidity fee')}
factor={ factor={feeFactors?.liquidityFee}
feeFactors?.liquidityFee value={discountedLiquidityFee}
? new BigNumber(feeFactors?.liquidityFee)
: undefined
}
value={fees.liquidityFee}
symbol={symbol} symbol={symbol}
decimals={decimals} decimals={decimals}
/> />
<FeesBreakdownItem <FeesBreakdownItem
label={t('Maker fee')} label={t('Maker fee')}
factor={ factor={feeFactors?.makerFee}
feeFactors?.makerFee ? new BigNumber(feeFactors?.makerFee) : undefined value={discountedMakerFee}
}
value={fees.makerFee}
symbol={symbol} symbol={symbol}
decimals={decimals} decimals={decimals}
/> />
{volumeDiscount && volumeDiscount !== '0' && ( {volumeDiscountFactor && volumeDiscount !== '0' && (
<FeesBreakdownItem <FeesBreakdownItem
label={t('Volume discount')} label={t('Volume discount')}
factor={new BigNumber(volumeDiscount).dividedBy( factor={volumeDiscountFactor}
BigNumber.sum(totalFees, totalDiscount)
)}
value={volumeDiscount} value={volumeDiscount}
symbol={symbol} symbol={symbol}
decimals={decimals} decimals={decimals}
/> />
)} )}
{referralDiscount && referralDiscount !== '0' && ( {referralDiscountFactor && referralDiscount !== '0' && (
<FeesBreakdownItem <FeesBreakdownItem
label={t('Referral discount')} label={t('Referral discount')}
factor={new BigNumber(referralDiscount).dividedBy( factor={referralDiscountFactor}
BigNumber.sum(totalFees, totalDiscount)
)}
value={referralDiscount} value={referralDiscount}
symbol={symbol} symbol={symbol}
decimals={decimals} decimals={decimals}
@ -120,8 +130,8 @@ export const FeesBreakdown = ({
)} )}
<FeesBreakdownItem <FeesBreakdownItem
label={t('Total fees')} label={t('Total fees')}
factor={feeFactors ? sumFeesFactors(feeFactors) : undefined} factor={feeFactors ? sumFeesFactors(feeFactors)?.toString() : undefined}
value={totalFees} value={totalFeeAmount}
symbol={symbol} symbol={symbol}
decimals={decimals} decimals={decimals}
/> />

View File

@ -31,4 +31,25 @@ query EstimateFees(
} }
totalFeeAmount totalFeeAmount
} }
epoch {
id
}
volumeDiscountStats(partyId: $partyId, pagination: { last: 1 }) {
edges {
node {
atEpoch
discountFactor
runningVolume
}
}
}
referralSetStats(partyId: $partyId, pagination: { last: 1 }) {
edges {
node {
atEpoch
discountFactor
referralSetRunningNotionalTakerVolume
}
}
}
} }

View File

@ -15,7 +15,7 @@ export type EstimateFeesQueryVariables = Types.Exact<{
}>; }>;
export type EstimateFeesQuery = { __typename?: 'Query', estimateFees: { __typename?: 'FeeEstimate', totalFeeAmount: string, fees: { __typename?: 'TradeFee', makerFee: string, infrastructureFee: string, liquidityFee: string, makerFeeReferralDiscount?: string | null, makerFeeVolumeDiscount?: string | null, infrastructureFeeReferralDiscount?: string | null, infrastructureFeeVolumeDiscount?: string | null, liquidityFeeReferralDiscount?: string | null, liquidityFeeVolumeDiscount?: string | null } } }; export type EstimateFeesQuery = { __typename?: 'Query', estimateFees: { __typename?: 'FeeEstimate', totalFeeAmount: string, fees: { __typename?: 'TradeFee', makerFee: string, infrastructureFee: string, liquidityFee: string, makerFeeReferralDiscount?: string | null, makerFeeVolumeDiscount?: string | null, infrastructureFeeReferralDiscount?: string | null, infrastructureFeeVolumeDiscount?: string | null, liquidityFeeReferralDiscount?: string | null, liquidityFeeVolumeDiscount?: string | null } }, epoch: { __typename?: 'Epoch', id: string }, volumeDiscountStats: { __typename?: 'VolumeDiscountStatsConnection', edges: Array<{ __typename?: 'VolumeDiscountStatsEdge', node: { __typename?: 'VolumeDiscountStats', atEpoch: number, discountFactor: string, runningVolume: string } } | null> }, referralSetStats: { __typename?: 'ReferralSetStatsConnection', edges: Array<{ __typename?: 'ReferralSetStatsEdge', node: { __typename?: 'ReferralSetStats', atEpoch: number, discountFactor: string, referralSetRunningNotionalTakerVolume: string } } | null> } };
export const EstimateFeesDocument = gql` export const EstimateFeesDocument = gql`
@ -43,6 +43,27 @@ export const EstimateFeesDocument = gql`
} }
totalFeeAmount totalFeeAmount
} }
epoch {
id
}
volumeDiscountStats(partyId: $partyId, pagination: {last: 1}) {
edges {
node {
atEpoch
discountFactor
runningVolume
}
}
}
referralSetStats(partyId: $partyId, pagination: {last: 1}) {
edges {
node {
atEpoch
discountFactor
referralSetRunningNotionalTakerVolume
}
}
}
} }
`; `;

View File

@ -6,6 +6,15 @@ export const estimateFeesQuery = (
override?: PartialDeep<EstimateFeesQuery> override?: PartialDeep<EstimateFeesQuery>
): EstimateFeesQuery => { ): EstimateFeesQuery => {
const defaultResult: EstimateFeesQuery = { const defaultResult: EstimateFeesQuery = {
epoch: {
id: '1',
},
referralSetStats: {
edges: [],
},
volumeDiscountStats: {
edges: [],
},
estimateFees: { estimateFees: {
__typename: 'FeeEstimate', __typename: 'FeeEstimate',
totalFeeAmount: '0.0006', totalFeeAmount: '0.0006',

View File

@ -5,6 +5,31 @@ import { Side, OrderTimeInForce, OrderType } from '@vegaprotocol/types';
import type { EstimateFeesQuery } from './__generated__/EstimateOrder'; import type { EstimateFeesQuery } from './__generated__/EstimateOrder';
const data: EstimateFeesQuery = { const data: EstimateFeesQuery = {
epoch: {
id: '2',
},
volumeDiscountStats: {
edges: [
{
node: {
atEpoch: 1,
discountFactor: '0.1',
runningVolume: '100',
},
},
],
},
referralSetStats: {
edges: [
{
node: {
atEpoch: 1,
discountFactor: '0.2',
referralSetRunningNotionalTakerVolume: '100',
},
},
],
},
estimateFees: { estimateFees: {
totalFeeAmount: '120', totalFeeAmount: '120',
fees: { fees: {
@ -54,6 +79,8 @@ describe('useEstimateFees', () => {
liquidityFee: '0', liquidityFee: '0',
makerFee: '0', makerFee: '0',
}, },
referralDiscountFactor: '0',
volumeDiscountFactor: '0',
}); });
expect(mockUseEstimateFeesQuery.mock.lastCall?.[0].skip).toBeTruthy(); expect(mockUseEstimateFeesQuery.mock.lastCall?.[0].skip).toBeTruthy();
}); });
@ -85,6 +112,46 @@ describe('useEstimateFees', () => {
makerFeeReferralDiscount: '5', makerFeeReferralDiscount: '5',
makerFeeVolumeDiscount: '6', makerFeeVolumeDiscount: '6',
}, },
referralDiscountFactor: '0',
volumeDiscountFactor: '0',
}); });
}); });
it('returns 0 discounts if discount stats are not at the current epoch', () => {
const { result } = renderHook(() =>
useEstimateFees(
{
marketId: 'marketId',
side: Side.SIDE_BUY,
size: '1',
price: '1',
timeInForce: OrderTimeInForce.TIME_IN_FORCE_FOK,
type: OrderType.TYPE_LIMIT,
},
true
)
);
expect(result.current?.referralDiscountFactor).toEqual('0');
expect(result.current?.volumeDiscountFactor).toEqual('0');
});
it('returns discounts', () => {
data.epoch.id = '1';
const { result } = renderHook(() =>
useEstimateFees(
{
marketId: 'marketId',
side: Side.SIDE_BUY,
size: '1',
price: '1',
timeInForce: OrderTimeInForce.TIME_IN_FORCE_FOK,
type: OrderType.TYPE_LIMIT,
},
true
)
);
expect(result.current?.referralDiscountFactor).toEqual('0.2');
expect(result.current?.volumeDiscountFactor).toEqual('0.1');
});
}); });

View File

@ -5,39 +5,22 @@ import type { EstimateFeesQuery } from './__generated__/EstimateOrder';
import { useEstimateFeesQuery } from './__generated__/EstimateOrder'; import { useEstimateFeesQuery } from './__generated__/EstimateOrder';
const divideByTwo = (n: string) => (BigInt(n) / BigInt(2)).toString(); const divideByTwo = (n: string) => (BigInt(n) / BigInt(2)).toString();
export const sumFeesDiscounts = (
fees: EstimateFeesQuery['estimateFees']['fees']
) => {
const volume = (
BigInt(fees.makerFeeVolumeDiscount || '0') +
BigInt(fees.infrastructureFeeVolumeDiscount || '0') +
BigInt(fees.liquidityFeeVolumeDiscount || '0')
).toString();
const referral = (
BigInt(fees.makerFeeReferralDiscount || '0') +
BigInt(fees.infrastructureFeeReferralDiscount || '0') +
BigInt(fees.liquidityFeeReferralDiscount || '0')
).toString();
return {
volume,
referral,
total: (BigInt(volume) + BigInt(referral)).toString(),
};
};
export const sumFees = (fees: EstimateFeesQuery['estimateFees']['fees']) =>
(
BigInt(fees.makerFee || '0') +
BigInt(fees.infrastructureFee || '0') +
BigInt(fees.liquidityFee || '0')
).toString();
export const useEstimateFees = ( export const useEstimateFees = (
order?: OrderSubmissionBody['orderSubmission'], order?: OrderSubmissionBody['orderSubmission'],
isMarketInAuction?: boolean isMarketInAuction?: boolean
): EstimateFeesQuery['estimateFees'] | undefined => { ):
| (EstimateFeesQuery['estimateFees'] & {
referralDiscountFactor: string;
volumeDiscountFactor: string;
})
| undefined => {
const { pubKey } = useVegaWallet(); const { pubKey } = useVegaWallet();
const { data } = useEstimateFeesQuery({ const {
data: currentData,
previousData,
loading,
} = useEstimateFeesQuery({
variables: order && { variables: order && {
marketId: order.marketId, marketId: order.marketId,
partyId: pubKey || '', partyId: pubKey || '',
@ -50,8 +33,21 @@ export const useEstimateFees = (
fetchPolicy: 'no-cache', fetchPolicy: 'no-cache',
skip: !pubKey || !order?.size || !order?.price || order.postOnly, skip: !pubKey || !order?.size || !order?.price || order.postOnly,
}); });
const data = loading ? currentData || previousData : currentData;
const volumeDiscountFactor =
(data?.volumeDiscountStats.edges[0]?.node.atEpoch.toString() ===
data?.epoch.id &&
data?.volumeDiscountStats.edges[0]?.node.discountFactor) ||
'0';
const referralDiscountFactor =
(data?.referralSetStats.edges[0]?.node.atEpoch.toString() ===
data?.epoch.id &&
data?.referralSetStats.edges[0]?.node.discountFactor) ||
'0';
if (order?.postOnly) { if (order?.postOnly) {
return { return {
volumeDiscountFactor,
referralDiscountFactor,
totalFeeAmount: '0', totalFeeAmount: '0',
fees: { fees: {
infrastructureFee: '0', infrastructureFee: '0',
@ -60,8 +56,13 @@ export const useEstimateFees = (
}, },
}; };
} }
return isMarketInAuction && data?.estimateFees if (!data?.estimateFees) {
return undefined;
}
return isMarketInAuction
? { ? {
volumeDiscountFactor,
referralDiscountFactor,
totalFeeAmount: divideByTwo(data.estimateFees.totalFeeAmount), totalFeeAmount: divideByTwo(data.estimateFees.totalFeeAmount),
fees: { fees: {
infrastructureFee: divideByTwo( infrastructureFee: divideByTwo(
@ -91,5 +92,9 @@ export const useEstimateFees = (
divideByTwo(data.estimateFees.fees.makerFeeVolumeDiscount), divideByTwo(data.estimateFees.fees.makerFeeVolumeDiscount),
}, },
} }
: data?.estimateFees; : {
volumeDiscountFactor,
referralDiscountFactor,
...data.estimateFees,
};
}; };

View File

@ -3,6 +3,7 @@ import type { Market, MarketMaybeWithDataAndCandles } from './markets-provider';
import { import {
calcTradedFactor, calcTradedFactor,
filterAndSortMarkets, filterAndSortMarkets,
sumFeesFactors,
totalFeesFactorsPercentage, totalFeesFactorsPercentage,
} from './market-utils'; } from './market-utils';
const { MarketState, MarketTradingMode } = Schema; const { MarketState, MarketTradingMode } = Schema;
@ -132,3 +133,15 @@ describe('calcTradedFactor', () => {
expect(fa > fb).toBeTruthy(); expect(fa > fb).toBeTruthy();
}); });
}); });
describe('sumFeesFactors', () => {
it('does not result in flop errors', () => {
expect(
sumFeesFactors({
makerFee: '0.1',
infrastructureFee: '0.2',
liquidityFee: '0.3',
})
).toEqual(0.6);
});
});

View File

@ -50,16 +50,19 @@ export const getQuoteName = (market: Partial<Market>) => {
}; };
export const sumFeesFactors = (fees: Market['fees']['factors']) => { export const sumFeesFactors = (fees: Market['fees']['factors']) => {
return fees if (!fees) return;
? new BigNumber(fees.makerFee)
.plus(fees.liquidityFee) return new BigNumber(fees.makerFee)
.plus(fees.infrastructureFee) .plus(fees.liquidityFee)
: undefined; .plus(fees.infrastructureFee)
.toNumber();
}; };
export const totalFeesFactorsPercentage = (fees: Market['fees']['factors']) => { export const totalFeesFactorsPercentage = (fees: Market['fees']['factors']) => {
const total = fees && sumFeesFactors(fees); const total = fees && sumFeesFactors(fees);
return total ? formatNumberPercentage(total.times(100)) : undefined; return total
? formatNumberPercentage(new BigNumber(total).times(100))
: undefined;
}; };
export const filterAndSortMarkets = (markets: MarketMaybeWithData[]) => { export const filterAndSortMarkets = (markets: MarketMaybeWithData[]) => {