1- import { ProtocolAction , EthereumTransactionTypeExtended , eEthereumTxType } from '@aave/contract-helpers' ;
1+ import {
2+ eEthereumTxType ,
3+ EthereumTransactionTypeExtended ,
4+ ProtocolAction ,
5+ } from '@aave/contract-helpers' ;
6+ import { useMeritClaimRewards } from '@aave/react' ;
27import { Trans } from '@lingui/macro' ;
3- import { utils } from 'ethers' ;
8+ import { BigNumber , PopulatedTransaction , utils } from 'ethers' ;
49import { Reward } from 'src/helpers/types' ;
510import { useTransactionHandler } from 'src/helpers/useTransactionHandler' ;
611import { useAppDataContext } from 'src/hooks/app-data-provider/useAppDataProvider' ;
12+ import { useWeb3Context } from 'src/libs/hooks/useWeb3Context' ;
713import { useRootStore } from 'src/store/root' ;
8-
9- import { useMeritClaimRewards } from '@aave/react' ;
1014import { useShallow } from 'zustand/shallow' ;
11- import { useWeb3Context } from 'src/libs/hooks/useWeb3Context' ;
12-
1315
1416import { TxActionsWrapper } from '../TxActionsWrapper' ;
1517
@@ -29,12 +31,14 @@ export const ClaimRewardsActions = ({
2931
3032 const { currentAccount } = useWeb3Context ( ) ;
3133
32-
33- const [ currentMarketData ] = useRootStore (
34- useShallow ( ( store ) => [ store . currentMarketData ] )
34+ const [ currentMarketData , estimateGasLimit ] = useRootStore (
35+ useShallow ( ( store ) => [ store . currentMarketData , store . estimateGasLimit ] )
3536 ) ;
3637
37- const { data : meritClaimRewards } = useMeritClaimRewards ( { user : currentAccount , chainId : currentMarketData . chainId } ) ;
38+ const { data : meritClaimRewards } = useMeritClaimRewards ( {
39+ user : currentAccount ,
40+ chainId : currentMarketData . chainId ,
41+ } ) ;
3842
3943 const { action, loadingTxns, mainTxState, requiresApproval } = useTransactionHandler ( {
4044 protocolAction : ProtocolAction . claimRewards ,
@@ -50,11 +54,17 @@ export const ClaimRewardsActions = ({
5054 const isClaimingProtocolAll = selectedReward . symbol === 'protocol-all' ;
5155 const hasProtocolRewards = selectedReward . incentiveControllerAddress !== 'MERIT_REWARD' ;
5256 const hasMeritRewards = meritClaimRewards ?. rewards && meritClaimRewards . rewards . length > 0 ;
53- const isIndividualProtocolReward = hasProtocolRewards && ! isClaimingAll && ! isClaimingProtocolAll && ! isClaimingMeritAll ;
57+ const isIndividualProtocolReward =
58+ hasProtocolRewards && ! isClaimingAll && ! isClaimingProtocolAll && ! isClaimingMeritAll ;
5459
5560 // Use simple approach for individual protocol rewards (most common case)
5661 if ( isIndividualProtocolReward ) {
57- return claimRewards ( { isWrongNetwork, blocked, selectedReward, formattedReserves : reserves } ) ;
62+ return claimRewards ( {
63+ isWrongNetwork,
64+ blocked,
65+ selectedReward,
66+ formattedReserves : reserves ,
67+ } ) ;
5868 }
5969
6070 // Use complex multicall logic only when needed
@@ -64,17 +74,20 @@ export const ClaimRewardsActions = ({
6474 isWrongNetwork,
6575 blocked,
6676 selectedReward,
67- formattedReserves : reserves
77+ formattedReserves : reserves ,
6878 } ) ;
6979
7080 // Create multicall transaction that includes both protocol and merit claims
7181 if ( ! meritClaimRewards ?. transaction ) {
7282 throw new Error ( 'Merit rewards transaction not available' ) ;
7383 }
74- const multicallTx = await createMulticallTransaction ( protocolTxns , meritClaimRewards . transaction ) ;
84+ const multicallTx = await createMulticallTransaction (
85+ protocolTxns ,
86+ meritClaimRewards . transaction
87+ ) ;
7588
7689 // Check if there are any approval transactions that need to be handled separately
77- const approvalTxns = protocolTxns . filter ( tx => tx . txType === 'ERC20_APPROVAL' ) ;
90+ const approvalTxns = protocolTxns . filter ( ( tx ) => tx . txType === 'ERC20_APPROVAL' ) ;
7891
7992 return approvalTxns . length > 0 ? [ ...approvalTxns , multicallTx ] : [ multicallTx ] ;
8093 } else if ( ( isClaimingAll && ! hasProtocolRewards && hasMeritRewards ) || isClaimingMeritAll ) {
@@ -85,7 +98,12 @@ export const ClaimRewardsActions = ({
8598 return [ convertMeritTransactionToEthereum ( meritClaimRewards . transaction ) ] ;
8699 } else {
87100 // Protocol-all or other cases - use existing protocol logic
88- return claimRewards ( { isWrongNetwork, blocked, selectedReward, formattedReserves : reserves } ) ;
101+ return claimRewards ( {
102+ isWrongNetwork,
103+ blocked,
104+ selectedReward,
105+ formattedReserves : reserves ,
106+ } ) ;
89107 }
90108 } ,
91109 skip : Object . keys ( selectedReward ) . length === 0 || blocked ,
@@ -95,43 +113,39 @@ export const ClaimRewardsActions = ({
95113 // Helper function to create multicall transaction
96114 const createMulticallTransaction = async (
97115 protocolTxns : EthereumTransactionTypeExtended [ ] ,
98- meritTransaction : any
116+ meritTransaction : PopulatedTransaction
99117 ) : Promise < EthereumTransactionTypeExtended > => {
100118 // Multicall3 contract address (same across chains)
101119 const multicallAddress = '0xcA11bde05977b3631167028862bE2a173976CA11' ;
102120
103- // Prepare calls array for multicall
104121 const calls = [ ] ;
105122
106- // Add protocol transaction calls
107123 for ( const txExt of protocolTxns ) {
108124 if ( txExt . txType === 'ERC20_APPROVAL' ) continue ; // Skip approvals for multicall
109125
110126 const tx = await txExt . tx ( ) ;
111127 calls . push ( {
112128 target : tx . to ,
113129 callData : tx . data ,
114- value : tx . value || '0'
130+ value : tx . value || '0' ,
115131 } ) ;
116132 }
117133
118- // Add merit transaction call
119134 calls . push ( {
120135 target : meritTransaction . to ,
121136 callData : meritTransaction . data ,
122- value : meritTransaction . value || '0'
137+ value : meritTransaction . value || '0' ,
123138 } ) ;
124139
125- // Encode multicall
126140 const multicallInterface = new utils . Interface ( [
127- 'function aggregate3Value((address target, bool allowFailure, uint256 value, bytes callData)[] calls) payable returns ((bool success, bytes returnData)[])'
141+ 'function aggregate3Value((address target, bool allowFailure, uint256 value, bytes callData)[] calls) payable returns ((bool success, bytes returnData)[])' ,
128142 ] ) ;
129143
130- const callsWithFailure = calls . map ( call => [
144+ const callsWithFailure = calls . map ( ( call ) => [
131145 call . target ,
132146 false , // allowFailure = false
133147 call . value ,
134- call . callData
148+ call . callData ,
135149 ] ) ;
136150
137151 const data = multicallInterface . encodeFunctionData ( 'aggregate3Value' , [ callsWithFailure ] ) ;
@@ -144,27 +158,71 @@ export const ClaimRewardsActions = ({
144158 data,
145159 value : '0' ,
146160 } ) ,
147- gas : async ( ) => ( {
148- gasLimit : '800000' , // Conservative gas limit for multicall
149- gasPrice : '0' ,
150- } ) ,
161+ gas : async ( ) => {
162+ try {
163+ const tx = {
164+ to : multicallAddress ,
165+ from : currentAccount ,
166+ data,
167+ value : BigNumber . from ( '0' ) ,
168+ } ;
169+
170+ const estimatedTx = await estimateGasLimit ( tx , currentMarketData . chainId ) ;
171+
172+ return {
173+ gasLimit : estimatedTx . gasLimit ?. toString ( ) ,
174+ gasPrice : '0' ,
175+ } ;
176+ } catch ( error ) {
177+ console . warn ( 'Gas estimation failed for multicall, using fallback:' , error ) ;
178+ return {
179+ gasLimit : '800000' , // Conservative fallback
180+ gasPrice : '0' ,
181+ } ;
182+ }
183+ } ,
151184 } ;
152185 } ;
153186
154187 // Helper function to convert merit transaction to Ethereum format
155- const convertMeritTransactionToEthereum = ( meritTx : any ) : EthereumTransactionTypeExtended => {
188+ const convertMeritTransactionToEthereum = (
189+ meritTx : PopulatedTransaction
190+ ) : EthereumTransactionTypeExtended => {
156191 return {
157192 txType : eEthereumTxType . DLP_ACTION ,
158193 tx : async ( ) => ( {
159194 to : meritTx . to ,
160195 from : meritTx . from || currentAccount ,
161196 data : meritTx . data ,
162- value : meritTx . value || '0' ,
163- } ) ,
164- gas : async ( ) => ( {
165- gasLimit : '400000' , // Conservative gas limit for merit only
166- gasPrice : '0' ,
197+ value : meritTx . value
198+ ? BigNumber . isBigNumber ( meritTx . value )
199+ ? meritTx . value . toString ( )
200+ : meritTx . value
201+ : '0' ,
167202 } ) ,
203+ gas : async ( ) => {
204+ try {
205+ const tx = {
206+ to : meritTx . to ,
207+ from : meritTx . from || currentAccount ,
208+ data : meritTx . data ,
209+ value : meritTx . value ,
210+ } ;
211+
212+ const estimatedTx = await estimateGasLimit ( tx , currentMarketData . chainId ) ;
213+
214+ return {
215+ gasLimit : estimatedTx . gasLimit ?. toString ( ) ,
216+ gasPrice : '0' ,
217+ } ;
218+ } catch ( error ) {
219+ console . warn ( 'Gas estimation failed for merit transaction, using fallback:' , error ) ;
220+ return {
221+ gasLimit : '400000' ,
222+ gasPrice : '0' ,
223+ } ;
224+ }
225+ } ,
168226 } ;
169227 } ;
170228
0 commit comments