diff --git a/src/app/collective-rewards/actions.ts b/src/app/collective-rewards/actions.ts index 67e0bb3c..b1bd42ad 100644 --- a/src/app/collective-rewards/actions.ts +++ b/src/app/collective-rewards/actions.ts @@ -1,7 +1,12 @@ import { Address } from 'viem' -import { SimplifiedRewardDistributorAddress } from '@/lib/contracts' +import { BackersManagerAddress, SimplifiedRewardDistributorAddress } from '@/lib/contracts' import { axiosInstance } from '@/lib/utils' -import { fetchNotifyRewardLogsByAddress, fetchRewardDistributedLogsByAddress } from '@/lib/endpoints' +import { + fetchBuilderRewardsClaimedLogsByAddress, + fetchGaugeNotifyRewardLogsByAddress, + fetchNotifyRewardLogsByAddress, + fetchRewardDistributedLogsByAddress, +} from '@/lib/endpoints' export const fetchRewardDistributedLogs = (fromBlock = 0) => { return axiosInstance.get( @@ -14,9 +19,25 @@ export const fetchRewardDistributedLogs = (fromBlock = 0) => { export const fetchRewardDistributedCached = () => axiosInstance.get('/reward-distributed/api', { baseURL: '/' }) -export const fetchNotifyRewardLogs = (gaugeAddress: Address, fromBlock = 0) => { +export const fetchNotifyRewardLogs = (fromBlock = 0) => { return axiosInstance.get( fetchNotifyRewardLogsByAddress + .replace('{{address}}', BackersManagerAddress) + .replace('{{fromBlock}}', fromBlock.toString()), + ) +} + +export const fetchGaugeNotifyRewardLogs = (gaugeAddress: Address, fromBlock = 0) => { + return axiosInstance.get( + fetchGaugeNotifyRewardLogsByAddress + .replace('{{address}}', gaugeAddress) + .replace('{{fromBlock}}', fromBlock.toString()), + ) +} + +export const fetchBuilderRewardsClaimed = (gaugeAddress: Address, fromBlock = 0) => { + return axiosInstance.get( + fetchBuilderRewardsClaimedLogsByAddress .replace('{{address}}', gaugeAddress) .replace('{{fromBlock}}', fromBlock.toString()), ) diff --git a/src/app/collective-rewards/rewards/AllTimeShare.tsx b/src/app/collective-rewards/rewards/AllTimeShare.tsx new file mode 100644 index 00000000..4e0b8c52 --- /dev/null +++ b/src/app/collective-rewards/rewards/AllTimeShare.tsx @@ -0,0 +1,58 @@ +import { Address } from 'viem' +import { FC } from 'react' +import { + useGetNotifyRewardLogs, + useGetGaugeNotifyRewardLogs, + useGetBuilderRewards, +} from '@/app/collective-rewards/rewards' +import { MetricsCardWithSpinner } from '@/components/MetricsCard/MetricsCard' +import { useHandleErrors } from '@/app/collective-rewards/utils' + +type AllTimeShareProps = { + gauge: Address + data: { + [token: string]: { + symbol: string + address: Address + } + } +} + +export const AllTimeShare: FC = ({ gauge, data: { rif } }) => { + const { data: rewardsPerToken, isLoading: logsLoading, error: rewardsError } = useGetNotifyRewardLogs() + const { + data: gaugeRewardsPerToken, + isLoading: gaugeLogsLoading, + error: gaugeRewardsError, + } = useGetGaugeNotifyRewardLogs(gauge) + const { + data: claimableRewards, + isLoading: claimableRewardsLoading, + error: claimableRewardsError, + } = useGetBuilderRewards(rif.address, gauge) + + const error = rewardsError ?? gaugeRewardsError ?? claimableRewardsError + + useHandleErrors([{ error, title: 'Error loading all time share' }]) + + let isLoading: boolean = logsLoading || gaugeLogsLoading || claimableRewardsLoading + + if (!rewardsPerToken[rif.address] || !gaugeRewardsPerToken[rif.address]) { + return + } + + const rifRewards = rewardsPerToken[rif.address].reduce((acc, event) => { + const amount = event.args.amount_ + return acc + amount + }, 0n) + const gaugeRifRewards = gaugeRewardsPerToken[rif.address].reduce((acc, event) => { + const amount = event.args.builderAmount_ + return acc + amount + }, 0n) + + const totalRewards = gaugeRifRewards + (claimableRewards ?? 0n) + + const amount = !rifRewards ? '0%' : `${(totalRewards * 100n) / rifRewards}%` + + return +} diff --git a/src/app/collective-rewards/rewards/LastCycleRewards.tsx b/src/app/collective-rewards/rewards/LastCycleRewards.tsx index f3f38886..a227038a 100644 --- a/src/app/collective-rewards/rewards/LastCycleRewards.tsx +++ b/src/app/collective-rewards/rewards/LastCycleRewards.tsx @@ -5,6 +5,7 @@ import { MetricsCardTitle, MetricsCardWithSpinner, TokenMetricsCardRow, + useGetGaugeNotifyRewardLogs, useGetNotifyRewardLogs, } from '@/app/collective-rewards/rewards' import { useHandleErrors } from '@/app/collective-rewards/utils' @@ -30,7 +31,11 @@ const RewardsTokenMetrics: FC = ({ setState, }) => { const { data: cycle, isLoading: cycleLoading, error: cycleError } = useCycleContext() - const { data: rewardsPerToken, isLoading: logsLoading, error: rewardsError } = useGetNotifyRewardLogs(gauge) + const { + data: rewardsPerToken, + isLoading: logsLoading, + error: rewardsError, + } = useGetGaugeNotifyRewardLogs(gauge) const error = cycleError ?? rewardsError useHandleErrors([{ error: error, title: 'Error loading last cycle rewards' }]) diff --git a/src/app/collective-rewards/rewards/MyRewards.tsx b/src/app/collective-rewards/rewards/MyRewards.tsx index 6f507781..54348c15 100644 --- a/src/app/collective-rewards/rewards/MyRewards.tsx +++ b/src/app/collective-rewards/rewards/MyRewards.tsx @@ -8,6 +8,7 @@ import { LastCycleRewards, ClaimableRewards, AllTimeRewards, + AllTimeShare, } from '@/app/collective-rewards/rewards' import { CycleContextProvider } from '@/app/collective-rewards/metrics' import { PricesContextProvider } from '@/shared/context/PricesContext' @@ -50,7 +51,7 @@ export const Rewards: FC<{ builder: Address; gauge: Address }> = ({ builder, gau
Estimated Rewards
-
All time share
+ { args: [rewardToken], query: { refetchInterval: AVERAGE_BLOCKTIME, - enabled: !!gauge, }, }) diff --git a/src/app/collective-rewards/rewards/hooks/useGetBuilderRewardsClaimedLogs.ts b/src/app/collective-rewards/rewards/hooks/useGetBuilderRewardsClaimedLogs.ts index e6cb9aeb..47cc9a49 100644 --- a/src/app/collective-rewards/rewards/hooks/useGetBuilderRewardsClaimedLogs.ts +++ b/src/app/collective-rewards/rewards/hooks/useGetBuilderRewardsClaimedLogs.ts @@ -1,5 +1,5 @@ import { useQuery } from '@tanstack/react-query' -import { fetchNotifyRewardLogs } from '@/app/collective-rewards/actions' +import { fetchBuilderRewardsClaimed } from '@/app/collective-rewards/actions' import { Address, getAddress, parseEventLogs } from 'viem' import { GaugeAbi } from '@/lib/abis/v2/GaugeAbi' import { AVERAGE_BLOCKTIME } from '@/lib/constants' @@ -10,10 +10,10 @@ export type BuilderRewardsClaimedEventLog = ReturnType< export type BuilderClaimedRewardsPerToken = Record -export const useGetBuilderRewardsClaimedLogs = (gauge?: Address) => { +export const useGetBuilderRewardsClaimedLogs = (gauge: Address) => { const { data, error, isLoading } = useQuery({ queryFn: async () => { - const { data } = await fetchNotifyRewardLogs(gauge!) + const { data } = await fetchBuilderRewardsClaimed(gauge!) const events = parseEventLogs({ abi: GaugeAbi, @@ -23,10 +23,7 @@ export const useGetBuilderRewardsClaimedLogs = (gauge?: Address) => { return events.reduce((acc, log) => { const rewardToken = getAddress(log.args.rewardToken_) - const existingRewardToken = acc[rewardToken] || [] - existingRewardToken.push(log) - - acc[rewardToken] = existingRewardToken + acc[rewardToken] = [...(acc[rewardToken] || []), log] return acc }, {}) @@ -34,7 +31,6 @@ export const useGetBuilderRewardsClaimedLogs = (gauge?: Address) => { queryKey: ['builderRewardsClaimedLogs'], refetchInterval: AVERAGE_BLOCKTIME, initialData: {}, - enabled: !!gauge, }) return { diff --git a/src/app/collective-rewards/rewards/hooks/useGetNotifyRewardLogs.ts b/src/app/collective-rewards/rewards/hooks/useGetNotifyRewardLogs.ts index 5fae824a..5a9a13a8 100644 --- a/src/app/collective-rewards/rewards/hooks/useGetNotifyRewardLogs.ts +++ b/src/app/collective-rewards/rewards/hooks/useGetNotifyRewardLogs.ts @@ -1,20 +1,24 @@ import { useQuery } from '@tanstack/react-query' -import { fetchNotifyRewardLogs } from '@/app/collective-rewards/actions' +import { fetchGaugeNotifyRewardLogs, fetchNotifyRewardLogs } from '@/app/collective-rewards/actions' import { Address, getAddress, parseEventLogs } from 'viem' import { GaugeAbi } from '@/lib/abis/v2/GaugeAbi' +import { BackersManagerAbi } from '@/lib/abis/v2/BackersManagerAbi' +import { BackersManagerAddress } from '@/lib/contracts' import { AVERAGE_BLOCKTIME } from '@/lib/constants' -export type NotifyRewardEventLog = ReturnType> +export type NotifyRewardEventLog = ReturnType< + typeof parseEventLogs +> export type NotifyRewardsPerToken = Record -export const useGetNotifyRewardLogs = (gauge: Address) => { +export const useGetNotifyRewardLogs = () => { const { data, error, isLoading } = useQuery({ queryFn: async () => { - const { data } = await fetchNotifyRewardLogs(gauge) + const { data } = await fetchNotifyRewardLogs() const events = parseEventLogs({ - abi: GaugeAbi, + abi: BackersManagerAbi, logs: data, eventName: 'NotifyReward', }) @@ -22,11 +26,44 @@ export const useGetNotifyRewardLogs = (gauge: Address) => { return events.reduce((acc, log) => { const rewardToken = getAddress(log.args.rewardToken_) acc[rewardToken] = [...(acc[rewardToken] || []), log] + return acc + }, {}) + }, + queryKey: ['notifyRewardLogs', BackersManagerAddress], + refetchInterval: AVERAGE_BLOCKTIME, + initialData: {}, + }) + + return { + data, + error, + isLoading, + } +} + +export type GaugeNotifyRewardEventLog = ReturnType< + typeof parseEventLogs +> +export type GaugeNotifyRewardsPerToken = Record +export const useGetGaugeNotifyRewardLogs = (gauge: Address) => { + const { data, error, isLoading } = useQuery({ + queryFn: async () => { + const { data } = await fetchGaugeNotifyRewardLogs(gauge) + + const events = parseEventLogs({ + abi: GaugeAbi, + logs: data, + eventName: 'NotifyReward', + }) + + return events.reduce((acc, log) => { + const rewardToken = getAddress(log.args.rewardToken_) + acc[rewardToken] = [...(acc[rewardToken] || []), log] return acc }, {}) }, - queryKey: ['notifyRewardLogs'], + queryKey: ['notifyRewardLogs', gauge], refetchInterval: AVERAGE_BLOCKTIME, initialData: {}, }) diff --git a/src/app/collective-rewards/rewards/index.ts b/src/app/collective-rewards/rewards/index.ts index a556b0c7..200675a1 100644 --- a/src/app/collective-rewards/rewards/index.ts +++ b/src/app/collective-rewards/rewards/index.ts @@ -5,3 +5,4 @@ export * from './MyRewards' export * from './LastCycleRewards' export * from './ClaimableRewards' export * from './AllTimeRewards' +export * from './AllTimeShare' diff --git a/src/app/collective-rewards/rewards/utils/getLastCycleRewards.ts b/src/app/collective-rewards/rewards/utils/getLastCycleRewards.ts index 72c618cf..db68ea10 100644 --- a/src/app/collective-rewards/rewards/utils/getLastCycleRewards.ts +++ b/src/app/collective-rewards/rewards/utils/getLastCycleRewards.ts @@ -1,13 +1,13 @@ -import { NotifyRewardEventLog } from '@/app/collective-rewards/rewards' +import { GaugeNotifyRewardEventLog } from '@/app/collective-rewards/rewards' import { Cycle } from '@/app/collective-rewards/metrics/context/CycleContext' -type Log = NotifyRewardEventLog[number] +type Log = GaugeNotifyRewardEventLog[number] type CycleRewards = { builderAmount: bigint backersAmount: bigint } -export const getLastCycleRewards = (cycle: Cycle, notifyRewardLogs?: NotifyRewardEventLog) => { +export const getLastCycleRewards = (cycle: Cycle, notifyRewardLogs?: GaugeNotifyRewardEventLog) => { const { cycleDuration, endDistributionWindow, cycleStart } = cycle const distributionWindow = endDistributionWindow.diff(cycleStart) const lastCycleStart = cycleStart.minus({ millisecond: +cycleDuration }) diff --git a/src/lib/endpoints.ts b/src/lib/endpoints.ts index faae7ed0..ae0f4f93 100644 --- a/src/lib/endpoints.ts +++ b/src/lib/endpoints.ts @@ -26,5 +26,11 @@ export const getNftHolders = `/nfts/{{address}}/holders?chainId=${CHAIN_ID}` const REWARD_DISTRIBUTED_EVENT = '0x57ea5c7c295b52ef3b06c69661d59c8a6d9c602ac5355cfe5e54e303c139f270' export const fetchRewardDistributedLogsByAddress = `/address/{{address}}/eventsByTopic0?topic0=${REWARD_DISTRIBUTED_EVENT}&chainId=${CHAIN_ID}&fromBlock={{fromBlock}}` -const NOTIFY_REWARD_EVENT = '0x3c0f5c48b0ffa2c570c1a0f4fbf7b0f8982213afff9eb42cd258ead865cf3c9d' +const NOTIFY_REWARD_EVENT = 'f70d5c697de7ea828df48e5c4573cb2194c659f1901f70110c52b066dcf50826' export const fetchNotifyRewardLogsByAddress = `/address/{{address}}/eventsByTopic0?topic0=${NOTIFY_REWARD_EVENT}&chainId=${CHAIN_ID}&fromBlock={{fromBlock}}` + +const GAUGE_NOTIFY_REWARD_EVENT = '0x3c0f5c48b0ffa2c570c1a0f4fbf7b0f8982213afff9eb42cd258ead865cf3c9d' +export const fetchGaugeNotifyRewardLogsByAddress = `/address/{{address}}/eventsByTopic0?topic0=${GAUGE_NOTIFY_REWARD_EVENT}&chainId=${CHAIN_ID}&fromBlock={{fromBlock}}` + +const BUILDER_REWARDS_CLAIMED_EVENT = 'c309438e69ba53ef6afef64839bd1ab1acc4a9a8fd28c8e0356075ca66f72c1b' +export const fetchBuilderRewardsClaimedLogsByAddress = `/address/{{address}}/eventsByTopic0?topic0=${BUILDER_REWARDS_CLAIMED_EVENT}&chainId=${CHAIN_ID}&fromBlock={{fromBlock}}`