feat: update reward pot card
This commit is contained in:
@@ -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 @@
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user