Skip to content

Commit 4bfea61

Browse files
authored
Merge pull request #100 from GenerationSoftware/pool-wide-twab-rewards
Pool-Wide TWAB Rewards
2 parents 004f17b + 40ee008 commit 4bfea61

34 files changed

+2514
-207
lines changed

apps/app/src/components/Account/AccountPromotionCard.tsx

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
import { Vault } from '@generationsoftware/hyperstructure-client-js'
22
import { usePublicClientsByChain } from '@generationsoftware/hyperstructure-react-hooks'
33
import { VaultBadge } from '@shared/react-components'
4+
import { lower } from '@shared/utilities'
45
import { useTranslations } from 'next-intl'
56
import Link from 'next/link'
67
import { useMemo } from 'react'
78
import { Address } from 'viem'
89
import { useAccount } from 'wagmi'
10+
import { useUserClaimablePoolWidePromotions } from '@hooks/useUserClaimablePoolWidePromotions'
911
import { useUserClaimablePromotions } from '@hooks/useUserClaimablePromotions'
12+
import { useUserClaimedPoolWidePromotions } from '@hooks/useUserClaimedPoolWidePromotions'
1013
import { useUserClaimedPromotions } from '@hooks/useUserClaimedPromotions'
1114
import { AccountPromotionClaimableRewards } from './AccountPromotionClaimableRewards'
1215
import { AccountPromotionClaimActions } from './AccountPromotionClaimActions'
@@ -16,37 +19,51 @@ import { AccountPromotionToken } from './AccountPromotionToken'
1619
interface AccountPromotionCardProps {
1720
chainId: number
1821
promotionId: bigint
19-
address?: Address
22+
userAddress?: Address
23+
vaultAddress?: Address
24+
isPoolWide?: boolean
2025
}
2126

2227
export const AccountPromotionCard = (props: AccountPromotionCardProps) => {
23-
const { chainId, promotionId, address } = props
28+
const { chainId, promotionId, userAddress, vaultAddress, isPoolWide } = props
2429

2530
const t = useTranslations('Account.bonusRewardHeaders')
2631

2732
const publicClients = usePublicClientsByChain()
2833

2934
const { address: _userAddress } = useAccount()
30-
const userAddress = address ?? _userAddress
3135

3236
const isExternalUser = useMemo(() => {
33-
return !!address && address.toLowerCase() !== _userAddress?.toLowerCase()
34-
}, [address, _userAddress])
37+
return !!userAddress && userAddress.toLowerCase() !== _userAddress?.toLowerCase()
38+
}, [userAddress, _userAddress])
3539

36-
const { data: allClaimed } = useUserClaimedPromotions(userAddress as Address)
37-
const { data: allClaimable } = useUserClaimablePromotions(userAddress as Address)
40+
const { data: allClaimed } = useUserClaimedPromotions((userAddress ?? _userAddress)!)
41+
const { data: allClaimable } = useUserClaimablePromotions((userAddress ?? _userAddress)!)
42+
43+
const { data: allPoolWideClaimed } = useUserClaimedPoolWidePromotions(
44+
(userAddress ?? _userAddress)!
45+
)
46+
const { data: allPoolWideClaimable } = useUserClaimablePoolWidePromotions(
47+
(userAddress ?? _userAddress)!
48+
)
3849

3950
const claimed = useMemo(() => {
40-
return allClaimed.find(
41-
(promotion) => promotion.chainId === chainId && promotion.promotionId === promotionId
51+
return (isPoolWide ? allPoolWideClaimed : allClaimed).find(
52+
(promotion) =>
53+
promotion.chainId === chainId &&
54+
promotion.promotionId === promotionId &&
55+
(!vaultAddress || lower(promotion.vault) === lower(vaultAddress))
4256
)
43-
}, [allClaimed])
57+
}, [isPoolWide, allClaimed, allPoolWideClaimed, chainId, promotionId, vaultAddress])
4458

4559
const claimable = useMemo(() => {
46-
return allClaimable.find(
47-
(promotion) => promotion.chainId === chainId && promotion.promotionId === promotionId
60+
return (isPoolWide ? allPoolWideClaimable : allClaimable).find(
61+
(promotion) =>
62+
promotion.chainId === chainId &&
63+
promotion.promotionId === promotionId &&
64+
(!vaultAddress || lower(promotion.vault) === lower(vaultAddress))
4865
)
49-
}, [allClaimable])
66+
}, [isPoolWide, allClaimable, allPoolWideClaimable, chainId, promotionId, vaultAddress])
5067

5168
const promotionInfo = claimed ?? claimable
5269

