Skip to content

Commit dcec418

Browse files
authored
Merge pull request #595 from aave/feat/594-minify-pool
Reducing pool size
2 parents 97ea0d6 + 1cb2324 commit dcec418

File tree

8 files changed

+216
-106
lines changed

8 files changed

+216
-106
lines changed

contracts/interfaces/IPool.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -699,7 +699,7 @@ interface IPool {
699699
* @notice Returns the maximum number of reserves supported to be listed in this Pool
700700
* @return The maximum number of reserves supported
701701
*/
702-
function MAX_NUMBER_RESERVES() external view returns (uint256);
702+
function MAX_NUMBER_RESERVES() external view returns (uint16);
703703

704704
/**
705705
* @notice Mints the assets accrued through the reserve factor to the treasury in the form of aTokens

contracts/mocks/helpers/MockPool.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ contract MockPoolInherited is Pool {
4242
_maxNumberOfReserves = newMaxNumberOfReserves;
4343
}
4444

45-
function MAX_NUMBER_RESERVES() public view override returns (uint256) {
45+
function MAX_NUMBER_RESERVES() public view override returns (uint16) {
4646
return _maxNumberOfReserves;
4747
}
4848

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
// SPDX-License-Identifier: BUSL-1.1
2+
pragma solidity 0.8.10;
3+
4+
import {GPv2SafeERC20} from '../../../dependencies/gnosis/contracts/GPv2SafeERC20.sol';
5+
import {Address} from '../../../dependencies/openzeppelin/contracts/Address.sol';
6+
import {IERC20} from '../../../dependencies/openzeppelin/contracts/IERC20.sol';
7+
import {IAToken} from '../../../interfaces/IAToken.sol';
8+
import {ReserveConfiguration} from '../configuration/ReserveConfiguration.sol';
9+
import {Errors} from '../helpers/Errors.sol';
10+
import {WadRayMath} from '../math/WadRayMath.sol';
11+
import {DataTypes} from '../types/DataTypes.sol';
12+
import {ReserveLogic} from './ReserveLogic.sol';
13+
import {ValidationLogic} from './ValidationLogic.sol';
14+
15+
/**
16+
* @title PoolLogic library
17+
* @author Aave
18+
* @notice Implements the logic for Pool specific functions
19+
*/
20+
library PoolLogic {
21+
using GPv2SafeERC20 for IERC20;
22+
using WadRayMath for uint256;
23+
using ReserveLogic for DataTypes.ReserveData;
24+
using ReserveConfiguration for DataTypes.ReserveConfigurationMap;
25+
26+
// See `IPool` for descriptions
27+
event MintedToTreasury(address indexed reserve, uint256 amountMinted);
28+
event IsolationModeTotalDebtUpdated(address indexed asset, uint256 totalDebt);
29+
30+
/**
31+
* @notice Initialize an asset reserve and add the reserve to the list of reserves
32+
* @param reservesData The state of all the reserves
33+
* @param reserves The addresses of all the active reserves
34+
* @param params Additional parameters needed for initiation
35+
* @return true if appended, false if inserted at existing empty spot
36+
**/
37+
function executeInitReserve(
38+
mapping(address => DataTypes.ReserveData) storage reservesData,
39+
mapping(uint256 => address) storage reserves,
40+
DataTypes.InitReserveParams memory params
41+
) external returns (bool) {
42+
require(Address.isContract(params.asset), Errors.NOT_CONTRACT);
43+
reservesData[params.asset].init(
44+
params.aTokenAddress,
45+
params.stableDebtAddress,
46+
params.variableDebtAddress,
47+
params.interestRateStrategyAddress
48+
);
49+
50+
bool reserveAlreadyAdded = reservesData[params.asset].id != 0 || reserves[0] == params.asset;
51+
require(!reserveAlreadyAdded, Errors.RESERVE_ALREADY_ADDED);
52+
53+
for (uint16 i = 0; i < params.reservesCount; i++) {
54+
if (reserves[i] == address(0)) {
55+
reservesData[params.asset].id = i;
56+
reserves[i] = params.asset;
57+
return false;
58+
}
59+
}
60+
61+
require(params.reservesCount < params.maxNumberReserves, Errors.NO_MORE_RESERVES_ALLOWED);
62+
reservesData[params.asset].id = params.reservesCount;
63+
reserves[params.reservesCount] = params.asset;
64+
return true;
65+
}
66+
67+
/**
68+
* @notice Rescue and transfer tokens locked in this contract
69+
* @param token The address of the token
70+
* @param to The address of the recipient
71+
* @param amount The amount of token to transfer
72+
*/
73+
function executeRescueTokens(
74+
address token,
75+
address to,
76+
uint256 amount
77+
) external {
78+
IERC20(token).safeTransfer(to, amount);
79+
}
80+
81+
/**
82+
* @notice Mints the assets accrued through the reserve factor to the treasury in the form of aTokens
83+
* @param reservesData The state of all the reserves
84+
* @param assets The list of reserves for which the minting needs to be executed
85+
**/
86+
function executeMintToTreasury(
87+
mapping(address => DataTypes.ReserveData) storage reservesData,
88+
address[] calldata assets
89+
) external {
90+
for (uint256 i = 0; i < assets.length; i++) {
91+
address assetAddress = assets[i];
92+
93+
DataTypes.ReserveData storage reserve = reservesData[assetAddress];
94+
95+
// this cover both inactive reserves and invalid reserves since the flag will be 0 for both
96+
if (!reserve.configuration.getActive()) {
97+
continue;
98+
}
99+
100+
uint256 accruedToTreasury = reserve.accruedToTreasury;
101+
102+
if (accruedToTreasury != 0) {
103+
reserve.accruedToTreasury = 0;
104+
uint256 normalizedIncome = reserve.getNormalizedIncome();
105+
uint256 amountToMint = accruedToTreasury.rayMul(normalizedIncome);
106+
IAToken(reserve.aTokenAddress).mintToTreasury(amountToMint, normalizedIncome);
107+
108+
emit MintedToTreasury(assetAddress, amountToMint);
109+
}
110+
}
111+
}
112+
113+
/**
114+
* @notice Resets the isolation mode total debt of the given asset to zero
115+
* @dev It requires the given asset has zero debt ceiling
116+
* @param reservesData The state of all the reserves
117+
* @param asset The address of the underlying asset to reset the isolationModeTotalDebt
118+
*/
119+
function executeResetIsolationModeTotalDebt(
120+
mapping(address => DataTypes.ReserveData) storage reservesData,
121+
address asset
122+
) external {
123+
require(reservesData[asset].configuration.getDebtCeiling() == 0, Errors.DEBT_CEILING_NOT_ZERO);
124+
reservesData[asset].isolationModeTotalDebt = 0;
125+
emit IsolationModeTotalDebtUpdated(asset, 0);
126+
}
127+
128+
/**
129+
* @notice Drop a reserve
130+
* @param reservesData The state of all the reserves
131+
* @param reserves The addresses of all the active reserves
132+
* @param asset The address of the underlying asset of the reserve
133+
**/
134+
function executeDropReserve(
135+
mapping(address => DataTypes.ReserveData) storage reservesData,
136+
mapping(uint256 => address) storage reserves,
137+
address asset
138+
) external {
139+
DataTypes.ReserveData storage reserve = reservesData[asset];
140+
ValidationLogic.validateDropReserve(reserves, reserve, asset);
141+
reserves[reservesData[asset].id] = address(0);
142+
delete reservesData[asset];
143+
}
144+
}

contracts/protocol/libraries/types/DataTypes.sol

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,4 +255,14 @@ library DataTypes {
255255
address reserve;
256256
address aToken;
257257
}
258+
259+
struct InitReserveParams {
260+
address asset;
261+
address aTokenAddress;
262+
address stableDebtAddress;
263+
address variableDebtAddress;
264+
address interestRateStrategyAddress;
265+
uint16 reservesCount;
266+
uint16 maxNumberReserves;
267+
}
258268
}

