diff --git a/apps/trading/components/rewards-container/Rewards.graphql b/apps/trading/components/rewards-container/Rewards.graphql index a1650ca2e..af44cb177 100644 --- a/apps/trading/components/rewards-container/Rewards.graphql +++ b/apps/trading/components/rewards-container/Rewards.graphql @@ -2,9 +2,14 @@ query RewardsPage($partyId: ID!) { party(id: $partyId) { id vestingStats { - epochSeq + # AKA hoarder reward multiplier rewardBonusMultiplier - quantumBalance + } + activityStreak { + # vesting multiplier + rewardVestingMultiplier + # AKA streak multiplier + rewardDistributionMultiplier } vestingBalancesSummary { epoch diff --git a/apps/trading/components/rewards-container/__generated__/Rewards.ts b/apps/trading/components/rewards-container/__generated__/Rewards.ts index 6d86accc8..3b28499ce 100644 --- a/apps/trading/components/rewards-container/__generated__/Rewards.ts +++ b/apps/trading/components/rewards-container/__generated__/Rewards.ts @@ -8,7 +8,7 @@ export type RewardsPageQueryVariables = Types.Exact<{ }>; -export type RewardsPageQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, vestingStats?: { __typename?: 'PartyVestingStats', epochSeq: number, rewardBonusMultiplier: string, quantumBalance: string } | null, vestingBalancesSummary: { __typename?: 'PartyVestingBalancesSummary', epoch?: number | null, vestingBalances?: Array<{ __typename?: 'PartyVestingBalance', balance: string, asset: { __typename?: 'Asset', id: string, symbol: string, decimals: number, quantum: string } }> | null, lockedBalances?: Array<{ __typename?: 'PartyLockedBalance', balance: string, untilEpoch: number, asset: { __typename?: 'Asset', id: string, symbol: string, decimals: number, quantum: string } }> | null } } | null }; +export type RewardsPageQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, vestingStats?: { __typename?: 'PartyVestingStats', rewardBonusMultiplier: string } | null, activityStreak?: { __typename?: 'PartyActivityStreak', rewardVestingMultiplier: string, rewardDistributionMultiplier: string } | null, vestingBalancesSummary: { __typename?: 'PartyVestingBalancesSummary', epoch?: number | null, vestingBalances?: Array<{ __typename?: 'PartyVestingBalance', balance: string, asset: { __typename?: 'Asset', id: string, symbol: string, decimals: number, quantum: string } }> | null, lockedBalances?: Array<{ __typename?: 'PartyLockedBalance', balance: string, untilEpoch: number, asset: { __typename?: 'Asset', id: string, symbol: string, decimals: number, quantum: string } }> | null } } | null }; export type RewardsHistoryQueryVariables = Types.Exact<{ partyId: Types.Scalars['ID']; @@ -32,9 +32,11 @@ export const RewardsPageDocument = gql` party(id: $partyId) { id vestingStats { - epochSeq rewardBonusMultiplier - quantumBalance + } + activityStreak { + rewardVestingMultiplier + rewardDistributionMultiplier } vestingBalancesSummary { epoch diff --git a/apps/trading/components/rewards-container/rewards-container.spec.tsx b/apps/trading/components/rewards-container/rewards-container.spec.tsx index 813cec183..41fb573d2 100644 --- a/apps/trading/components/rewards-container/rewards-container.spec.tsx +++ b/apps/trading/components/rewards-container/rewards-container.spec.tsx @@ -3,9 +3,6 @@ import type { Account } from '@vegaprotocol/accounts'; import { AccountType, AssetStatus } from '@vegaprotocol/types'; import { MemoryRouter } from 'react-router-dom'; import { RewardPot, Vesting, type RewardPotProps } from './rewards-container'; -import type { MockedResponse } from '@apollo/react-testing'; -import { MockedProvider } from '@apollo/react-testing'; -import { type AssetQuery, AssetDocument } from '@vegaprotocol/assets'; const rewardAsset = { id: 'asset-1', @@ -154,65 +151,27 @@ describe('RewardPot', () => { }); describe('Vesting', () => { - it('renders vesting rates', async () => { - const assetMock: MockedResponse = { - request: { - query: AssetDocument, - variables: { - assetId: rewardAsset.id, - }, - }, - result: { - data: { - assetsConnection: { - edges: [ - { - node: rewardAsset, - }, - ], - }, - }, - }, - }; - render( - - - + it('renders vesting rates', () => { + render(); + + expect(screen.getByTestId('vesting-rate')).toHaveTextContent('50%'); + + expect(screen.getByText('Base rate').nextElementSibling).toHaveTextContent( + '25%' ); + expect( + screen.getByText('Vesting multiplier').nextSibling + ).toHaveTextContent('2x'); + }); - const computedRate = await screen.findByTestId('vesting-rate'); - expect(computedRate).toHaveTextContent('50%'); + it('doesnt use multiplier if not connected', () => { + render(); - const baseRateLabel = screen.getByText(/Base rate/); - expect(baseRateLabel.nextElementSibling).toHaveTextContent('25%'); + expect(screen.getByTestId('vesting-rate')).toHaveTextContent('25%'); - const nextEpochLabel = screen.getByText('Available to withdraw next epoch'); - expect(nextEpochLabel.nextElementSibling).toHaveTextContent('2.50'); + expect(screen.getByText('Base rate').nextElementSibling).toHaveTextContent( + '25%' + ); + expect(screen.queryByText('Vesting multiplier')).not.toBeInTheDocument(); }); }); diff --git a/apps/trading/components/rewards-container/rewards-container.tsx b/apps/trading/components/rewards-container/rewards-container.tsx index 1e9d651db..7a4067031 100644 --- a/apps/trading/components/rewards-container/rewards-container.tsx +++ b/apps/trading/components/rewards-container/rewards-container.tsx @@ -31,7 +31,6 @@ import { addDecimalsFormatNumberQuantum } from '@vegaprotocol/utils'; import { ViewType, useSidebar } from '../sidebar'; import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id'; import { RewardsHistoryContainer } from './rewards-history'; -import { useAssetDataProvider } from '@vegaprotocol/assets'; export const RewardsContainer = () => { const { pubKey } = useVegaWallet(); @@ -72,7 +71,7 @@ export const RewardsContainer = () => { // TODO: Fix grid rows, they break on small screens when things stack return (
- {/* Always show the rewards pot for the reward asset AKA Vega */} + {/* Always show reward information for vega */} { vestingBalancesSummary={rewardsData?.party?.vestingBalancesSummary} /> + + + + + + - {/* Show all other rewards */} + {/* Show all other reward pots, most of the time users will not have other rewards */} {Object.keys(rewardAssetsMap).map((assetId) => { const asset = rewardAssetsMap[assetId][0].asset; return ( @@ -109,23 +132,6 @@ export const RewardsContainer = () => { ); })} - - - - - - { - const { data: asset } = useAssetDataProvider(assetId); - - if (!asset) return null; - const rate = new BigNumber(baseRate).times(multiplier); const rateFormatted = formatPercentage(Number(rate)); const baseRateFormatted = formatPercentage(Number(baseRate)); - const lockedEntries = vestingBalancesSummary?.lockedBalances?.filter( - (b) => b.asset.id === assetId - ); - - const unlockingNextEpoch = lockedEntries?.filter( - (e) => e.untilEpoch === epoch + 1 - ); - - const nextEpochBalances = unlockingNextEpoch?.length - ? unlockingNextEpoch.map((e) => e.balance) - : [0]; - - const totalUnlockingNextEpoch = BigNumber.sum.apply(null, nextEpochBalances); - return (
@@ -336,32 +318,44 @@ export const Vesting = ({ {baseRateFormatted}% {pubKey && ( - <> - - {t('Vesting multiplier')} - {multiplier} - - - {t('Available to withdraw next epoch')} - - {addDecimalsFormatNumberQuantum( - totalUnlockingNextEpoch.toString(), - asset.decimals, - asset.quantum - )} - - - + + {t('Vesting multiplier')} + {multiplier}x + )}
); }; -const Multipliers = () => { +const Multipliers = ({ + streakMultiplier = '1', + hoarderMultiplier = '1', +}: { + streakMultiplier?: string; + hoarderMultiplier?: string; +}) => { + const combinedMultiplier = new BigNumber(streakMultiplier).times( + hoarderMultiplier + ); + return (
-

{t('No active reward bonuses')}

+ + + + {t('Streak reward multiplier')} + {streakMultiplier}x + + + {t('Hoarder reward multiplier')} + {hoarderMultiplier}x + +
); };