From 0776332ba76362ee3272bae9ab31fc1e2ee05787 Mon Sep 17 00:00:00 2001 From: Art Date: Thu, 9 Nov 2023 16:50:50 +0100 Subject: [PATCH] fix(trading): fees page issues (#5217) --- .../components/fees-container/Fees.graphql | 16 +++ .../fees-container/__generated__/Fees.ts | 18 ++- .../fees-container/fees-container.tsx | 129 ++++++++++++++++-- .../components/fees-container/stat.tsx | 22 ++- .../fees-container/use-referral-stats.spec.ts | 4 + .../fees-container/use-referral-stats.ts | 16 ++- .../components/fees-container/utils.spec.ts | 14 +- .../components/fees-container/utils.ts | 8 +- 8 files changed, 196 insertions(+), 31 deletions(-) diff --git a/apps/trading/components/fees-container/Fees.graphql b/apps/trading/components/fees-container/Fees.graphql index 0b058637d..f4e4f6b44 100644 --- a/apps/trading/components/fees-container/Fees.graphql +++ b/apps/trading/components/fees-container/Fees.graphql @@ -36,6 +36,22 @@ query Fees( } } } + referrer: referralSets(referrer: $partyId) { + edges { + node { + id + referrer + } + } + } + referee: referralSets(referee: $partyId) { + edges { + node { + id + referrer + } + } + } referralSetReferees(referee: $partyId) { edges { node { diff --git a/apps/trading/components/fees-container/__generated__/Fees.ts b/apps/trading/components/fees-container/__generated__/Fees.ts index 064f75229..aeb340c17 100644 --- a/apps/trading/components/fees-container/__generated__/Fees.ts +++ b/apps/trading/components/fees-container/__generated__/Fees.ts @@ -15,7 +15,7 @@ export type FeesQueryVariables = Types.Exact<{ }>; -export type FeesQuery = { __typename?: 'Query', epoch: { __typename?: 'Epoch', id: string }, volumeDiscountStats: { __typename?: 'VolumeDiscountStatsConnection', edges: Array<{ __typename?: 'VolumeDiscountStatsEdge', node: { __typename?: 'VolumeDiscountStats', atEpoch: number, discountFactor: string, runningVolume: string } } | null> }, referralSetReferees: { __typename?: 'ReferralSetRefereeConnection', edges: Array<{ __typename?: 'ReferralSetRefereeEdge', node: { __typename?: 'ReferralSetReferee', atEpoch: number } } | null> }, referralSetStats: { __typename?: 'ReferralSetStatsConnection', edges: Array<{ __typename?: 'ReferralSetStatsEdge', node: { __typename?: 'ReferralSetStats', atEpoch: number, discountFactor: string, referralSetRunningNotionalTakerVolume: string } } | null> } }; +export type FeesQuery = { __typename?: 'Query', epoch: { __typename?: 'Epoch', id: string }, volumeDiscountStats: { __typename?: 'VolumeDiscountStatsConnection', edges: Array<{ __typename?: 'VolumeDiscountStatsEdge', node: { __typename?: 'VolumeDiscountStats', atEpoch: number, discountFactor: string, runningVolume: string } } | null> }, referrer: { __typename?: 'ReferralSetConnection', edges: Array<{ __typename?: 'ReferralSetEdge', node: { __typename?: 'ReferralSet', id: string, referrer: string } } | null> }, referee: { __typename?: 'ReferralSetConnection', edges: Array<{ __typename?: 'ReferralSetEdge', node: { __typename?: 'ReferralSet', id: string, referrer: string } } | null> }, referralSetReferees: { __typename?: 'ReferralSetRefereeConnection', edges: Array<{ __typename?: 'ReferralSetRefereeEdge', node: { __typename?: 'ReferralSetReferee', atEpoch: number } } | null> }, referralSetStats: { __typename?: 'ReferralSetStatsConnection', edges: Array<{ __typename?: 'ReferralSetStatsEdge', node: { __typename?: 'ReferralSetStats', atEpoch: number, discountFactor: string, referralSetRunningNotionalTakerVolume: string } } | null> } }; export const DiscountProgramsDocument = gql` @@ -81,6 +81,22 @@ export const FeesDocument = gql` } } } + referrer: referralSets(referrer: $partyId) { + edges { + node { + id + referrer + } + } + } + referee: referralSets(referee: $partyId) { + edges { + node { + id + referrer + } + } + } referralSetReferees(referee: $partyId) { edges { node { diff --git a/apps/trading/components/fees-container/fees-container.tsx b/apps/trading/components/fees-container/fees-container.tsx index d63bc4e9a..ea4c8a095 100644 --- a/apps/trading/components/fees-container/fees-container.tsx +++ b/apps/trading/components/fees-container/fees-container.tsx @@ -17,6 +17,14 @@ import { useReferralStats } from './use-referral-stats'; import { formatPercentage, getAdjustedFee } from './utils'; import { Table, Td, Th, THead, Tr } from './table'; import BigNumber from 'bignumber.js'; +import { Links } from '../../lib/links'; +import { Link } from 'react-router-dom'; +import { + Tooltip, + VegaIcon, + VegaIconNames, + truncateMiddle, +} from '@vegaprotocol/ui-toolkit'; export const FeesContainer = () => { const { pubKey } = useVegaWallet(); @@ -56,16 +64,25 @@ export const FeesContainer = () => { referralTierIndex, referralTiers, epochsInSet, + code, + isReferrer, } = useReferralStats( feesData?.referralSetStats, feesData?.referralSetReferees, programData?.currentReferralProgram, - feesData?.epoch + feesData?.epoch, + feesData?.referrer, + feesData?.referee ); const loading = paramsLoading || feesLoading || programLoading; const isConnected = Boolean(pubKey); + const isReferralProgramRunning = Boolean(programData?.currentReferralProgram); + const isVolumeDiscountProgramRunning = Boolean( + programData?.currentVolumeDiscountProgram + ); + return (
{isConnected && ( @@ -90,6 +107,8 @@ export const FeesContainer = () => { { className="sm:col-span-2" loading={loading} > - + {isVolumeDiscountProgramRunning ? ( + + ) : ( +

+ {t('No volume discount program active')} +

+ )}
- + {isReferrer ? ( + + ) : isReferralProgramRunning ? ( + + ) : ( +

+ {t('No referral program active')} +

+ )}
)} @@ -142,7 +175,7 @@ export const FeesContainer = () => { /> @@ -325,26 +358,64 @@ const ReferralBenefits = ({ const TotalDiscount = ({ referralDiscount, volumeDiscount, + isReferralProgramRunning, + isVolumeDiscountProgramRunning, }: { referralDiscount: number; volumeDiscount: number; + isReferralProgramRunning: boolean; + isVolumeDiscountProgramRunning: boolean; }) => { + const totalDiscount = 1 - (1 - volumeDiscount) * (1 - referralDiscount); + const totalDiscountDescription = t( + 'The total discount is calculated according to the following formula: ' + ); + const formula = ( + + 1 - (1 - dvolume) ⋇ (1 - dreferral) + + ); + return (
+ {totalDiscountDescription} + {formula} + + } + value={formatPercentage(totalDiscount) + '%'} highlight={true} /> - + @@ -491,3 +562,31 @@ const YourTier = () => { ); }; + +const ReferrerInfo = ({ code }: { code?: string }) => ( +
+

+ {t('Connected key is owner of the referral set')} + {code && ( + <> + {' '} + + {truncateMiddle(code)} + + + )} + {'. '} + {t('As owner, it is eligible for commission not fee discounts.')} +

+

+ {t('See')}{' '} + + {t('Referrals')} + {' '} + {t('for more information.')} +

+
+); diff --git a/apps/trading/components/fees-container/stat.tsx b/apps/trading/components/fees-container/stat.tsx index fe2784aae..307b77ff0 100644 --- a/apps/trading/components/fees-container/stat.tsx +++ b/apps/trading/components/fees-container/stat.tsx @@ -1,23 +1,31 @@ +import { Tooltip } from '@vegaprotocol/ui-toolkit'; import classNames from 'classnames'; +import type { ReactNode } from 'react'; export const Stat = ({ value, text, highlight, + description, }: { value: string | number; text?: string; highlight?: boolean; + description?: ReactNode; }) => { + const val = ( + + {value} + + ); return (

- - {value} - + {description ? {val} : val} {text && ( {text} )} diff --git a/apps/trading/components/fees-container/use-referral-stats.spec.ts b/apps/trading/components/fees-container/use-referral-stats.spec.ts index ffd3c4a7c..e38eb899d 100644 --- a/apps/trading/components/fees-container/use-referral-stats.spec.ts +++ b/apps/trading/components/fees-container/use-referral-stats.spec.ts @@ -73,6 +73,8 @@ describe('useReferralStats', () => { referralTierIndex: -1, referralTiers: [], epochsInSet: 0, + code: undefined, + isReferrer: false, }); }); @@ -93,6 +95,8 @@ describe('useReferralStats', () => { referralTierIndex: 1, referralTiers: program.benefitTiers, epochsInSet: Number(epoch.id) - set.atEpoch, + code: undefined, + isReferrer: false, }); }); diff --git a/apps/trading/components/fees-container/use-referral-stats.ts b/apps/trading/components/fees-container/use-referral-stats.ts index dbdafb41b..94821ed70 100644 --- a/apps/trading/components/fees-container/use-referral-stats.ts +++ b/apps/trading/components/fees-container/use-referral-stats.ts @@ -2,12 +2,15 @@ import compact from 'lodash/compact'; import maxBy from 'lodash/maxBy'; import { getReferralBenefitTier } from './utils'; import type { DiscountProgramsQuery, FeesQuery } from './__generated__/Fees'; +import { first } from 'lodash'; export const useReferralStats = ( setStats?: FeesQuery['referralSetStats'], setReferees?: FeesQuery['referralSetReferees'], program?: DiscountProgramsQuery['currentReferralProgram'], - epoch?: FeesQuery['epoch'] + epoch?: FeesQuery['epoch'], + setIfReferrer?: FeesQuery['referrer'], + setIfReferee?: FeesQuery['referee'] ) => { const referralTiers = program?.benefitTiers || []; @@ -18,9 +21,18 @@ export const useReferralStats = ( referralTierIndex: -1, referralTiers, epochsInSet: 0, + code: undefined, + isReferrer: false, }; } + const setIfReferrerData = first( + compact(setIfReferrer?.edges).map((e) => e.node) + ); + const setIfRefereeData = first( + compact(setIfReferee?.edges).map((e) => e.node) + ); + const referralSetsStats = compact(setStats.edges).map((e) => e.node); const referralSets = compact(setReferees.edges).map((e) => e.node); @@ -48,5 +60,7 @@ export const useReferralStats = ( referralTierIndex, referralTiers, epochsInSet, + code: (setIfReferrerData || setIfRefereeData)?.id, + isReferrer: Boolean(setIfReferrerData), }; }; diff --git a/apps/trading/components/fees-container/utils.spec.ts b/apps/trading/components/fees-container/utils.spec.ts index c2b3cd86e..3f618cbdc 100644 --- a/apps/trading/components/fees-container/utils.spec.ts +++ b/apps/trading/components/fees-container/utils.spec.ts @@ -21,7 +21,7 @@ describe('getAdjustedFee', () => { new BigNumber(referralDiscount), ]; - // 1 - 0.5 - 0.5 + // 1 - 0.5 = 0.5 const v = new BigNumber(1).minus(new BigNumber(volumeDiscount)); // 1 - 0.5 = 0.5 @@ -34,13 +34,15 @@ describe('getAdjustedFee', () => { // 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(); + // (1 - 0.3) * 0.75 = 0.525 + const expected = new BigNumber(totalFees) + .times(new BigNumber(1).minus(factor)) + .toNumber(); expect(getAdjustedFee(fees, discounts)).toBe(expected); }); - it('combines discount factors multiplicativly', () => { + it('combines discount factors multiplicatively', () => { const volumeDiscount = 0.4; const referralDiscount = 0.1; @@ -67,7 +69,9 @@ describe('getAdjustedFee', () => { // summed fees const totalFees = fees.reduce((sum, x) => sum.plus(x), new BigNumber(0)); - const expected = new BigNumber(totalFees).times(factor).toNumber(); + const expected = new BigNumber(totalFees) + .times(new BigNumber(1).minus(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 30a4be30a..68b980035 100644 --- a/apps/trading/components/fees-container/utils.ts +++ b/apps/trading/components/fees-container/utils.ts @@ -12,7 +12,9 @@ export const formatPercentage = (num: number) => { const pct = new BigNumber(num).times(100); const dps = pct.decimalPlaces(); const formatter = new Intl.NumberFormat(getUserLocale(), { - minimumFractionDigits: dps || 0, + // set to 0 in order to remove the "trailing zeroes" for numbers such as: + // 0.123456789 -non-zero-min-> 12.3456800% -zero-min-> 12.34568% + minimumFractionDigits: 0, maximumFractionDigits: dps || 0, }); return formatter.format(parseFloat(pct.toFixed(5))); @@ -101,5 +103,7 @@ export const getAdjustedFee = (fees: BigNumber[], discounts: BigNumber[]) => { const totalFactor = new BigNumber(1).minus(combinedFactors); - return totalFee.times(BigNumber.max(0, totalFactor)).toNumber(); + return totalFee + .times(new BigNumber(1).minus(BigNumber.max(0, totalFactor))) + .toNumber(); };

{t('Volume discount')}{formatPercentage(volumeDiscount)}% + {formatPercentage(volumeDiscount)}% + {!isVolumeDiscountProgramRunning && ( + + + {' '} + + + + )} +
{t('Referral discount')} {formatPercentage(referralDiscount)}% + {!isReferralProgramRunning && ( + + + {' '} + + + + )}