-
Notifications
You must be signed in to change notification settings - Fork 1
Feat/1909 add claim rewards in space treasury view #1967
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
5a76ada
cf07fdf
2cd28e3
b47f0b1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,168 @@ | ||
| 'use client'; | ||
|
|
||
| import { FC, useCallback, useEffect, useState } from 'react'; | ||
| import { SectionFilter } from '@hypha-platform/ui/server'; | ||
| import { | ||
| usePendingRewards, | ||
| useSpaceDetailsWeb3Rpc, | ||
| } from '@hypha-platform/core/client'; | ||
| import { AssetCard } from './asset-card'; | ||
| import { useAssetsSection, useTokenSupply } from '../../hooks'; | ||
| import { Button } from '@hypha-platform/ui'; | ||
| import { Loader2 } from 'lucide-react'; | ||
| import { useAuthentication } from '@hypha-platform/authentication'; | ||
| import { Empty } from '../../../common'; | ||
| import { useSpaceMember } from '../../../spaces'; | ||
| import { useParams } from 'next/navigation'; | ||
| import { useSWRConfig } from 'swr'; | ||
|
|
||
| const HYPHA_TOKEN_ADDRESS = '0x8b93862835C36e9689E9bb1Ab21De3982e266CD3'; | ||
| const MIN_REWARD_CLAIM_VALUE = 0.01; | ||
|
|
||
| const HYPHA_REWARDS_FALLBACK = { | ||
| icon: '/placeholder/hypha-token-icon.svg', | ||
| name: 'Hypha', | ||
| symbol: 'HYPHA', | ||
| value: 0, | ||
| address: HYPHA_TOKEN_ADDRESS, | ||
| }; | ||
|
|
||
| type SpacePendingRewardsSectionProps = { | ||
| web3SpaceId: number; | ||
| }; | ||
|
|
||
| export const SpacePendingRewardsSection: FC< | ||
| SpacePendingRewardsSectionProps | ||
| > = ({ web3SpaceId }) => { | ||
| const { id: spaceSlug } = useParams<{ id: string }>(); | ||
| const { mutate } = useSWRConfig(); | ||
| const { isAuthenticated } = useAuthentication(); | ||
| const { spaceDetails } = useSpaceDetailsWeb3Rpc({ spaceId: web3SpaceId }); | ||
| const { isMember } = useSpaceMember({ spaceId: web3SpaceId }); | ||
| const executor = spaceDetails?.executor as `0x${string}` | undefined; | ||
|
|
||
| const { filteredAssets, isLoading: isLoadingAssets } = useAssetsSection(); | ||
| const { supply: hyphaTotalSupply } = useTokenSupply( | ||
| HYPHA_TOKEN_ADDRESS as `0x${string}`, | ||
| ); | ||
|
|
||
| const { | ||
| pendingRewards, | ||
| isLoading, | ||
| claim, | ||
| waitForClaimReceipt, | ||
| isClaiming, | ||
| updatePendingRewards, | ||
| } = usePendingRewards({ user: executor }); | ||
|
|
||
| const [hasClaimed, setHasClaimed] = useState(false); | ||
|
|
||
| const originalAsset = filteredAssets?.find( | ||
| (a) => a.address === HYPHA_TOKEN_ADDRESS, | ||
| ); | ||
|
|
||
| const parsedRewardValue = | ||
| pendingRewards !== undefined ? Number(pendingRewards / 10n ** 18n) : 0; | ||
|
Comment on lines
+64
to
+65
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same BigInt truncation issue as
Proposed fix const parsedRewardValue =
- pendingRewards !== undefined ? Number(pendingRewards / 10n ** 18n) : 0;
+ pendingRewards !== undefined
+ ? Number(pendingRewards) / Number(10n ** 18n)
+ : 0;🤖 Prompt for AI Agents |
||
|
|
||
| const baseHyphaAsset = originalAsset | ||
| ? { ...originalAsset, value: parsedRewardValue } | ||
| : { ...HYPHA_REWARDS_FALLBACK, value: parsedRewardValue }; | ||
|
|
||
| const supplyFromAsset = (originalAsset as { supply?: { total: number } }) | ||
| ?.supply; | ||
| const supply = | ||
| supplyFromAsset ?? | ||
| (hyphaTotalSupply !== undefined ? { total: hyphaTotalSupply } : undefined); | ||
|
|
||
| const hyphaTokenAsset = | ||
| pendingRewards !== undefined ? { ...baseHyphaAsset, supply } : undefined; | ||
|
|
||
| useEffect(() => { | ||
| if (parsedRewardValue >= MIN_REWARD_CLAIM_VALUE) { | ||
| setHasClaimed(false); | ||
| } | ||
| }, [parsedRewardValue]); | ||
|
|
||
| const updateSpaceAssets = useCallback(() => { | ||
| if (spaceSlug) { | ||
| mutate([`/api/v1/spaces/${spaceSlug}/assets`]); | ||
| } | ||
| }, [mutate, spaceSlug]); | ||
|
|
||
| const disableClaimButton = | ||
| hasClaimed || | ||
| !(parsedRewardValue >= MIN_REWARD_CLAIM_VALUE) || | ||
| isClaiming || | ||
| pendingRewards === undefined; | ||
|
|
||
| const canClaim = isAuthenticated && isMember; | ||
|
|
||
| const onHandleClaim = useCallback(async () => { | ||
| if (!canClaim || !executor) return; | ||
| try { | ||
| const txHash = await claim(); | ||
| await waitForClaimReceipt(txHash as `0x${string}`); | ||
| await updatePendingRewards(); | ||
| await updateSpaceAssets(); | ||
| setHasClaimed(true); | ||
| } catch (error) { | ||
| console.error('Claim failed:', error); | ||
| } | ||
| }, [ | ||
| canClaim, | ||
| executor, | ||
| claim, | ||
| waitForClaimReceipt, | ||
| updatePendingRewards, | ||
| updateSpaceAssets, | ||
| ]); | ||
|
|
||
| return ( | ||
| <div className="flex flex-col w-full justify-center items-center gap-3"> | ||
| <div className="w-full flex justify-between"> | ||
| <SectionFilter label="Rewards" /> | ||
| <Button | ||
| title={ | ||
| !isAuthenticated | ||
| ? 'Please sign in to claim rewards' | ||
| : !isMember | ||
| ? 'Only space members can claim rewards' | ||
| : disableClaimButton | ||
| ? 'The reward value must be greater than 0' | ||
| : '' | ||
|
Comment on lines
+130
to
+132
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Align disabled tooltip copy with the actual minimum claim threshold. At Line 131, the message says “greater than 0” but the guard uses Suggested copy fix- ? 'The reward value must be greater than 0'
+ ? 'The reward value must be at least 0.01'🤖 Prompt for AI Agents |
||
| } | ||
| disabled={!canClaim || disableClaimButton} | ||
| onClick={onHandleClaim} | ||
| > | ||
| {isClaiming && <Loader2 className="animate-spin w-4 h-4" />} | ||
| Claim | ||
| </Button> | ||
| </div> | ||
| <div className="w-full"> | ||
| {isLoading || !executor ? ( | ||
| <div className="w-full grid grid-cols-1 sm:grid-cols-3 gap-2 mt-2"> | ||
| <AssetCard isLoading /> | ||
| </div> | ||
| ) : !isAuthenticated ? ( | ||
| <Empty> | ||
| <p>Sign in to view space rewards</p> | ||
| </Empty> | ||
| ) : ( | ||
| <div className="w-full grid grid-cols-1 sm:grid-cols-3 gap-2 mt-2"> | ||
| <AssetCard | ||
| {...(hyphaTokenAsset ?? { | ||
| ...HYPHA_REWARDS_FALLBACK, | ||
| value: 0, | ||
| supply: | ||
| hyphaTotalSupply !== undefined | ||
| ? { total: hyphaTotalSupply } | ||
| : undefined, | ||
| })} | ||
| isLoading={isLoadingAssets} | ||
| /> | ||
| </div> | ||
| )} | ||
| </div> | ||
| </div> | ||
| ); | ||
| }; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: hypha-dao/hypha-web
Length of output: 90
🏁 Script executed:
Repository: hypha-dao/hypha-web
Length of output: 1685
🏁 Script executed:
Repository: hypha-dao/hypha-web
Length of output: 604
Extract duplicated constants into a shared module.
HYPHA_TOKEN_ADDRESSandMIN_REWARD_CLAIM_VALUEare duplicated verbatim in bothpending-rewards-section.tsx(lines 13–14) andspace-pending-rewards-section.tsx(lines 19–20). Extract them into a shared constants file (e.g.,constants.tsin the same directory) to avoid drift and improve maintainability.🤖 Prompt for AI Agents