contracts/protocol/pool/Pool.sol

Lines changed: 30 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,21 @@
11
// SPDX-License-Identifier: BUSL-1.1
22
pragma solidity 0.8.10;
33

4-
import {IERC20} from '../../dependencies/openzeppelin/contracts/IERC20.sol';
5-
import {GPv2SafeERC20} from '../../dependencies/gnosis/contracts/GPv2SafeERC20.sol';
6-
import {Address} from '../../dependencies/openzeppelin/contracts/Address.sol';
74
import {VersionedInitializable} from '../libraries/aave-upgradeability/VersionedInitializable.sol';
85
import {Errors} from '../libraries/helpers/Errors.sol';
9-
import {WadRayMath} from '../libraries/math/WadRayMath.sol';
6+
import {ReserveConfiguration} from '../libraries/configuration/ReserveConfiguration.sol';
7+
import {PoolLogic} from '../libraries/logic/PoolLogic.sol';
108
import {ReserveLogic} from '../libraries/logic/ReserveLogic.sol';
119
import {GenericLogic} from '../libraries/logic/GenericLogic.sol';
12-
import {ValidationLogic} from '../libraries/logic/ValidationLogic.sol';
1310
import {EModeLogic} from '../libraries/logic/EModeLogic.sol';
1411
import {SupplyLogic} from '../libraries/logic/SupplyLogic.sol';
1512
import {FlashLoanLogic} from '../libraries/logic/FlashLoanLogic.sol';
1613
import {BorrowLogic} from '../libraries/logic/BorrowLogic.sol';
1714
import {LiquidationLogic} from '../libraries/logic/LiquidationLogic.sol';
18-
import {ReserveConfiguration} from '../libraries/configuration/ReserveConfiguration.sol';
1915
import {DataTypes} from '../libraries/types/DataTypes.sol';
2016
import {BridgeLogic} from '../libraries/logic/BridgeLogic.sol';
2117
import {IERC20WithPermit} from '../../interfaces/IERC20WithPermit.sol';
2218
import {IPoolAddressesProvider} from '../../interfaces/IPoolAddressesProvider.sol';
23-
import {IAToken} from '../../interfaces/IAToken.sol';
2419
import {IPool} from '../../interfaces/IPool.sol';
2520
import {IACLManager} from '../../interfaces/IACLManager.sol';
2621
import {PoolStorage} from './PoolStorage.sol';
@@ -43,10 +38,7 @@ import {PoolStorage} from './PoolStorage.sol';
4338
* PoolAddressesProvider
4439
**/
4540
contract Pool is VersionedInitializable, IPool, PoolStorage {
46-
using WadRayMath for uint256;
47-
using GPv2SafeERC20 for IERC20;
4841
using ReserveLogic for DataTypes.ReserveData;
49-
using ReserveConfiguration for DataTypes.ReserveConfigurationMap;
5042

5143
uint256 public constant POOL_REVISION = 0x1;
5244
IPoolAddressesProvider public immutable ADDRESSES_PROVIDER;
@@ -449,27 +441,7 @@ contract Pool is VersionedInitializable, IPool, PoolStorage {
449441

450442
/// @inheritdoc IPool
451443
function mintToTreasury(address[] calldata assets) external override {
452-
for (uint256 i = 0; i < assets.length; i++) {
453-
address assetAddress = assets[i];
454-
455-
DataTypes.ReserveData storage reserve = _reserves[assetAddress];
456-
457-
// this cover both inactive reserves and invalid reserves since the flag will be 0 for both
458-
if (!reserve.configuration.getActive()) {
459-
continue;
460-
}
461-
462-
uint256 accruedToTreasury = reserve.accruedToTreasury;
463-
464-
if (accruedToTreasury != 0) {
465-
reserve.accruedToTreasury = 0;
466-
uint256 normalizedIncome = reserve.getNormalizedIncome();
467-
uint256 amountToMint = accruedToTreasury.rayMul(normalizedIncome);
468-
IAToken(reserve.aTokenAddress).mintToTreasury(amountToMint, normalizedIncome);
469-
470-
emit MintedToTreasury(assetAddress, amountToMint);
471-
}
472-
}
444+
PoolLogic.executeMintToTreasury(_reserves, assets);
473445
}
474446

475447
/// @inheritdoc IPool
@@ -566,23 +538,23 @@ contract Pool is VersionedInitializable, IPool, PoolStorage {
566538

567539
/// @inheritdoc IPool
568540
function getReservesList() external view override returns (address[] memory) {
569-
uint256 reserveListCount = _reservesCount;
541+
uint256 reservesListCount = _reservesCount;
570542
uint256 droppedReservesCount = 0;
571-
address[] memory reserves = new address[](reserveListCount);
543+
address[] memory reservesList = new address[](reservesListCount);
572544

573-
for (uint256 i = 0; i < reserveListCount; i++) {
545+
for (uint256 i = 0; i < reservesListCount; i++) {
574546
if (_reservesList[i] != address(0)) {
575-
reserves[i - droppedReservesCount] = _reservesList[i];
547+
reservesList[i - droppedReservesCount] = _reservesList[i];
576548
} else {
577549
droppedReservesCount++;
578550
}
579551
}
580552

581553
// Reduces the length of the reserves array by `droppedReservesCount`
582554
assembly {
583-
mstore(reserves, sub(reserveListCount, droppedReservesCount))
555+
mstore(reservesList, sub(reservesListCount, droppedReservesCount))
584556
}
585-
return reserves;
557+
return reservesList;
586558
}
587559

588560
/// @inheritdoc IPool
@@ -606,7 +578,7 @@ contract Pool is VersionedInitializable, IPool, PoolStorage {
606578
}
607579

608580
/// @inheritdoc IPool
609-
function MAX_NUMBER_RESERVES() public view virtual override returns (uint256) {
581+
function MAX_NUMBER_RESERVES() public view virtual override returns (uint16) {
610582
return ReserveConfiguration.MAX_RESERVES_COUNT;
611583
}
612584

@@ -647,22 +619,28 @@ contract Pool is VersionedInitializable, IPool, PoolStorage {
647619
address variableDebtAddress,
648620
address interestRateStrategyAddress
649621
) external override onlyPoolConfigurator {
650-
require(Address.isContract(asset), Errors.NOT_CONTRACT);
651-
_reserves[asset].init(
652-
aTokenAddress,
653-
stableDebtAddress,
654-
variableDebtAddress,
655-
interestRateStrategyAddress
656-
);
657-
_addReserveToList(asset);
622+
if (
623+
PoolLogic.executeInitReserve(
624+
_reserves,
625+
_reservesList,
626+
DataTypes.InitReserveParams({
627+
asset: asset,
628+
aTokenAddress: aTokenAddress,
629+
stableDebtAddress: stableDebtAddress,
630+
variableDebtAddress: variableDebtAddress,
631+
interestRateStrategyAddress: interestRateStrategyAddress,
632+
reservesCount: _reservesCount,
633+
maxNumberReserves: MAX_NUMBER_RESERVES()
634+
})
635+
)
636+
) {
637+
_reservesCount++;
638+
}
658639
}
659640

660641
/// @inheritdoc IPool
661642
function dropReserve(address asset) external virtual override onlyPoolConfigurator {
662-
DataTypes.ReserveData storage reserve = _reserves[asset];
663-
ValidationLogic.validateDropReserve(_reservesList, reserve, asset);
664-
_reservesList[_reserves[asset].id] = address(0);
665-
delete _reserves[asset];
643+
PoolLogic.executeDropReserve(_reserves, _reservesList, asset);
666644
}
667645

668646
/// @inheritdoc IPool
@@ -745,9 +723,7 @@ contract Pool is VersionedInitializable, IPool, PoolStorage {
745723

746724
/// @inheritdoc IPool
747725
function resetIsolationModeTotalDebt(address asset) external override onlyPoolConfigurator {
748-
require(_reserves[asset].configuration.getDebtCeiling() == 0, Errors.DEBT_CEILING_NOT_ZERO);
749-
_reserves[asset].isolationModeTotalDebt = 0;
750-
emit IsolationModeTotalDebtUpdated(asset, 0);
726+
PoolLogic.executeResetIsolationModeTotalDebt(_reserves, asset);
751727
}
752728

753729
/// @inheritdoc IPool
@@ -756,31 +732,7 @@ contract Pool is VersionedInitializable, IPool, PoolStorage {
756732
address to,
757733
uint256 amount
758734
) external override onlyPoolAdmin {
759-
IERC20(token).safeTransfer(to, amount);
760-
}
761-
762-
/**
763-
* @notice Add an asset to the reserve list
764-
* @param asset The address of the underlying asset
765-
*/
766-
function _addReserveToList(address asset) internal {
767-
bool reserveAlreadyAdded = _reserves[asset].id != 0 || _reservesList[0] == asset;
768-
require(!reserveAlreadyAdded, Errors.RESERVE_ALREADY_ADDED);
769-
770-
uint16 reservesCount = _reservesCount;
771-
772-
for (uint16 i = 0; i < reservesCount; i++) {
773-
if (_reservesList[i] == address(0)) {
774-
_reserves[asset].id = i;
775-
_reservesList[i] = asset;
776-
return;
777-
}
778-
}
779-
require(reservesCount < MAX_NUMBER_RESERVES(), Errors.NO_MORE_RESERVES_ALLOWED);
780-
_reserves[asset].id = reservesCount;
781-
_reservesList[reservesCount] = asset;
782-
// no need to check for overflow - the require above must ensure that max number of reserves < type(uint16).max
783-
_reservesCount = reservesCount + 1;
735+
PoolLogic.executeRescueTokens(token, to, amount);
784736
}
785737

786738
/// @inheritdoc IPool

0 commit comments

Comments
 (0)