Skip to content

Commit 24d9fa1

Browse files
committed
feat: ui fixes for claiming
1 parent 88c88ea commit 24d9fa1

File tree

8 files changed

+294
-115
lines changed

8 files changed

+294
-115
lines changed

src/components/transactions/ClaimRewards/ClaimRewardsActions.tsx

Lines changed: 94 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
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';
27
import { Trans } from '@lingui/macro';
3-
import { utils } from 'ethers';
8+
import { BigNumber, PopulatedTransaction, utils } from 'ethers';
49
import { Reward } from 'src/helpers/types';
510
import { useTransactionHandler } from 'src/helpers/useTransactionHandler';
611
import { useAppDataContext } from 'src/hooks/app-data-provider/useAppDataProvider';
12+
import { useWeb3Context } from 'src/libs/hooks/useWeb3Context';
713
import { useRootStore } from 'src/store/root';
8-
9-
import { useMeritClaimRewards } from '@aave/react';
1014
import { useShallow } from 'zustand/shallow';
11-
import { useWeb3Context } from 'src/libs/hooks/useWeb3Context';
12-
1315

1416
import { 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

Comments
 (0)