diff --git a/src/app/collective-rewards/rewards/ClaimableRewards.tsx b/src/app/collective-rewards/rewards/ClaimableRewards.tsx new file mode 100644 index 00000000..14dec5a6 --- /dev/null +++ b/src/app/collective-rewards/rewards/ClaimableRewards.tsx @@ -0,0 +1,117 @@ +import { + formatMetrics, + MetricsCard, + MetricsCardTitle, + TokenMetricsCardRow, + useClaimBuilderRewards, + useClaimStateReporting, + useGetBuilderRewards, +} from '@/app/collective-rewards/rewards' +import { useHandleErrors } from '@/app/collective-rewards/utils' +import { formatBalanceToHuman } from '@/app/user/Balances/balanceUtils' +import { Button, ButtonProps } from '@/components/Button' +import { withSpinner } from '@/components/LoadingSpinner/withLoadingSpinner' +import { Popover } from '@/components/Popover' +import { usePricesContext } from '@/shared/context/PricesContext' +import { FC } from 'react' +import { Address } from 'viem' + +const ClaimYourRewardsSvg = () => ( + + + +) + +const ClaimYourRewardsButton: FC>> = buttonProps => ( +
+ +

Claim your rewards

+
+ } + size="small" + position="top" + trigger="hover" + > + + + +) + +type Token = { + symbol: string + address: Address +} + +type RewardsTokenMetricsProps = { + builder: Address + gauge: Address + token: Token + currency?: string +} + +const RewardsTokenMetrics: FC = ({ + builder, + gauge, + token: { address, symbol }, + currency = 'USD', +}) => { + const { prices } = usePricesContext() + + const { + data: rewards, + isLoading: isLoadingRewards, + error: rewardsError, + } = useGetBuilderRewards(address, gauge) + useHandleErrors({ error: rewardsError, title: 'Error loading rewards' }) + + const tokenPrice = prices[symbol]?.price ?? 0 + + const { amount, fiatAmount } = formatMetrics( + Number(formatBalanceToHuman(rewards ?? 0n)), + tokenPrice, + symbol, + currency, + ) + + const { isClaimFunctionReady, claimRewards, ...claimTx } = useClaimBuilderRewards(builder) + + useClaimStateReporting({ ...claimTx, error: rewardsError ?? claimTx.error }) + + return withSpinner(TokenMetricsCardRow)({ + amount, + fiatAmount, + isLoading: isLoadingRewards, + children: ( + claimRewards(address)} disabled={!isClaimFunctionReady} /> + ), + }) +} + +type ClaimableRewardsProps = { + builder: Address + gauge: Address + currency?: string + data: { + [token: string]: Token + } +} + +export const ClaimableRewards: FC = ({ data, ...rest }) => { + return ( + + + + + + ) +} diff --git a/src/app/collective-rewards/rewards/MyRewards.tsx b/src/app/collective-rewards/rewards/MyRewards.tsx index 012c89fb..e530fa27 100644 --- a/src/app/collective-rewards/rewards/MyRewards.tsx +++ b/src/app/collective-rewards/rewards/MyRewards.tsx @@ -3,9 +3,10 @@ import { Address, getAddress } from 'viem' import { RewardsSection, RewardsSectionHeader, - useClaimAllRewards, + useClaimBuilderRewards, useClaimStateReporting, LastCycleRewards, + ClaimableRewards, } from '@/app/collective-rewards/rewards' import { CycleContextProvider } from '@/app/collective-rewards/metrics' import { PricesContextProvider } from '@/shared/context/PricesContext' @@ -16,7 +17,7 @@ import { Button } from '@/components/Button' import { Paragraph } from '@/components/Typography' export const Rewards: FC<{ builder: Address; gauge: Address }> = ({ builder, gauge }) => { - const { isClaimFunctionReady, claimAllRewards, ...claimTx } = useClaimAllRewards(builder) + const { isClaimFunctionReady, claimRewards, ...claimTx } = useClaimBuilderRewards(builder) useClaimStateReporting({ ...claimTx }) @@ -44,7 +45,7 @@ export const Rewards: FC<{ builder: Address; gauge: Address }> = ({ builder, gau
-
Claimable Rewards
+
Estimated Rewards
All time rewards
@@ -62,7 +63,7 @@ export const Rewards: FC<{ builder: Address; gauge: Address }> = ({ builder, gau position="bottom" className="z-[100]" > - diff --git a/src/app/collective-rewards/rewards/hooks/index.ts b/src/app/collective-rewards/rewards/hooks/index.ts index e227d850..418750a7 100644 --- a/src/app/collective-rewards/rewards/hooks/index.ts +++ b/src/app/collective-rewards/rewards/hooks/index.ts @@ -1,4 +1,5 @@ -export * from './useClaimAllRewards' +export * from './useClaimBuilderRewards' +export * from './useGetBuilderRewards' export * from './useGetRewardDistributedLogs' export * from './useGetTokenProjectedReward' export * from './useGetNotifyRewardLogs' diff --git a/src/app/collective-rewards/rewards/hooks/useClaimAllRewards.ts b/src/app/collective-rewards/rewards/hooks/useClaimBuilderRewards.ts similarity index 89% rename from src/app/collective-rewards/rewards/hooks/useClaimAllRewards.ts rename to src/app/collective-rewards/rewards/hooks/useClaimBuilderRewards.ts index 4645e2a3..2075169b 100644 --- a/src/app/collective-rewards/rewards/hooks/useClaimAllRewards.ts +++ b/src/app/collective-rewards/rewards/hooks/useClaimBuilderRewards.ts @@ -6,7 +6,7 @@ import { useEffect, useMemo } from 'react' import { useAlertContext } from '@/app/providers' import { useGetBuilderToGauge } from '@/app/collective-rewards/user' -export const useClaimAllRewards = (builder: Address) => { +export const useClaimBuilderRewards = (builder: Address) => { const { writeContractAsync, error: executionError, data: hash, isPending } = useWriteContract() const { data: gauge, @@ -52,18 +52,18 @@ export const useClaimAllRewards = (builder: Address) => { } }, [gauge, gaugeError, builder, executionError, receiptError, isFetched]) - const claimAllRewards = () => { + const claimBuilderReward = (rewardToken?: Address) => { return writeContractAsync({ abi: GaugeAbi, address: gauge as Address, functionName: 'claimBuilderReward', - args: [], + args: rewardToken ? [rewardToken] : [], }) } return { isClaimFunctionReady, - claimAllRewards: () => isClaimFunctionReady && claimAllRewards(), + claimRewards: (rewardToken?: Address) => isClaimFunctionReady && claimBuilderReward(rewardToken), error, isPendingTx: isPending, isLoadingReceipt: isLoading, @@ -78,7 +78,7 @@ export const useClaimStateReporting = ({ isLoadingReceipt, isSuccess, receipt, -}: Omit, 'isClaimFunctionReady' | 'claimAllRewards'>) => { +}: Omit, 'isClaimFunctionReady' | 'claimRewards'>) => { const { setMessage } = useAlertContext() useEffect(() => { diff --git a/src/app/collective-rewards/rewards/hooks/useGetBuilderRewards.ts b/src/app/collective-rewards/rewards/hooks/useGetBuilderRewards.ts new file mode 100644 index 00000000..0342d6d7 --- /dev/null +++ b/src/app/collective-rewards/rewards/hooks/useGetBuilderRewards.ts @@ -0,0 +1,22 @@ +import { GaugeAbi } from '@/lib/abis/v2/GaugeAbi' +import { Address } from 'viem' +import { useReadContract } from 'wagmi' +import { AVERAGE_BLOCKTIME } from '@/lib/constants' + +export const useGetBuilderRewards = (rewardToken: Address, gauge: Address) => { + const { data, isLoading, error } = useReadContract({ + address: gauge, + abi: GaugeAbi, + functionName: 'builderRewards', + args: [rewardToken], + query: { + refetchInterval: AVERAGE_BLOCKTIME, + }, + }) + + return { + data, + isLoading, + error, + } +} diff --git a/src/app/collective-rewards/rewards/index.ts b/src/app/collective-rewards/rewards/index.ts index 01cdddf9..752b7b97 100644 --- a/src/app/collective-rewards/rewards/index.ts +++ b/src/app/collective-rewards/rewards/index.ts @@ -3,3 +3,4 @@ export * from './hooks' export * from './utils' export * from './MyRewards' export * from './LastCycleRewards' +export * from './ClaimableRewards' diff --git a/src/components/Button/Button.tsx b/src/components/Button/Button.tsx index c7787a72..da93452b 100644 --- a/src/components/Button/Button.tsx +++ b/src/components/Button/Button.tsx @@ -26,6 +26,7 @@ interface Props { startIconClasses?: string 'data-testid'?: string } +export type ButtonProps = Props const DEFAULT_DATA_TESTID = 'Button' diff --git a/src/components/Popover/Popover.tsx b/src/components/Popover/Popover.tsx index 31ae2ce3..c2b4a8c5 100644 --- a/src/components/Popover/Popover.tsx +++ b/src/components/Popover/Popover.tsx @@ -12,7 +12,6 @@ interface Props extends Omit, 'children' | 'conte size?: 'small' | 'medium' hasCaret?: boolean } - export const Popover = ({ children, content,