diff --git a/src/app/collective-rewards/builder/ClaimableRewards.tsx b/src/app/collective-rewards/builder/ClaimableRewards.tsx new file mode 100644 index 00000000..0cf7633c --- /dev/null +++ b/src/app/collective-rewards/builder/ClaimableRewards.tsx @@ -0,0 +1,119 @@ +import { FC } from 'react' +import { Address } from 'viem' +import { useGetBuilderRewards } from '@/app/collective-rewards/hooks/useGetBuilderRewards' +import { usePricesContext } from '@/shared/context/PricesContext' +import { formatMetrics } from '@/app/collective-rewards/utils/formatMetrics' +import { formatBalanceToHuman } from '@/app/user/Balances/balanceUtils' +import { MetricsCardMultipleRowsWithSpinner } from '@/app/collective-rewards/components/MetricsCardMultipleRows' +import { Popover } from '@/components/Popover' +import { + useClaimBuilderRewards, + useClaimStateReporting, +} from '@/app/collective-rewards/builder/hooks/useClaimBuilderRewards' +import { useHandleErrors } from '@/app/collective-rewards/builder/LastCycleRewards' + +type Token = { + symbol: string + address: Address +} + +type ClaimableRewardsProps = { + builder: Address + gauge: Address + currency?: string + data: { + [token: string]: Token + } +} + +const ClaimYourRewardsSvg = () => ( + + + +) + +const getAction = (onClick: () => void, disabled: boolean) => ( + + Claim your rewards + + } + size="small" + position="top" + trigger="hover" + > + + + + +) + +export const ClaimableRewards: FC = ({ + builder, + gauge, + data: { rif, rbtc }, + currency = 'USD', +}) => { + const { prices } = usePricesContext() + + const useGetRewardMetrics = (tokenAddress: Address, symbol: string, currency: string) => { + const { data: rewards, isLoading, error } = useGetBuilderRewards(tokenAddress, gauge) + + const price = prices[symbol]?.price ?? 0 + const rewardsInHuman = Number(formatBalanceToHuman(rewards ?? 0n)) + const rewardMetrics = formatMetrics(rewardsInHuman, price, symbol, currency) + + const { isClaimFunctionReady, claimRewards, ...claimTx } = useClaimBuilderRewards(builder, tokenAddress) + useClaimStateReporting({ ...claimTx }) + + const action = getAction(claimRewards, !isClaimFunctionReady) + + return { + data: { + ...rewardMetrics, + action, + }, + error, + isLoading, + } + } + + const { + data: rifRewardsMetrics, + isLoading: rifLoading, + error: rifError, + } = useGetRewardMetrics(rif.address, rif.symbol, currency) + const { + data: rbtcRewardsMetrics, + isLoading: rbtcLoading, + error: rbtcError, + } = useGetRewardMetrics(rbtc.address, rbtc.symbol, currency) + + useHandleErrors([ + { error: rifError, title: 'Error loading builder rif rewards' }, + { error: rbtcError, title: 'Error loading builder rbtc rewards' }, + ]) + + const isLoading = rifLoading || rbtcLoading + + return ( + + + + ) +} diff --git a/src/app/collective-rewards/builder/LastCycleRewards.tsx b/src/app/collective-rewards/builder/LastCycleRewards.tsx index 92c546ba..3a787185 100644 --- a/src/app/collective-rewards/builder/LastCycleRewards.tsx +++ b/src/app/collective-rewards/builder/LastCycleRewards.tsx @@ -10,20 +10,22 @@ import { import { Cycle, useCycleContext } from '@/app/collective-rewards/CycleContext' import { MetricsCardMultipleRowsWithSpinner } from '@/app/collective-rewards/components/MetricsCardMultipleRows' import { getLastCycleRewards } from '@/app/collective-rewards/builder/utils/getLastCycleRewards' -import { formatMetrics } from '@/app/collective-rewards/builder/utils/formatMetrics' +import { formatMetrics } from '@/app/collective-rewards/utils/formatMetrics' + +type Token = { + symbol: string + address: Address +} type LastCycleRewardsProps = { gauge: Address currency?: string data: { - [token: string]: { - symbol: string - address: Address - } + [token: string]: Token } } -const useHandleErrors = (errors: { error: Error | null; title: string }[]) => { +export const useHandleErrors = (errors: { error: Error | null; title: string }[]) => { const { setMessage } = useAlertContext() useEffect(() => { diff --git a/src/app/collective-rewards/builder/Rewards.tsx b/src/app/collective-rewards/builder/Rewards.tsx index 40a57446..07e3c352 100644 --- a/src/app/collective-rewards/builder/Rewards.tsx +++ b/src/app/collective-rewards/builder/Rewards.tsx @@ -4,11 +4,15 @@ import { tokenContracts } from '@/lib/contracts' import { PricesContextProvider } from '@/shared/context/PricesContext' import { FC } from 'react' import { Button } from '@/components/Button' -import { useClaimAllRewards, useClaimStateReporting } from '@/app/collective-rewards/hooks/useClaimAllRewards' +import { + useClaimBuilderRewards, + useClaimStateReporting, +} from '@/app/collective-rewards/builder/hooks/useClaimBuilderRewards' import { Popover } from '@/components/Popover' import { getCoinBaseAddress } from '@/app/collective-rewards/utils/getCoinBaseAddress' import { CycleContextProvider } from '@/app/collective-rewards/CycleContext' import { LastCycleRewards } from '@/app/collective-rewards/builder/LastCycleRewards' +import { ClaimableRewards } from '@/app/collective-rewards/builder/ClaimableRewards' type RewardsProps = { builder: Address @@ -16,7 +20,7 @@ type RewardsProps = { } export const Rewards: FC = ({ builder, gauge }) => { - const { isClaimFunctionReady, claimAllRewards, ...claimTx } = useClaimAllRewards(builder) + const { isClaimFunctionReady, claimRewards, ...claimTx } = useClaimBuilderRewards(builder) useClaimStateReporting({ ...claimTx }) @@ -33,41 +37,44 @@ export const Rewards: FC = ({ builder, gauge }) => { return ( <> - <> - - As a Builder - - {' '} - Monitor the rewards you are getting from your Collective Rewards. - - - - - + + As a Builder + + {' '} + Monitor the rewards you are getting from your Collective Rewards. + + + + + + + - - - - > + + + - - Wait a moment, please. Preparing the claim functionality. - - } - trigger="hover" - background="dark" - size="small" - position="bottom" - className="z-[100]" - > - - {/* TODO: adapt size once metrics are in place */} - Claim all - - + + + Wait a moment, please. Preparing the claim functionality. + + } + trigger="hover" + background="dark" + size="small" + position="bottom" + className="z-[100]" + > + + {/* TODO: adapt size once metrics are in place */} + Claim all + + + + > ) } diff --git a/src/app/collective-rewards/hooks/useClaimAllRewards.ts b/src/app/collective-rewards/builder/hooks/useClaimBuilderRewards.ts similarity index 90% rename from src/app/collective-rewards/hooks/useClaimAllRewards.ts rename to src/app/collective-rewards/builder/hooks/useClaimBuilderRewards.ts index b102ade2..25f7aab6 100644 --- a/src/app/collective-rewards/hooks/useClaimAllRewards.ts +++ b/src/app/collective-rewards/builder/hooks/useClaimBuilderRewards.ts @@ -6,7 +6,7 @@ import { useEffect, useMemo } from 'react' import { useAlertContext } from '@/app/providers' import { useGetBuilderToGauge } from '@/app/collective-rewards/hooks/useGetBuilderToGauge' -export const useClaimAllRewards = (builder: Address) => { +export const useClaimBuilderRewards = (builder: Address, rewardToken?: 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 = () => { return writeContractAsync({ abi: GaugeAbi, address: gauge as Address, functionName: 'claimBuilderReward', - args: [], + args: rewardToken ? [rewardToken] : [], }) } return { isClaimFunctionReady, - claimAllRewards: () => isClaimFunctionReady && claimAllRewards(), + claimRewards: () => isClaimFunctionReady && claimBuilderReward(), 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/components/MetricsCardMultipleRows.tsx b/src/app/collective-rewards/components/MetricsCardMultipleRows.tsx index 506c50ab..49921d5c 100644 --- a/src/app/collective-rewards/components/MetricsCardMultipleRows.tsx +++ b/src/app/collective-rewards/components/MetricsCardMultipleRows.tsx @@ -9,61 +9,48 @@ import { Span, Typography } from '../../../components/Typography' type MetricsCardRow = { amount: string fiatAmount?: string + action?: JSX.Element } type MetricsCardMultipleRowsProps = { - /** - * The title of the card, usually indicating the type of balance. - */ title: ReactNode - data: { [token: string]: MetricsCardRow } - - /** - * Whether the card should have a border or not. - */ borderless?: boolean - - /** - * The address of the contract to link to. - */ contractAddress?: Address 'data-testid'?: string } - -const DEFAULT_CLASSES = 'h-min-[79px] w-full py-[12px] px-[12px] flex flex-col bg-foreground' - -export const MetricsCardRow: FC = ({ amount, fiatAmount }) => ( - - - {amount} - - {fiatAmount && ( +export const MetricsCardRow: FC = ({ amount, fiatAmount, action }) => ( + + - {fiatAmount} + {amount} - )} + {fiatAmount && ( + + {fiatAmount} + + )} + + {action} ) -/** - * Card for displaying balance and corresponding (fiat) value. - */ +const DEFAULT_CLASSES = 'h-min-[79px] w-full py-[12px] px-[12px] flex flex-col bg-foreground' export const MetricsCardMultipleRows: FC = ({ title, borderless = false, @@ -73,7 +60,7 @@ export const MetricsCardMultipleRows: FC = ({ }) => { const borderClasses = borderless ? '' : 'border border-white border-opacity-40 rounded-lg' return ( - + {typeof title === 'string' ? ( { + const { data, isLoading, error } = useReadContract({ + address: gauge!, + abi: GaugeAbi, + functionName: 'builderRewards', + args: [rewardToken], + query: { + refetchInterval: 30_000, + enabled: !!gauge, + }, + }) + + return { + data, + isLoading, + error, + } +} diff --git a/src/app/collective-rewards/hooks/useGetNotifyRewardLogs.ts b/src/app/collective-rewards/hooks/useGetNotifyRewardLogs.ts index c0358191..298cbc4b 100644 --- a/src/app/collective-rewards/hooks/useGetNotifyRewardLogs.ts +++ b/src/app/collective-rewards/hooks/useGetNotifyRewardLogs.ts @@ -31,6 +31,7 @@ export const useGetNotifyRewardLogs = (gauge?: Address) => { queryKey: ['notifyRewardLogs'], refetchInterval: 30_000, initialData: {}, + enabled: !!gauge, }) return { diff --git a/src/app/collective-rewards/hooks/useGetSponsorsRewards.ts b/src/app/collective-rewards/hooks/useGetSponsorsRewards.ts new file mode 100644 index 00000000..b03c1266 --- /dev/null +++ b/src/app/collective-rewards/hooks/useGetSponsorsRewards.ts @@ -0,0 +1,22 @@ +import { GaugeAbi } from '@/lib/abis/v2/GaugeAbi' +import { Address } from 'viem' +import { useReadContract } from 'wagmi' + +export const useGetSponsorRewards = (rewardToken: Address, sponsor: Address, gauge?: Address) => { + const { data, isLoading, error } = useReadContract({ + address: gauge!, + abi: GaugeAbi, + functionName: 'earned', + args: [rewardToken, sponsor], + query: { + refetchInterval: 30_000, + enabled: !!gauge, + }, + }) + + return { + data, + isLoading, + error, + } +} diff --git a/src/app/collective-rewards/builder/utils/formatMetrics.ts b/src/app/collective-rewards/utils/formatMetrics.ts similarity index 100% rename from src/app/collective-rewards/builder/utils/formatMetrics.ts rename to src/app/collective-rewards/utils/formatMetrics.ts
Claim your rewards