@@ -71,7 +88,9 @@ export const AccountPromotionCard = (props: AccountPromotionCardProps) => {
7188
<AccountPromotionClaimedRewards
7289
chainId={chainId}
7390
promotionId={promotionId}
74-
address={userAddress}
91+
userAddress={userAddress ?? _userAddress}
92+
vaultAddress={promotionInfo.vault}
93+
isPoolWide={isPoolWide}
7594
className='!flex-row gap-1'
7695
/>
7796
</div>
@@ -82,7 +101,9 @@ export const AccountPromotionCard = (props: AccountPromotionCardProps) => {
82101
<AccountPromotionClaimableRewards
83102
chainId={chainId}
84103
promotionId={promotionId}
85-
address={userAddress}
104+
userAddress={userAddress ?? _userAddress}
105+
vaultAddress={promotionInfo.vault}
106+
isPoolWide={isPoolWide}
86107
className='!flex-row gap-1'
87108
/>
88109
</div>
@@ -92,7 +113,9 @@ export const AccountPromotionCard = (props: AccountPromotionCardProps) => {
92113
<AccountPromotionClaimActions
93114
chainId={chainId}
94115
promotionId={promotionId}
95-
address={userAddress}
116+
userAddress={userAddress ?? _userAddress}
117+
vaultAddress={promotionInfo.vault}
118+
isPoolWide={isPoolWide}
96119
fullSized={true}
97120
className='w-full justify-center'
98121
/>

apps/app/src/components/Account/AccountPromotionCards.tsx

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,69 @@
1+
import { lower } from '@shared/utilities'
12
import classNames from 'classnames'
23
import { useTranslations } from 'next-intl'
34
import { useMemo, useState } from 'react'
45
import { Address } from 'viem'
56
import { useAccount } from 'wagmi'
7+
import { useUserClaimablePoolWidePromotions } from '@hooks/useUserClaimablePoolWidePromotions'
68
import { useUserClaimablePromotions } from '@hooks/useUserClaimablePromotions'
9+
import { useUserClaimedPoolWidePromotions } from '@hooks/useUserClaimedPoolWidePromotions'
710
import { useUserClaimedPromotions } from '@hooks/useUserClaimedPromotions'
811
import { AccountPromotionCard } from './AccountPromotionCard'
912

1013
interface AccountPromotionCardsProps {
11-
address?: Address
14+
userAddress?: Address
1215
className?: string
1316
}
1417

1518
export const AccountPromotionCards = (props: AccountPromotionCardsProps) => {
16-
const { address, className } = props
19+
const { userAddress, className } = props
1720

1821
const t = useTranslations('Common')
1922

2023
const baseNumCards = 10
2124
const [numCards, setNumCards] = useState<number>(baseNumCards)
2225

2326
const { address: _userAddress } = useAccount()
24-
const userAddress = address ?? _userAddress
2527

26-
const { data: claimed } = useUserClaimedPromotions(userAddress as Address)
27-
const { data: claimable } = useUserClaimablePromotions(userAddress as Address)
28+
const { data: claimed } = useUserClaimedPromotions((userAddress ?? _userAddress)!)
29+
const { data: claimable } = useUserClaimablePromotions((userAddress ?? _userAddress)!)
30+
31+
const { data: poolWideClaimed } = useUserClaimedPoolWidePromotions((userAddress ?? _userAddress)!)
32+
const { data: poolWideClaimable } = useUserClaimablePoolWidePromotions(
33+
(userAddress ?? _userAddress)!
34+
)
2835

2936
const promotions = useMemo(() => {
3037
const promotions: { [id: string]: { startTimestamp: number; claimable: boolean } } = {}
3138

3239
claimed.forEach((promotion) => {
33-
const id = `${promotion.chainId}-${promotion.promotionId}`
40+
const id = `${promotion.chainId}-${promotion.promotionId}-${lower(promotion.vault)}-0`
3441

3542
if (promotions[id] === undefined) {
3643
promotions[id] = { startTimestamp: Number(promotion.startTimestamp), claimable: false }
3744
}
3845
})
3946

4047
claimable.forEach((promotion) => {
41-
const id = `${promotion.chainId}-${promotion.promotionId}`
48+
const id = `${promotion.chainId}-${promotion.promotionId}-${lower(promotion.vault)}-0`
49+
50+
if (promotions[id] === undefined) {
51+
promotions[id] = { startTimestamp: Number(promotion.startTimestamp), claimable: true }
52+
} else if (!promotions[id].claimable) {
53+
promotions[id].claimable = true
54+
}
55+
})
56+
57+
poolWideClaimed.forEach((promotion) => {
58+
const id = `${promotion.chainId}-${promotion.promotionId}-${lower(promotion.vault)}-1`
59+
60+
if (promotions[id] === undefined) {
61+
promotions[id] = { startTimestamp: Number(promotion.startTimestamp), claimable: false }
62+
}
63+
})
64+
65+
poolWideClaimable.forEach((promotion) => {
66+
const id = `${promotion.chainId}-${promotion.promotionId}-${lower(promotion.vault)}-1`
4267

4368
if (promotions[id] === undefined) {
4469
promotions[id] = { startTimestamp: Number(promotion.startTimestamp), claimable: true }
@@ -51,20 +76,24 @@ export const AccountPromotionCards = (props: AccountPromotionCardsProps) => {
5176
.sort((a, b) => b[1].startTimestamp - a[1].startTimestamp)
5277
.sort((a, b) => +b[1].claimable - +a[1].claimable)
5378
?.map(([id]) => id)
54-
}, [claimed, claimable])
79+
}, [claimed, claimable, poolWideClaimed, poolWideClaimable])
5580

5681
return (
5782
<div className={classNames('w-full flex flex-col gap-4', className)}>
5883
{promotions.slice(0, numCards).map((promotion) => {
5984
const chainId = parseInt(promotion.split('-')[0])
6085
const promotionId = BigInt(promotion.split('-')[1])
86+
const vaultAddress = promotion.split('-')[2] as Address
87+
const isPoolWide = promotion.split('-')[3] === '1'
6188

6289
return (
6390
<AccountPromotionCard
6491
key={promotion}
6592
chainId={chainId}
6693
promotionId={promotionId}
67-
address={userAddress}
94+
userAddress={userAddress ?? _userAddress}
95+
vaultAddress={vaultAddress}
96+
isPoolWide={isPoolWide}
6897
/>
6998
)
7099
})}

apps/app/src/components/Account/AccountPromotionClaimActions.tsx

Lines changed: 74 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,45 @@
11
import {
22
useSendClaimRewardsTransaction,
3+
useSendPoolWideClaimRewardsTransaction,
34
useToken
45
} from '@generationsoftware/hyperstructure-react-hooks'
56
import { useAddRecentTransaction, useChainModal, useConnectModal } from '@rainbow-me/rainbowkit'
67
import { TokenAmount, TransactionButton } from '@shared/react-components'
7-
import { getSecondsSinceEpoch } from '@shared/utilities'
8+
import { getSecondsSinceEpoch, lower } from '@shared/utilities'
89
import classNames from 'classnames'
910
import { useTranslations } from 'next-intl'
1011
import { useMemo } from 'react'
1112
import { Address, formatUnits } from 'viem'
1213
import { useAccount } from 'wagmi'
14+
import { useUserClaimablePoolWidePromotions } from '@hooks/useUserClaimablePoolWidePromotions'
1315
import { useUserClaimablePromotions } from '@hooks/useUserClaimablePromotions'
16+
import { useUserClaimedPoolWidePromotions } from '@hooks/useUserClaimedPoolWidePromotions'
1417
import { useUserClaimedPromotions } from '@hooks/useUserClaimedPromotions'
1518

1619
interface AccountPromotionClaimActionsProps {
1720
chainId: number
1821
promotionId: bigint
19-
address?: Address
22+
userAddress?: Address
23+
vaultAddress?: Address
24+
isPoolWide?: boolean
2025
fullSized?: boolean
2126
className?: string
2227
}
2328

2429
export const AccountPromotionClaimActions = (props: AccountPromotionClaimActionsProps) => {
25-
const { chainId, promotionId, address, fullSized, className } = props
30+
const { chainId, promotionId, userAddress, vaultAddress, isPoolWide, fullSized, className } =
31+
props
2632

2733
const { address: _userAddress } = useAccount()
28-
const userAddress = address ?? _userAddress
2934

3035
if (!!userAddress) {
3136
return (
3237
<ClaimRewardsButton
3338
chainId={chainId}
3439
promotionId={promotionId}
35-
userAddress={userAddress}
40+
userAddress={userAddress ?? _userAddress}
41+
vaultAddress={vaultAddress}
42+
isPoolWide={isPoolWide}
3643
fullSized={fullSized}
3744
className={className}
3845
/>
@@ -46,12 +53,15 @@ interface ClaimRewardsButtonProps {
4653
chainId: number
4754
promotionId: bigint
4855
userAddress: Address
56+
vaultAddress?: Address
57+
isPoolWide?: boolean
4958
fullSized?: boolean
5059
className?: string
5160
}
5261

5362
const ClaimRewardsButton = (props: ClaimRewardsButtonProps) => {
54-
const { chainId, promotionId, userAddress, fullSized, className } = props
63+
const { chainId, promotionId, userAddress, vaultAddress, isPoolWide, fullSized, className } =
64+
props
5565

5666
const t_common = useTranslations('Common')
5767
const t_account = useTranslations('Account')
@@ -62,36 +72,78 @@ const ClaimRewardsButton = (props: ClaimRewardsButtonProps) => {
6272
const addRecentTransaction = useAddRecentTransaction()
6373

6474
const { refetch: refetchClaimed } = useUserClaimedPromotions(userAddress)
75+
const { refetch: refetchPoolWideClaimed } = useUserClaimedPoolWidePromotions(userAddress)
76+
6577
const {
6678
data: allClaimable,
6779
isFetched: isFetchedAllClaimable,
6880
refetch: refetchClaimable
6981
} = useUserClaimablePromotions(userAddress)
82+
const {
83+
data: allPoolWideClaimable,
84+
isFetched: isFetchedAllPoolWideClaimable,
85+
refetch: refetchPoolWideClaimable
86+
} = useUserClaimablePoolWidePromotions(userAddress)
7087

7188
const promotion = useMemo(() => {
72-
return allClaimable.find(
73-
(promotion) => promotion.chainId === chainId && promotion.promotionId === promotionId
89+
return (isPoolWide ? allPoolWideClaimable : allClaimable).find(
90+
(promotion) =>
91+
promotion.chainId === chainId &&
92+
promotion.promotionId === promotionId &&
93+
(!vaultAddress || lower(promotion.vault) === lower(vaultAddress))
7494
)
75-
}, [allClaimable])
95+
}, [isPoolWide, allClaimable, allPoolWideClaimable, chainId, promotionId, vaultAddress])
7696

7797
const { data: token } = useToken(chainId, promotion?.token!)
7898

7999
const epochsToClaim =
80-
!!promotion && isFetchedAllClaimable
100+
!!promotion && (isPoolWide ? isFetchedAllPoolWideClaimable : isFetchedAllClaimable)
81101
? Object.keys(promotion.epochRewards).map((k) => parseInt(k))
82102
: []
83-
const { isWaiting, isConfirming, isSuccess, txHash, sendClaimRewardsTransaction } =
84-
useSendClaimRewardsTransaction(
85-
chainId,
86-
userAddress,
87-
{ [promotionId.toString()]: epochsToClaim },
88-
{
89-
onSuccess: () => {
90-
refetchClaimed()
91-
refetchClaimable()
92-
}
103+
104+
const {
105+
isWaiting: isWaitingClaimRewards,
106+
isConfirming: isConfirmingClaimRewards,
107+
isSuccess: isSuccessClaimRewards,
108+
txHash: txHashClaimRewards,
109+
sendClaimRewardsTransaction
110+
} = useSendClaimRewardsTransaction(
111+
chainId,
112+
userAddress,
113+
{ [promotionId.toString()]: epochsToClaim },
114+
{
115+
onSuccess: () => {
116+
refetchClaimed()
117+
refetchClaimable()
93118
}
94-
)
119+
}
120+
)
121+
122+
const {
123+
isWaiting: isWaitingPoolWideClaimRewards,
124+
isConfirming: isConfirmingPoolWideClaimRewards,
125+
isSuccess: isSuccessPoolWideClaimRewards,
126+
txHash: txHashPoolWideClaimRewards,
127+
sendPoolWideClaimRewardsTransaction
128+
} = useSendPoolWideClaimRewardsTransaction(
129+
chainId,
130+
userAddress,
131+
{ [promotionId.toString()]: { vaultAddress: promotion?.vault!, epochs: epochsToClaim } },
132+
{
133+
onSuccess: () => {
134+
refetchPoolWideClaimed()
135+
refetchPoolWideClaimable()
136+
}
137+
}
138+
)
139+
140+
const isWaiting = isPoolWide ? isWaitingPoolWideClaimRewards : isWaitingClaimRewards
141+
const isConfirming = isPoolWide ? isConfirmingPoolWideClaimRewards : isConfirmingClaimRewards
142+
const isSuccess = isPoolWide ? isSuccessPoolWideClaimRewards : isSuccessClaimRewards
143+
const txHash = isPoolWide ? txHashPoolWideClaimRewards : txHashClaimRewards
144+
const sendTransaction = isPoolWide
145+
? sendPoolWideClaimRewardsTransaction
146+
: sendClaimRewardsTransaction
95147

96148
if (!!promotion && !!token) {
97149
const claimableAmount = Object.values(promotion.epochRewards).reduce((a, b) => a + b, 0n)
@@ -110,7 +162,7 @@ const ClaimRewardsButton = (props: ClaimRewardsButtonProps) => {
110162
chainId={chainId}
111163
isTxLoading={isWaiting || isConfirming}
112164
isTxSuccess={isSuccess}
113-
write={sendClaimRewardsTransaction}
165+
write={sendTransaction}
114166
txHash={txHash}
115167
txDescription={t_account('claimRewardsTx', { symbol: token.symbol })}
116168
openConnectModal={openConnectModal}

0 commit comments

Comments
 (0)