diff --git a/apps/trading/components/fees-container/fees-container.tsx b/apps/trading/components/fees-container/fees-container.tsx
index 64f6bb018..6e4298cb3 100644
--- a/apps/trading/components/fees-container/fees-container.tsx
+++ b/apps/trading/components/fees-container/fees-container.tsx
@@ -7,7 +7,7 @@ import {
NetworkParams,
} from '@vegaprotocol/network-parameters';
import { useMarketList } from '@vegaprotocol/markets';
-import { formatNumber } from '@vegaprotocol/utils';
+import { formatNumber, formatNumberRounded } from '@vegaprotocol/utils';
import { useDiscountProgramsQuery, useFeesQuery } from './__generated__/Fees';
import { FeeCard } from './fees-card';
import { MarketFees } from './market-fees';
@@ -284,7 +284,7 @@ export const CurrentVolume = ({
return (
{requiredForNextTier > 0 && (
diff --git a/apps/trading/components/fees-container/utils.spec.ts b/apps/trading/components/fees-container/utils.spec.ts
new file mode 100644
index 000000000..c2b3cd86e
--- /dev/null
+++ b/apps/trading/components/fees-container/utils.spec.ts
@@ -0,0 +1,74 @@
+import BigNumber from 'bignumber.js';
+import { getAdjustedFee } from './utils';
+
+describe('getAdjustedFee', () => {
+ it('simple', () => {
+ const volumeDiscount = 0.5;
+ const referralDiscount = 0.5;
+
+ const infraFee = 0.1;
+ const makerFee = 0.1;
+ const liqFee = 0.1;
+
+ const fees = [
+ new BigNumber(infraFee),
+ new BigNumber(makerFee),
+ new BigNumber(liqFee),
+ ];
+
+ const discounts = [
+ new BigNumber(volumeDiscount),
+ new BigNumber(referralDiscount),
+ ];
+
+ // 1 - 0.5 - 0.5
+ const v = new BigNumber(1).minus(new BigNumber(volumeDiscount));
+
+ // 1 - 0.5 = 0.5
+ const r = new BigNumber(1).minus(new BigNumber(referralDiscount));
+
+ // 0.5 * 0.5 = 0.25
+ // 1 - 0.25 = 0.75
+ const factor = new BigNumber(1).minus(v.times(r));
+
+ // 0.1 + 0.1 + 0.1 = 0.3
+ const totalFees = fees.reduce((sum, x) => sum.plus(x), new BigNumber(0));
+
+ // 0.3 * 0.75 = 0.225
+ const expected = new BigNumber(totalFees).times(factor).toNumber();
+
+ expect(getAdjustedFee(fees, discounts)).toBe(expected);
+ });
+
+ it('combines discount factors multiplicativly', () => {
+ const volumeDiscount = 0.4;
+ const referralDiscount = 0.1;
+
+ const infraFee = 0.0005;
+ const makerFee = 0.0002;
+ const liqFee = 0.01;
+
+ const fees = [
+ new BigNumber(infraFee),
+ new BigNumber(makerFee),
+ new BigNumber(liqFee),
+ ];
+
+ const discounts = [
+ new BigNumber(volumeDiscount),
+ new BigNumber(referralDiscount),
+ ];
+
+ // formula for calculating adjusted fees
+ const v = new BigNumber(1).minus(new BigNumber(volumeDiscount));
+ const r = new BigNumber(1).minus(new BigNumber(referralDiscount));
+ const factor = new BigNumber(1).minus(v.times(r));
+
+ // summed fees
+ const totalFees = fees.reduce((sum, x) => sum.plus(x), new BigNumber(0));
+
+ const expected = new BigNumber(totalFees).times(factor).toNumber();
+
+ expect(getAdjustedFee(fees, discounts)).toBe(expected);
+ });
+});
diff --git a/apps/trading/components/fees-container/utils.ts b/apps/trading/components/fees-container/utils.ts
index e0ce161c2..30a4be30a 100644
--- a/apps/trading/components/fees-container/utils.ts
+++ b/apps/trading/components/fees-container/utils.ts
@@ -88,14 +88,18 @@ export const getReferralBenefitTier = (
/**
* Given a set of fees and a set of discounts return
* the adjusted fee factor
+ *
+ * Formula for calculating the adjusted fees
+ * total_discount_factor = 1 - (1 - volumeDiscount) * (1 - referralDiscount)
*/
export const getAdjustedFee = (fees: BigNumber[], discounts: BigNumber[]) => {
const totalFee = fees.reduce((sum, f) => sum.plus(f), new BigNumber(0));
- const totalDiscount = discounts.reduce(
- (sum, d) => sum.plus(d),
- new BigNumber(0)
- );
- return totalFee
- .times(BigNumber.max(0, new BigNumber(1).minus(totalDiscount)))
- .toNumber();
+
+ const combinedFactors = discounts.reduce((acc, d) => {
+ return acc.times(new BigNumber(1).minus(d));
+ }, new BigNumber(1));
+
+ const totalFactor = new BigNumber(1).minus(combinedFactors);
+
+ return totalFee.times(BigNumber.max(0, totalFactor)).toNumber();
};
diff --git a/libs/utils/src/lib/format/number.ts b/libs/utils/src/lib/format/number.ts
index 261502a38..783dfaf5c 100644
--- a/libs/utils/src/lib/format/number.ts
+++ b/libs/utils/src/lib/format/number.ts
@@ -179,3 +179,33 @@ export const toNumberParts = (
export const isNumeric = (
value?: string | number | BigNumber | bigint | null
): value is NonNullable => /^-?\d*\.?\d+$/.test(String(value));
+
+/**
+ * Format a number greater than 1 million with m for million, b for billion
+ * and t for trillion
+ */
+export const formatNumberRounded = (num: BigNumber) => {
+ let value = '';
+
+ const format = (divisor: string) => {
+ const result = num.dividedBy(divisor);
+ return result.isInteger() ? result.toString() : result.toFixed(1);
+ };
+
+ if (num.isGreaterThan(new BigNumber('1e14'))) {
+ value = '>100t';
+ } else if (num.isGreaterThanOrEqualTo(new BigNumber('1e12'))) {
+ // Trillion
+ value = `${format('1e12')}t`;
+ } else if (num.isGreaterThanOrEqualTo(new BigNumber('1e9'))) {
+ // Billion
+ value = `${format('1e9')}b`;
+ } else if (num.isGreaterThanOrEqualTo(new BigNumber('1e6'))) {
+ // Million
+ value = `${format('1e6')}m`;
+ } else {
+ value = formatNumber(num);
+ }
+
+ return value;
+};