Skip to content
This repository was archived by the owner on Oct 21, 2025. It is now read-only.

Commit e52b435

Browse files
authored
Merge pull request #55 from aave/feat/gas-golfing-incentivescontroller
Gas golfing incentivesController
2 parents 86fc824 + eb76389 commit e52b435

23 files changed

+3181
-707
lines changed

contracts/misc/UiIncentiveDataProviderV3.sol

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -263,14 +263,14 @@ contract UiIncentiveDataProviderV3 is IUiIncentiveDataProviderV3 {
263263
userRewardInformation.rewardTokenAddress = aTokenRewardAddresses[j];
264264

265265
userRewardInformation.tokenIncentivesUserIndex = aTokenIncentiveController
266-
.getUserAssetData(
266+
.getUserAssetIndex(
267267
user,
268268
baseData.aTokenAddress,
269269
userRewardInformation.rewardTokenAddress
270270
);
271271

272272
userRewardInformation.userUnclaimedRewards = aTokenIncentiveController
273-
.getUserUnclaimedRewardsFromStorage(user, userRewardInformation.rewardTokenAddress);
273+
.getUserAccruedRewards(user, userRewardInformation.rewardTokenAddress);
274274
userRewardInformation.rewardTokenDecimals = IERC20Detailed(
275275
userRewardInformation.rewardTokenAddress
276276
).decimals();
@@ -316,14 +316,14 @@ contract UiIncentiveDataProviderV3 is IUiIncentiveDataProviderV3 {
316316
userRewardInformation.rewardTokenAddress = vTokenRewardAddresses[j];
317317

318318
userRewardInformation.tokenIncentivesUserIndex = vTokenIncentiveController
319-
.getUserAssetData(
319+
.getUserAssetIndex(
320320
user,
321321
baseData.variableDebtTokenAddress,
322322
userRewardInformation.rewardTokenAddress
323323
);
324324

325325
userRewardInformation.userUnclaimedRewards = vTokenIncentiveController
326-
.getUserUnclaimedRewardsFromStorage(user, userRewardInformation.rewardTokenAddress);
326+
.getUserAccruedRewards(user, userRewardInformation.rewardTokenAddress);
327327
userRewardInformation.rewardTokenDecimals = IERC20Detailed(
328328
userRewardInformation.rewardTokenAddress
329329
).decimals();
@@ -369,14 +369,14 @@ contract UiIncentiveDataProviderV3 is IUiIncentiveDataProviderV3 {
369369
userRewardInformation.rewardTokenAddress = sTokenRewardAddresses[j];
370370

371371
userRewardInformation.tokenIncentivesUserIndex = sTokenIncentiveController
372-
.getUserAssetData(
372+
.getUserAssetIndex(
373373
user,
374374
baseData.stableDebtTokenAddress,
375375
userRewardInformation.rewardTokenAddress
376376
);
377377

378378
userRewardInformation.userUnclaimedRewards = sTokenIncentiveController
379-
.getUserUnclaimedRewardsFromStorage(user, userRewardInformation.rewardTokenAddress);
379+
.getUserAccruedRewards(user, userRewardInformation.rewardTokenAddress);
380380
userRewardInformation.rewardTokenDecimals = IERC20Detailed(
381381
userRewardInformation.rewardTokenAddress
382382
).decimals();

contracts/mocks/ATokenMock.sol

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,22 @@ contract ATokenMock {
99
uint256 internal _totalSupply;
1010
uint256 internal immutable _decimals;
1111

12-
// hack to be able to test event from EI properly
13-
event RewardsAccrued(address indexed user, uint256 amount);
14-
1512
// hack to be able to test event from Distribution manager properly
16-
event AssetConfigUpdated(address indexed asset, uint256 emission);
17-
event AssetIndexUpdated(address indexed asset, uint256 index);
18-
event UserIndexUpdated(address indexed user, address indexed asset, uint256 index);
13+
event AssetConfigUpdated(
14+
address indexed asset,
15+
address indexed reward,
16+
uint256 emission,
17+
uint256 distributionEnd,
18+
uint256 assetIndex
19+
);
20+
21+
event Accrued(
22+
address indexed asset,
23+
address indexed user,
24+
uint256 assetIndex,
25+
uint256 userIndex,
26+
uint256 rewardsAccrued
27+
);
1928

2029
constructor(IRewardsController aic, uint256 decimals) {
2130
_aic = aic;
@@ -52,6 +61,10 @@ contract ATokenMock {
5261
return _totalSupply;
5362
}
5463

64+
function totalSupply() external view returns (uint256) {
65+
return _totalSupply;
66+
}
67+
5568
function cleanUserState() external {
5669
_userBalance = 0;
5770
_totalSupply = 0;

contracts/rewards/RewardsController.sol

Lines changed: 54 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22
pragma solidity 0.8.10;
33

44
import {VersionedInitializable} from '@aave/core-v3/contracts/protocol/libraries/aave-upgradeability/VersionedInitializable.sol';
5+
import {SafeCast} from '@aave/core-v3/contracts/dependencies/openzeppelin/contracts/SafeCast.sol';
56
import {IScaledBalanceToken} from '@aave/core-v3/contracts/interfaces/IScaledBalanceToken.sol';
67
import {RewardsDistributor} from './RewardsDistributor.sol';
78
import {IRewardsController} from './interfaces/IRewardsController.sol';
89
import {ITransferStrategyBase} from './interfaces/ITransferStrategyBase.sol';
9-
import {RewardsDistributorTypes} from './libraries/RewardsDistributorTypes.sol';
10+
import {RewardsDataTypes} from './libraries/RewardsDataTypes.sol';
1011
import {IEACAggregatorProxy} from '../misc/interfaces/IEACAggregatorProxy.sol';
1112

1213
/**
@@ -15,6 +16,8 @@ import {IEACAggregatorProxy} from '../misc/interfaces/IEACAggregatorProxy.sol';
1516
* @author Aave
1617
**/
1718
contract RewardsController is RewardsDistributor, VersionedInitializable, IRewardsController {
19+
using SafeCast for uint256;
20+
1821
uint256 public constant REVISION = 1;
1922

2023
// This mapping allows whitelisted addresses to claim on behalf of others
@@ -69,7 +72,7 @@ contract RewardsController is RewardsDistributor, VersionedInitializable, IRewar
6972
}
7073

7174
/// @inheritdoc IRewardsController
72-
function configureAssets(RewardsDistributorTypes.RewardsConfigInput[] memory config)
75+
function configureAssets(RewardsDataTypes.RewardsConfigInput[] memory config)
7376
external
7477
override
7578
onlyEmissionManager
@@ -109,7 +112,7 @@ contract RewardsController is RewardsDistributor, VersionedInitializable, IRewar
109112
uint256 totalSupply,
110113
uint256 userBalance
111114
) external override {
112-
_updateUserRewardsPerAssetInternal(msg.sender, user, userBalance, totalSupply);
115+
_updateData(msg.sender, user, userBalance, totalSupply);
113116
}
114117

115118
/// @inheritdoc IRewardsController
@@ -187,28 +190,28 @@ contract RewardsController is RewardsDistributor, VersionedInitializable, IRewar
187190
}
188191

189192
/**
190-
* @dev Get usage statistics of a list of assets that supports IScaledBalanceToken interface
193+
* @dev Get user balances and total supply of all the assets specified by the assets parameter
191194
* @param assets List of assets to retrieve user balance and total supply
192195
* @param user Address of the user
193-
* @return userState contains a list of usage statistics like user balance and total supply of the assets passed as argument
196+
* @return userAssetBalances contains a list of structs with user balance and total supply of the given assets
194197
*/
195-
function _getUserStake(address[] calldata assets, address user)
198+
function _getUserAssetBalances(address[] calldata assets, address user)
196199
internal
197200
view
198201
override
199-
returns (RewardsDistributorTypes.UserAssetStatsInput[] memory userState)
202+
returns (RewardsDataTypes.UserAssetBalance[] memory userAssetBalances)
200203
{
201-
userState = new RewardsDistributorTypes.UserAssetStatsInput[](assets.length);
204+
userAssetBalances = new RewardsDataTypes.UserAssetBalance[](assets.length);
202205
for (uint256 i = 0; i < assets.length; i++) {
203-
userState[i].underlyingAsset = assets[i];
204-
(userState[i].userBalance, userState[i].totalSupply) = IScaledBalanceToken(assets[i])
206+
userAssetBalances[i].asset = assets[i];
207+
(userAssetBalances[i].userBalance, userAssetBalances[i].totalSupply) = IScaledBalanceToken(assets[i])
205208
.getScaledUserBalanceAndSupply(user);
206209
}
207-
return userState;
210+
return userAssetBalances;
208211
}
209212

210213
/**
211-
* @dev Claims one type of reward for an user on behalf, on all the assets of the lending pool, accumulating the pending rewards.
214+
* @dev Claims one type of reward for a user on behalf, on all the assets of the pool, accumulating the pending rewards.
212215
* @param assets List of assets to check eligible distributions before claiming rewards
213216
* @param amount Amount of rewards to claim
214217
* @param claimer Address of the claimer who claims rewards on behalf of user
@@ -228,28 +231,35 @@ contract RewardsController is RewardsDistributor, VersionedInitializable, IRewar
228231
if (amount == 0) {
229232
return 0;
230233
}
231-
uint256 unclaimedRewards = _usersUnclaimedRewards[user][reward];
234+
uint256 totalRewards;
232235

233-
if (amount > unclaimedRewards) {
234-
_distributeRewards(user, _getUserStake(assets, user));
235-
unclaimedRewards = _usersUnclaimedRewards[user][reward];
236+
_updateDataMultiple(user, _getUserAssetBalances(assets, user));
237+
for (uint256 i = 0; i < assets.length; i++) {
238+
address asset = assets[i];
239+
totalRewards += _assets[asset].rewards[reward].usersData[user].accrued;
240+
241+
if (totalRewards <= amount) {
242+
_assets[asset].rewards[reward].usersData[user].accrued = 0;
243+
} else {
244+
uint256 difference = totalRewards - amount;
245+
totalRewards -= difference;
246+
_assets[asset].rewards[reward].usersData[user].accrued = difference.toUint128();
247+
break;
248+
}
236249
}
237250

238-
if (unclaimedRewards == 0) {
251+
if (totalRewards == 0) {
239252
return 0;
240253
}
241254

242-
uint256 amountToClaim = amount > unclaimedRewards ? unclaimedRewards : amount;
243-
_usersUnclaimedRewards[user][reward] = unclaimedRewards - amountToClaim; // Safe due to the previous line
244-
245-
_transferRewards(to, reward, amountToClaim);
246-
emit RewardsClaimed(user, reward, to, claimer, amountToClaim);
255+
_transferRewards(to, reward, totalRewards);
256+
emit RewardsClaimed(user, reward, to, claimer, totalRewards);
247257

248-
return amountToClaim;
258+
return totalRewards;
249259
}
250260

251261
/**
252-
* @dev Claims one type of reward for an user on behalf, on all the assets of the lending pool, accumulating the pending rewards.
262+
* @dev Claims one type of reward for a user on behalf, on all the assets of the pool, accumulating the pending rewards.
253263
* @param assets List of assets to check eligible distributions before claiming rewards
254264
* @param claimer Address of the claimer on behalf of user
255265
* @param user Address to check and claim rewards
@@ -264,24 +274,29 @@ contract RewardsController is RewardsDistributor, VersionedInitializable, IRewar
264274
address user,
265275
address to
266276
) internal returns (address[] memory rewardsList, uint256[] memory claimedAmounts) {
267-
_distributeRewards(user, _getUserStake(assets, user));
277+
uint256 rewardsListLength = _rewardsList.length;
278+
rewardsList = new address[](rewardsListLength);
279+
claimedAmounts = new uint256[](rewardsListLength);
268280

269-
rewardsList = new address[](_rewardsList.length);
270-
claimedAmounts = new uint256[](_rewardsList.length);
281+
_updateDataMultiple(user, _getUserAssetBalances(assets, user));
271282

272-
for (uint256 i = 0; i < _rewardsList.length; i++) {
273-
address reward = _rewardsList[i];
274-
uint256 rewardAmount = _usersUnclaimedRewards[user][reward];
275-
276-
rewardsList[i] = reward;
277-
claimedAmounts[i] = rewardAmount;
278-
279-
if (rewardAmount != 0) {
280-
_usersUnclaimedRewards[user][reward] = 0;
281-
_transferRewards(to, reward, rewardAmount);
282-
emit RewardsClaimed(user, reward, to, claimer, rewardAmount);
283+
for (uint256 i = 0; i < assets.length; i++) {
284+
address asset = assets[i];
285+
for (uint256 j = 0; j < rewardsListLength; j++) {
286+
if (rewardsList[j] == address(0)) {
287+
rewardsList[j] = _rewardsList[j];
288+
}
289+
uint256 rewardAmount = _assets[asset].rewards[rewardsList[j]].usersData[user].accrued;
290+
if (rewardAmount != 0) {
291+
claimedAmounts[j] += rewardAmount;
292+
_assets[asset].rewards[rewardsList[j]].usersData[user].accrued = 0;
293+
}
283294
}
284295
}
296+
for (uint256 i = 0; i < rewardsListLength; i++) {
297+
_transferRewards(to, rewardsList[i], claimedAmounts[i]);
298+
emit RewardsClaimed(user, rewardsList[i], to, claimer, claimedAmounts[i]);
299+
}
285300
return (rewardsList, claimedAmounts);
286301
}
287302

@@ -338,7 +353,7 @@ contract RewardsController is RewardsDistributor, VersionedInitializable, IRewar
338353
}
339354

340355
/**
341-
* @dev internal function to update the Price Oracle of a reward token. The Price Oracle must follow Chainlink IEACAggregatorProxy interface.
356+
* @dev Update the Price Oracle of a reward token. The Price Oracle must follow Chainlink IEACAggregatorProxy interface.
342357
* @notice The Price Oracle of a reward is used for displaying correct data about the incentives at the UI frontend.
343358
* @param reward The address of the reward token
344359
* @param rewardOracle The address of the price oracle

0 commit comments

Comments
 (0)