feat: update reward pot card

This commit is contained in:
Matthew Russell
2023-11-14 21:55:36 -08:00
parent 6ea9258574
commit 389772f4e1
7 changed files with 272 additions and 44 deletions
+51 -2
View File
@@ -1,3 +1,4 @@
import { Tooltip } from '@vegaprotocol/ui-toolkit';
import classNames from 'classnames';
import type { ReactNode } from 'react';
@@ -17,10 +18,10 @@ export const Card = ({
className={classNames(
'p-4 bg-vega-clight-800 dark:bg-vega-cdark-800 col-span-full lg:col-auto',
'rounded-lg',
className
className,
)}
>
<h2 className="mb-3">{title}</h2>
<h2 className="mb-9">{title}</h2>
{loading ? <CardLoader /> : children}
</div>
);
@@ -34,3 +35,51 @@ export const CardLoader = () => {
</div>
);
};
export const CardStat = ({
value,
text,
highlight,
description,
}: {
value: ReactNode;
text?: string;
highlight?: boolean;
description?: ReactNode;
}) => {
const val = (
<span
className={classNames('inline-block text-3xl leading-none', {
'text-transparent bg-rainbow bg-clip-text': highlight,
'cursor-help': description,
})}
>
{value}
</span>
);
return (
<p className="leading-none">
{description ? <Tooltip description={description}>{val}</Tooltip> : val}
{text && (
<small className="block mt-0.5 text-xs text-muted">{text}</small>
)}
</p>
);
};
export const CardTable = ({ children }: { children: ReactNode }) => {
return (
<table className="w-full mt-0.5 text-xs text-muted">
<tbody>{children}</tbody>
</table>
);
};
export const CardTableTH = ({ children }: { children: ReactNode }) => {
return <th className="font-normal text-left">{children}</th>;
};
export const CardTableTD = ({ children }: { children: ReactNode }) => {
return <td className="text-right">{children}</td>;
};
+1 -1
View File
@@ -1 +1 @@
export { Card } from './card';
export { Card, CardStat, CardTable, CardTableTH, CardTableTD } from './card';
@@ -253,7 +253,7 @@ export const TradingFees = ({
: `${formatPercentage(adjustedTotal)}%`}
</p>
<CardTable>
<tr className="text-defualt">
<tr className="text-default">
<CardTableTH>{t('Total fee before discount')}</CardTableTH>
<CardTableTD>
{minTotal !== undefined && maxTotal !== undefined
@@ -0,0 +1,15 @@
query RewardsPage($partyId: ID!) {
party(id: $partyId) {
id
activityStreak {
isActive
activeFor
inactiveFor
rewardDistributionMultiplier
rewardVestingMultiplier
epoch
tradedVolume
openVolume
}
}
}
@@ -0,0 +1,58 @@
import * as Types from '@vegaprotocol/types';
import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
export type RewardsPageQueryVariables = Types.Exact<{
partyId: Types.Scalars['ID'];
}>;
export type RewardsPageQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, activityStreak?: { __typename?: 'PartyActivityStreak', isActive: boolean, activeFor: number, inactiveFor: number, rewardDistributionMultiplier: string, rewardVestingMultiplier: string, epoch: number, tradedVolume: string, openVolume: string } | null } | null };
export const RewardsPageDocument = gql`
query RewardsPage($partyId: ID!) {
party(id: $partyId) {
id
activityStreak {
isActive
activeFor
inactiveFor
rewardDistributionMultiplier
rewardVestingMultiplier
epoch
tradedVolume
openVolume
}
}
}
`;
/**
* __useRewardsPageQuery__
*
* To run a query within a React component, call `useRewardsPageQuery` and pass it any options that fit your needs.
* When your component renders, `useRewardsPageQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useRewardsPageQuery({
* variables: {
* partyId: // value for 'partyId'
* },
* });
*/
export function useRewardsPageQuery(baseOptions: Apollo.QueryHookOptions<RewardsPageQuery, RewardsPageQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<RewardsPageQuery, RewardsPageQueryVariables>(RewardsPageDocument, options);
}
export function useRewardsPageLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<RewardsPageQuery, RewardsPageQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<RewardsPageQuery, RewardsPageQueryVariables>(RewardsPageDocument, options);
}
export type RewardsPageQueryHookResult = ReturnType<typeof useRewardsPageQuery>;
export type RewardsPageLazyQueryHookResult = ReturnType<typeof useRewardsPageLazyQuery>;
export type RewardsPageQueryResult = Apollo.QueryResult<RewardsPageQuery, RewardsPageQueryVariables>;
@@ -1,18 +1,26 @@
import type { Account} from '@vegaprotocol/accounts';
import type { Account } from '@vegaprotocol/accounts';
import { useAccounts } from '@vegaprotocol/accounts';
import { t } from '@vegaprotocol/i18n';
import {
NetworkParams,
useNetworkParam,
useNetworkParams,
} from '@vegaprotocol/network-parameters';
import { AccountType } from '@vegaprotocol/types';
import { TradingAnchorButton, TradingButton } from '@vegaprotocol/ui-toolkit';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { Links } from '../../lib/links';
import BigNumber from 'bignumber.js';
import { Link } from 'react-router-dom';
import { Card } from '../card/card';
import {
Card,
CardStat,
CardTable,
CardTableTD,
CardTableTH,
} from '../card/card';
import { getQuantumValue } from '@vegaprotocol/assets';
import { useRewardsPageQuery } from './__generated__/Rewards';
import { TradingButton } from '@vegaprotocol/ui-toolkit';
import { formatPercentage } from '../fees-container/utils';
const REWARD_ACCOUNT_TYPES = [
AccountType.ACCOUNT_TYPE_VESTED_REWARDS,
@@ -21,36 +29,50 @@ const REWARD_ACCOUNT_TYPES = [
export const RewardsContainer = () => {
const { pubKey } = useVegaWallet();
const { param, loading: paramsLoading } = useNetworkParam(
NetworkParams.rewards_activityStreak_benefitTiers
);
const { params, loading: paramsLoading } = useNetworkParams([
NetworkParams.reward_asset,
NetworkParams.rewards_activityStreak_benefitTiers,
NetworkParams.rewards_vesting_baseRate,
]);
const { data: accounts, loading: accountsLoading } = useAccounts(pubKey);
const { data: rewardsData, loading: rewardsLoading } = useRewardsPageQuery({
variables: {
partyId: pubKey || '',
},
skip: !pubKey,
});
const loading = paramsLoading || accountsLoading;
const loading = paramsLoading || accountsLoading || rewardsLoading;
return (
<div className="p-4">
<h3 className="mb-4">Rewards</h3>
<div className="grid auto-rows-min grid-cols-6 gap-3">
<Card title={t('Reward pot')} className="lg:col-span-2">
<RewardPot accounts={accounts} />
</Card>
<Card title={t('Vesting')} className="lg:col-span-2">
TODO:
</Card>
<Card title={t('Rewards multipliers')} className="lg:col-span-2">
TODO:
</Card>
<Card
title={t('Activity streak')}
className="lg:col-span-3"
title={t('Reward pot')}
className="lg:col-span-2"
loading={loading}
>
<ActivityStreak />
<RewardPot accounts={accounts} rewardAssetId={params.reward_asset} />
</Card>
<Card title={t('Vesting')} className="lg:col-span-2" loading={loading}>
<Vesting baseRate={params.rewards_vesting_baseRate} />
</Card>
<Card
title={t('Rewards multipliers')}
className="lg:col-span-2"
loading={loading}
>
<Multipliers />
</Card>
{/*
<Card title={t('Activity streak')} className="lg:col-span-3">
TODO:
</Card>
<Card title={t('Reward hoarder bonus')} className="lg:col-span-3">
TODO:
</Card>
*/}
<Card title={t('Rewards history')} className="lg:col-span-full">
TODO:
</Card>
@@ -59,15 +81,17 @@ export const RewardsContainer = () => {
);
};
export const RewardPot = ({ accounts }: { accounts: Account[] | null }) => {
export const RewardPot = ({
accounts,
rewardAssetId,
}: {
accounts: Account[] | null;
rewardAssetId: string; // VEGA
}) => {
const rewardAccounts = accounts
? accounts.filter((a) => REWARD_ACCOUNT_TYPES.includes(a.type))
: [];
const vestedRewardAccounts = accounts
? accounts.filter((a) => a.type === AccountType.ACCOUNT_TYPE_VESTED_REWARDS)
: [];
const totalRewards = BigNumber.sum.apply(
null,
rewardAccounts.length
@@ -75,28 +99,110 @@ export const RewardPot = ({ accounts }: { accounts: Account[] | null }) => {
: [0]
);
const totalVestedRewards = BigNumber.sum.apply(
const rewardAssetAccounts = accounts
? accounts.filter((a) => {
return a.asset.id === rewardAssetId;
})
: [];
const vestedRewardAssetAccounts = rewardAssetAccounts.filter(
(a) => a.type === AccountType.ACCOUNT_TYPE_VESTED_REWARDS
);
const vestingRewardAssetAccounts = rewardAssetAccounts.filter(
(a) => a.type === AccountType.ACCOUNT_TYPE_VESTED_REWARDS
);
const totalVestedRewardsByRewardAsset = BigNumber.sum.apply(
null,
vestedRewardAccounts.length
? vestedRewardAccounts.map((a) =>
getQuantumValue(a.balance, a.asset.quantum)
)
vestedRewardAssetAccounts.length
? vestedRewardAssetAccounts.map((a) => a.balance)
: [0]
);
const totalVestingRewardsByRewardAsset = BigNumber.sum.apply(
null,
vestingRewardAssetAccounts.length
? vestingRewardAssetAccounts.map((a) => a.balance)
: [0]
);
const totalRewardAsset = totalVestedRewardsByRewardAsset.plus(
totalVestingRewardsByRewardAsset
);
return (
<div>
<p data-testid="total-rewards">
{totalRewards.toString()} {t('qUSD')}
</p>
<p data-testid="available-rewards">
{totalVestedRewards.toString()} {t('qUSD')}
</p>
<Link to={Links.TRANSFER()}>{t('Redeem')}</Link>
<div className="flex justify-between">
<CardStat
value={
<p data-testid="total-rewards">
{totalRewardAsset.toString()} {t('VEGA')}
</p>
}
/>
<CardStat
value={
<p data-testid="total-rewards">
{totalRewards.toString()} {t('qUSD')}
</p>
}
/>
</div>
<div className="flex flex-col gap-4">
<CardTable>
<tr>
<CardTableTH>{t('Locked VEGA')}</CardTableTH>
<CardTableTD>FOO</CardTableTD>
</tr>
<tr>
<CardTableTH>{t('Vesting VEGA')}</CardTableTH>
<CardTableTD>
{totalVestingRewardsByRewardAsset.toString()}
</CardTableTD>
</tr>
<tr>
<CardTableTH>{t('Available to withdraw this epoch')}</CardTableTH>
<CardTableTD>
{totalVestedRewardsByRewardAsset.toString()}
</CardTableTD>
</tr>
</CardTable>
<Link to={Links.TRANSFER()}>
<TradingButton size="small">{t('Redeem')}</TradingButton>
</Link>
</div>
</div>
);
};
const ActivityStreak = () => {
return <div>ActivityStreak</div>;
const Vesting = ({ baseRate }: { baseRate: string }) => {
const baseRateFormatted = formatPercentage(Number(baseRate));
return (
<div>
<CardStat value={baseRateFormatted + '%'} />
<CardTable>
<tr>
<CardTableTH>{t('Base rate')}</CardTableTH>
<CardTableTD>{baseRateFormatted}%</CardTableTD>
</tr>
<tr>
<CardTableTH>{t('Vesting multiplier')}</CardTableTH>
<CardTableTD>0%</CardTableTD>
</tr>
<tr>
<CardTableTH>{t('Available to withdraw next epoch')}</CardTableTH>
<CardTableTD>0%</CardTableTD>
</tr>
</CardTable>
</div>
);
};
const Multipliers = () => {
return (
<div>
<p className="text-sm text-muted">{t('No active reward bonuses')}</p>
</div>
);
};
@@ -8,6 +8,7 @@ import {
export const NetworkParams = {
blockchains_ethereumConfig: 'blockchains_ethereumConfig',
reward_asset: 'reward_asset',
rewards_activityStreak_benefitTiers: 'rewards_activityStreak_benefitTiers',
rewards_marketCreationQuantumMultiple:
'rewards_marketCreationQuantumMultiple',
reward_staking_delegation_payoutDelay:
@@ -178,7 +179,6 @@ export const NetworkParams = {
transfer_fee_factor: 'transfer_fee_factor',
transfer_minTransferQuantumMultiple: 'transfer_minTransferQuantumMultiple',
network_validators_incumbentBonus: 'network_validators_incumbentBonus',
rewards_activityStreak_benefitTiers: 'rewards_activityStreak_benefitTiers',
} as const;
type Params = typeof NetworkParams;