1- import { ProtocolAction } from '@aave/contract-helpers' ;
1+ import { ProtocolAction , EthereumTransactionTypeExtended , eEthereumTxType } from '@aave/contract-helpers' ;
22import { Trans } from '@lingui/macro' ;
3+ import { utils } from 'ethers' ;
34import { Reward } from 'src/helpers/types' ;
45import { useTransactionHandler } from 'src/helpers/useTransactionHandler' ;
56import { useAppDataContext } from 'src/hooks/app-data-provider/useAppDataProvider' ;
67import { useRootStore } from 'src/store/root' ;
78
9+ import { useMeritClaimRewards } from '@aave/react' ;
10+ import { useShallow } from 'zustand/shallow' ;
11+ import { useWeb3Context } from 'src/libs/hooks/useWeb3Context' ;
12+
13+
814import { TxActionsWrapper } from '../TxActionsWrapper' ;
915
1016export type ClaimRewardsActionsProps = {
@@ -21,6 +27,15 @@ export const ClaimRewardsActions = ({
2127 const claimRewards = useRootStore ( ( state ) => state . claimRewards ) ;
2228 const { reserves } = useAppDataContext ( ) ;
2329
30+ const { currentAccount } = useWeb3Context ( ) ;
31+
32+
33+ const [ currentMarketData ] = useRootStore (
34+ useShallow ( ( store ) => [ store . currentMarketData ] )
35+ ) ;
36+
37+ const { data : meritClaimRewards } = useMeritClaimRewards ( { user : currentAccount , chainId : currentMarketData . chainId } ) ;
38+
2439 const { action, loadingTxns, mainTxState, requiresApproval } = useTransactionHandler ( {
2540 protocolAction : ProtocolAction . claimRewards ,
2641 eventTxInfo : {
@@ -29,12 +44,130 @@ export const ClaimRewardsActions = ({
2944 } ,
3045 tryPermit : false ,
3146 handleGetTxns : async ( ) => {
32- return claimRewards ( { isWrongNetwork, blocked, selectedReward, formattedReserves : reserves } ) ;
47+ // Check if we need to claim both protocol and merit rewards
48+ const isClaimingAll = selectedReward . symbol === 'all' ;
49+ const isClaimingMeritAll = selectedReward . symbol === 'merit-all' ;
50+ const isClaimingProtocolAll = selectedReward . symbol === 'protocol-all' ;
51+ const hasProtocolRewards = selectedReward . incentiveControllerAddress !== 'MERIT_REWARD' ;
52+ const hasMeritRewards = meritClaimRewards ?. rewards && meritClaimRewards . rewards . length > 0 ;
53+ const isIndividualProtocolReward = hasProtocolRewards && ! isClaimingAll && ! isClaimingProtocolAll && ! isClaimingMeritAll ;
54+
55+ // Use simple approach for individual protocol rewards (most common case)
56+ if ( isIndividualProtocolReward ) {
57+ return claimRewards ( { isWrongNetwork, blocked, selectedReward, formattedReserves : reserves } ) ;
58+ }
59+
60+ // Use complex multicall logic only when needed
61+ if ( isClaimingAll && hasProtocolRewards && hasMeritRewards ) {
62+ // Get protocol rewards transaction
63+ const protocolTxns = await claimRewards ( {
64+ isWrongNetwork,
65+ blocked,
66+ selectedReward,
67+ formattedReserves : reserves
68+ } ) ;
69+
70+ // Create multicall transaction that includes both protocol and merit claims
71+ if ( ! meritClaimRewards ?. transaction ) {
72+ throw new Error ( 'Merit rewards transaction not available' ) ;
73+ }
74+ const multicallTx = await createMulticallTransaction ( protocolTxns , meritClaimRewards . transaction ) ;
75+
76+ // Check if there are any approval transactions that need to be handled separately
77+ const approvalTxns = protocolTxns . filter ( tx => tx . txType === 'ERC20_APPROVAL' ) ;
78+
79+ return approvalTxns . length > 0 ? [ ...approvalTxns , multicallTx ] : [ multicallTx ] ;
80+ } else if ( ( isClaimingAll && ! hasProtocolRewards && hasMeritRewards ) || isClaimingMeritAll ) {
81+ // Only merit rewards - use merit transaction directly
82+ if ( ! meritClaimRewards ?. transaction ) {
83+ throw new Error ( 'Merit rewards transaction not available' ) ;
84+ }
85+ return [ convertMeritTransactionToEthereum ( meritClaimRewards . transaction ) ] ;
86+ } else {
87+ // Protocol-all or other cases - use existing protocol logic
88+ return claimRewards ( { isWrongNetwork, blocked, selectedReward, formattedReserves : reserves } ) ;
89+ }
3390 } ,
3491 skip : Object . keys ( selectedReward ) . length === 0 || blocked ,
35- deps : [ selectedReward ] ,
92+ deps : [ selectedReward , meritClaimRewards ] ,
3693 } ) ;
3794
95+ // Helper function to create multicall transaction
96+ const createMulticallTransaction = async (
97+ protocolTxns : EthereumTransactionTypeExtended [ ] ,
98+ meritTransaction : any
99+ ) : Promise < EthereumTransactionTypeExtended > => {
100+ // Multicall3 contract address (same across chains)
101+ const multicallAddress = '0xcA11bde05977b3631167028862bE2a173976CA11' ;
102+
103+ // Prepare calls array for multicall
104+ const calls = [ ] ;
105+
106+ // Add protocol transaction calls
107+ for ( const txExt of protocolTxns ) {
108+ if ( txExt . txType === 'ERC20_APPROVAL' ) continue ; // Skip approvals for multicall
109+
110+ const tx = await txExt . tx ( ) ;
111+ calls . push ( {
112+ target : tx . to ,
113+ callData : tx . data ,
114+ value : tx . value || '0'
115+ } ) ;
116+ }
117+
118+ // Add merit transaction call
119+ calls . push ( {
120+ target : meritTransaction . to ,
121+ callData : meritTransaction . data ,
122+ value : meritTransaction . value || '0'
123+ } ) ;
124+
125+ // Encode multicall
126+ const multicallInterface = new utils . Interface ( [
127+ 'function aggregate3Value((address target, bool allowFailure, uint256 value, bytes callData)[] calls) payable returns ((bool success, bytes returnData)[])'
128+ ] ) ;
129+
130+ const callsWithFailure = calls . map ( call => [
131+ call . target ,
132+ false , // allowFailure = false
133+ call . value ,
134+ call . callData
135+ ] ) ;
136+
137+ const data = multicallInterface . encodeFunctionData ( 'aggregate3Value' , [ callsWithFailure ] ) ;
138+
139+ return {
140+ txType : eEthereumTxType . DLP_ACTION ,
141+ tx : async ( ) => ( {
142+ to : multicallAddress ,
143+ from : currentAccount ,
144+ data,
145+ value : '0' ,
146+ } ) ,
147+ gas : async ( ) => ( {
148+ gasLimit : '800000' , // Conservative gas limit for multicall
149+ gasPrice : '0' ,
150+ } ) ,
151+ } ;
152+ } ;
153+
154+ // Helper function to convert merit transaction to Ethereum format
155+ const convertMeritTransactionToEthereum = ( meritTx : any ) : EthereumTransactionTypeExtended => {
156+ return {
157+ txType : eEthereumTxType . DLP_ACTION ,
158+ tx : async ( ) => ( {
159+ to : meritTx . to ,
160+ from : meritTx . from || currentAccount ,
161+ data : meritTx . data ,
162+ value : meritTx . value || '0' ,
163+ } ) ,
164+ gas : async ( ) => ( {
165+ gasLimit : '400000' , // Conservative gas limit for merit only
166+ gasPrice : '0' ,
167+ } ) ,
168+ } ;
169+ } ;
170+
38171 return (
39172 < TxActionsWrapper
40173 requiresApproval = { requiresApproval }
@@ -45,6 +178,10 @@ export const ClaimRewardsActions = ({
45178 actionText = {
46179 selectedReward . symbol === 'all' ? (
47180 < Trans > Claim all</ Trans >
181+ ) : selectedReward . symbol === 'merit-all' ? (
182+ < Trans > Claim all merit rewards</ Trans >
183+ ) : selectedReward . symbol === 'protocol-all' ? (
184+ < Trans > Claim all protocol rewards</ Trans >
48185 ) : (
49186 < Trans > Claim { selectedReward . symbol } </ Trans >
50187 )
0 commit comments