diff --git a/LICENSE b/LICENSE index ab66bca8..aa471602 100644 --- a/LICENSE +++ b/LICENSE @@ -10,7 +10,7 @@ Parameters Licensor: Aave DAO, represented by its governance smart contracts -Licensed Work: Aave v3.1 +Licensed Work: Aave v3.2 The Licensed Work is (c) 2024 Aave DAO, represented by its governance smart contracts Additional Use Grant: You are permitted to use, copy, and modify the Licensed Work, subject to @@ -35,7 +35,7 @@ Additional Use Grant: You are permitted to use, copy, and modify the Licensed Wo Change Date: The earlier of: - 2027-03-06 - - If specified, the date in the 'change-date' record on v31.aavelicense.eth + - If specified, the date in the 'change-date' record on v32.aavelicense.eth Change License: MIT @@ -114,4 +114,4 @@ other recipients of the licensed work to be provided by Licensor: 3. To specify a Change Date. -4. Not to modify this License in any other way. \ No newline at end of file +4. Not to modify this License in any other way. diff --git a/README.md b/README.md index 9b99b38a..50222720 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ -# Aave V3.1 Origin +# Aave V3.2 Origin ![Aave v3.1 Origin_banner](./resources/v3-1-banner.jpeg) -Aave v3.1 complete codebase, Foundry-based. +Aave v3.2 complete codebase, Foundry-based. [![Coverage badge](./report/coverage.svg)](https://aave-dao.github.io/aave-v3-origin)
@@ -42,6 +42,8 @@ bun install - [Aave v3 technical Paper](./docs/Aave_V3_Technical_Paper.pdf) - [v3 to v3.0.2 production upgrade](https://github.com/bgd-labs/proposal-3.0.2-upgrade/blob/main/README.md) - [Aave v3.1 features](./docs/Aave-v3.1-features.md) +- [Aave v3.2 features](./docs/3.2/Aave-v3.2-features.md) +- [v3.1 to v3.2.0 production upgrade](https://github.com/bgd-labs/protocol-3.2.0-upgrade/blob/main/README.md) - [Set Ltv to 0 on Freeze Feature State diagram](./docs/freeze-ltv0-states.png)
@@ -85,7 +87,22 @@ The following are the security procedures historically applied to Aave v3.X vers - [MixBytes](./audits/02-05-2024_MixBytes_AaveV3.1.pdf) - An internal review by [SterMi](https://twitter.com/stermi) on the virtual accounting feature was conducted on an initial phase of the codebase. - [Cantina competition report](./audits/02-06-2024-Cantina-contest-AaveV3.1.pdf) -- Additionally, Certora properties have been improved over time since the Aave v3 release. More details [HERE](./certora/README.md). +- Additionally, Certora properties have been improved over time since the Aave v3 release. More details [HERE](./certora/basic/README.md). + +
+ +**-> Aave v3.2 - September 2024** + +#### Stable Rate and Liquid eModes + +- [Certora](./audits/2024-09-10_Certora_Aave-v3.2_Stable_Rate_Removal.pdf) +- [Enigma Dark](./audits/2024-09-30_Enigma_Aave-v3.2.pdf) + +#### Liquid eModes + +- [Certora](./audits/2024-09-19_Certora_Aave-v3.2_Liquid_eModes.pdf) +- [Oxorio](./audits/2024-09-12_Oxorio_Aav3-v3.2.pdf) +- [Pashov](./audits/2024-09-15_Pashov_Aave-v3.2.pdf)
diff --git a/audits/2024-09-10_Certora_Aave-v3.2_Stable_Rate_Removal.pdf b/audits/2024-09-10_Certora_Aave-v3.2_Stable_Rate_Removal.pdf new file mode 100644 index 00000000..fffe37eb Binary files /dev/null and b/audits/2024-09-10_Certora_Aave-v3.2_Stable_Rate_Removal.pdf differ diff --git a/audits/2024-09-12_Oxorio_Aav3-v3.2.pdf b/audits/2024-09-12_Oxorio_Aav3-v3.2.pdf new file mode 100644 index 00000000..3624d1cf Binary files /dev/null and b/audits/2024-09-12_Oxorio_Aav3-v3.2.pdf differ diff --git a/audits/2024-09-15_Pashov_Aave-v3.2.pdf b/audits/2024-09-15_Pashov_Aave-v3.2.pdf new file mode 100644 index 00000000..15939f52 Binary files /dev/null and b/audits/2024-09-15_Pashov_Aave-v3.2.pdf differ diff --git a/audits/2024-09-19_Certora_Aave-v3.2_Liquid_eModes.pdf b/audits/2024-09-19_Certora_Aave-v3.2_Liquid_eModes.pdf new file mode 100644 index 00000000..c6ad11d0 Binary files /dev/null and b/audits/2024-09-19_Certora_Aave-v3.2_Liquid_eModes.pdf differ diff --git a/audits/2024-09-30_Enigma_Aave-v3.2.pdf b/audits/2024-09-30_Enigma_Aave-v3.2.pdf new file mode 100644 index 00000000..aa5bec59 Binary files /dev/null and b/audits/2024-09-30_Enigma_Aave-v3.2.pdf differ diff --git a/certora/basic/harness/DummyContract.sol b/certora/basic/harness/DummyContract.sol index bc1dc298..bca97e32 100644 --- a/certora/basic/harness/DummyContract.sol +++ b/certora/basic/harness/DummyContract.sol @@ -1,8 +1,7 @@ - contract DummyContract { - function havoc_all_dummy() external { - // havoc_all_dummy_internal(); - } + function havoc_all_dummy() external { + // havoc_all_dummy_internal(); + } - //function havoc_all_dummy_internal() internal {} + //function havoc_all_dummy_internal() internal {} } diff --git a/certora/basic/harness/EModeConfigurationHarness.sol b/certora/basic/harness/EModeConfigurationHarness.sol index 593a7a0b..b4a92207 100644 --- a/certora/basic/harness/EModeConfigurationHarness.sol +++ b/certora/basic/harness/EModeConfigurationHarness.sol @@ -10,21 +10,29 @@ contract EModeConfigurationHarness { function setCollateral(uint256 reserveIndex, bool enabled) public { DataTypes.EModeCategory memory emode_new = eModeCategory; - eModeCategory.collateralBitmap = EModeConfiguration.setReserveBitmapBit(emode_new.collateralBitmap, reserveIndex, enabled); + eModeCategory.collateralBitmap = EModeConfiguration.setReserveBitmapBit( + emode_new.collateralBitmap, + reserveIndex, + enabled + ); } function isCollateralAsset(uint256 reserveIndex) public returns (bool) { - return EModeConfiguration.isReserveEnabledOnBitmap(eModeCategory.collateralBitmap, reserveIndex); + return + EModeConfiguration.isReserveEnabledOnBitmap(eModeCategory.collateralBitmap, reserveIndex); } - - - function setBorrowable(uint256 reserveIndex,bool enabled) public { + function setBorrowable(uint256 reserveIndex, bool enabled) public { DataTypes.EModeCategory memory emode_new = eModeCategory; - eModeCategory.borrowableBitmap = EModeConfiguration.setReserveBitmapBit(emode_new.borrowableBitmap, reserveIndex, enabled); + eModeCategory.borrowableBitmap = EModeConfiguration.setReserveBitmapBit( + emode_new.borrowableBitmap, + reserveIndex, + enabled + ); } - + function isBorrowableAsset(uint256 reserveIndex) public returns (bool) { - return EModeConfiguration.isReserveEnabledOnBitmap(eModeCategory.borrowableBitmap, reserveIndex); + return + EModeConfiguration.isReserveEnabledOnBitmap(eModeCategory.borrowableBitmap, reserveIndex); } } diff --git a/certora/basic/harness/PoolInstanceHarness.sol b/certora/basic/harness/PoolInstanceHarness.sol index 94dc4c29..ac9b7e0a 100644 --- a/certora/basic/harness/PoolInstanceHarness.sol +++ b/certora/basic/harness/PoolInstanceHarness.sol @@ -8,18 +8,18 @@ import {DataTypes} from '../munged/contracts/protocol/libraries/types/DataTypes. import {ReserveLogic} from '../munged/contracts/protocol/libraries/logic/ReserveLogic.sol'; import {WadRayMath} from '../munged/contracts/protocol/libraries/math/WadRayMath.sol'; -import {DummyContract} from "./DummyContract.sol"; - +import {DummyContract} from './DummyContract.sol'; contract PoolInstanceHarness is PoolInstance { DummyContract DUMMY; constructor(IPoolAddressesProvider provider) PoolInstance(provider) {} - function cumulateToLiquidityIndex(address asset, - uint256 totalLiquidity, - uint256 amount - ) external returns (uint256) { + function cumulateToLiquidityIndex( + address asset, + uint256 totalLiquidity, + uint256 amount + ) external returns (uint256) { return ReserveLogic.cumulateToLiquidityIndex(_reserves[asset], totalLiquidity, amount); } @@ -34,12 +34,12 @@ contract PoolInstanceHarness is PoolInstance { function havoc_all() public { DUMMY.havoc_all_dummy(); } - + function rayMul(uint256 a, uint256 b) external returns (uint256) { - return WadRayMath.rayMul(a,b); + return WadRayMath.rayMul(a, b); } - + function rayDiv(uint256 a, uint256 b) external returns (uint256) { - return WadRayMath.rayDiv(a,b); + return WadRayMath.rayDiv(a, b); } } diff --git a/certora/stata/harness/pool/SymbolicLendingPool.sol b/certora/stata/harness/pool/SymbolicLendingPool.sol index 1ee040f9..1051ae1e 100644 --- a/certora/stata/harness/pool/SymbolicLendingPool.sol +++ b/certora/stata/harness/pool/SymbolicLendingPool.sol @@ -80,7 +80,7 @@ contract SymbolicLendingPool { res.isolationModeTotalDebt = reserveLegacy.isolationModeTotalDebt; return res; } - + function getReserveDataExtended( address asset ) external view returns (DataTypes.ReserveData memory) { diff --git a/changelog/3.2.md b/changelog/3.2.md deleted file mode 100644 index 0b1e37d0..00000000 --- a/changelog/3.2.md +++ /dev/null @@ -1,115 +0,0 @@ -# Aave 3.2 - -Aave 3.2 focuses on two main areas of the aave protocol: - -- the final deprecation of stable borrowing -- improvements on the eModes - -## Stable Rate offboarding - -While previous upgrades allowed graceful offboarding of stable borrowing, now with no stable borrow positions being left the protcol can remove all the now obsolete stable rate related logic. - -### Migration guide - -The upgrade is 100% backwards compatible for anyone only integrating on the pool level. -There are no changes to any methods, nor are there changes to emitted events. -Parameters emitted in events that relate to stable rate are nulled. - -For anyone directly integrating with the InterestRateStrategy the method `calculateInterestRates` will no longer return the stable rate. - -``` -function calculateInterestRates( - DataTypes.CalculateInterestRatesParams memory params -- ) external view returns (uint256, uint256, uint256); -+ ) external view returns (uint256, uint256); -``` - -## Emodes: Removal of the eMode oracle - -The eMode oracle has never been used and it's usefulnes is debatable. -Therefore to allow for storage optimization within the eMode configuration and reduce unnecessary code paths - the eMode oracle was removed. - -#### Indexers - -For backwards compatibility the existing `EModeCategoryAdded` will be emitted, but with `oracle` being nullified. - -## Emodes: Liquid eModes - -The new Liquid eMode feature of Aave v3.2 removes the previous constraint: **an asset listed on Aave can be eligible for different eModes, and then it only depends on the user to choose which eMode he wants to enter to.** - -For example, with liquid eModes, a possible configuration not doable before would be: - -- eMode 1, with wstETH, weETH and WETH. -- eMode 2, with wstETH and WETH. -- eMode 3, with weETH and WETH. -- eMode 4, with WETH and GHO. - -So then, user A holding the wstETH and weETH collaterals, could borrow WETH at high LTV. -User B holding only wstETH could borrow WETH at high (but different) LTV. -User C holding only weETH could similarly borrow WETH at a different LTV than the previous two eModes. -User D could have a position with WETH collateral and GHO borrowings. - -This doesn’t stop there, as more sophisticated configuration strategies could be adopted, like: - -- eMode for only WETH and stablecoins. -- eMode for onboarding less mature LSTs, without requiring them being together with all major LSTs. - -**For extra configuration flexibility, liquid eModes also allow now to flag an asset as only borrowable, only collateral, or both, in the context of an eMode.** -For example, in a hypothetic eMode with only wstETH and WETH, the normal configuration would be wstETH as only collateral and WETH as only borrowable, fully focusing on the wstETH leverage use-case. - -### BREAKING CHANGES - -- DataTypes.EModeCategory will return the same data as now, but is flagged deprecated and will be removed at a later point. -- the new version of `PoolDataProvider` no longer exposes `PoolDataProvider.getReserveEModeCategory(address asset)` as there no longer is a `1:1` relation between assets and eModes. -- `reserveConfig.getEModeCategory()` will return the current eMode, but will no longer be updated and is flagged deprecated. - -### Migration guide - -For existing users, the upgrade is 100% backwards compatible and no migration or similar is required. -Entering and leaving an eMode still works via `setUserEMode(categoryId)` and `getUserEMode(address user)` like in previous versions of the protocol. - -#### Indexers - -As collateral/borrowable flags are newly introduced, two new events are being emitted: - -- `event AssetCollateralInEModeChanged(address indexed asset, uint8 categoryId, bool collateral);` -- `event AssetBorrowableInEModeChanged(address indexed asset, uint8 categoryId, bool borrowable);` - -#### Getters - -In aave 3.1 all eMode parameters were exposed via a single `getEModeCategoryData` getter. -When checking existing integrations, we noticed that in most cases this approach is suboptimal, given that users only rely on a subset of the data. -Therefore in addition to the **deprecated** `getEModeCategoryData` getter there are now independent getters for the respective values: - -- `getEModeCategoryCollateralConfig(categoryId)`, returning the eMode ltv,lt,lb -- `getEModeCategoryLabel(categoryId)`, returning the eMode label -- `getEModeCategoryCollateralBitmap(categoryId)`, returning the collateral bitmap -- `getEModeCategoryBorrowableBitmap(categoryId)`, returning the borrowable bitmap - -#### Identifying eModes for an asset - -In the previous version of the eModes feature it was possible to query a reserve configuration to receive its unique eMode. -The relevant bits on the reseve configuration have been nullified. - -To identify eModes of a selected asset, there is currently multiple options: - -- onchain one can iterate trough eModes and select the "correct one" based on your application specific needs. - -```sol -for (uint8 i = 1; i < 256; i++) { - DataTypes.CollateralConfig memory cfg = pool.getEModeCategoryCollateralConfig(i); - // check if it is an active eMode - if (cfg.liquidationThreshold != 0) { - // check if it's an eMode you are interested in - EModeConfiguration.isCollateralAsset(pool.getEModeCategoryCollateralBitmap(i), someReserveIndex); - EModeConfiguration.isBorrowableAsset(pool.getEModeCategoryBorrowableBitmap(i), someReserveIndex); - } -} -``` - -- an offchain system could listen to `AssetCollateralInEModeChanged` & `AssetBorrowableInEModeChanged` events and feed the onchain contract with an appropriate categoryId - -### Deprecations - -- `getEModeCategoryData` was deprecated and might be removed in a future version. Use `getEModeCategoryCollateralConfig`, `getEModeCategoryLabel`, `getEModeCategoryCollateralBitmap` & `getEModeCategoryBorrowableBitmap` instead. -- `getReserveDataExtended` was deprecated and might be removed in a future version. Use `getReserveData` & `getLiquidationGracePeriod` instead. diff --git a/docs/3.2/3.1-3.2_PoolConfiguratorDiff.md b/docs/3.2/3.1-3.2_PoolConfiguratorDiff.md new file mode 100644 index 00000000..92cbb252 --- /dev/null +++ b/docs/3.2/3.1-3.2_PoolConfiguratorDiff.md @@ -0,0 +1,1438 @@ +```diff +diff --git a/tmp/PoolConfiguratorInstanceFlattened.sol b/tmp/PoolConfiguratorInstanceFlattened_3.2.sol +index 992b2e4..d9bbd68 100644 +--- a/tmp/PoolConfiguratorInstanceFlattened.sol ++++ b/tmp/PoolConfiguratorInstanceFlattened_3.2.sol +@@ -1,7 +1,7 @@ + // SPDX-License-Identifier: MIT + pragma solidity ^0.8.0 ^0.8.10; + +-// src/core/contracts/dependencies/openzeppelin/contracts/Address.sol ++// src/contracts/dependencies/openzeppelin/contracts/Address.sol + + // OpenZeppelin Contracts v4.4.1 (utils/Address.sol) + +@@ -221,7 +221,7 @@ library Address { + } + } + +-// src/core/contracts/dependencies/openzeppelin/contracts/IERC20.sol ++// src/contracts/dependencies/openzeppelin/contracts/IERC20.sol + + /** + * @dev Interface of the ERC20 standard as defined in the EIP. +@@ -297,7 +297,7 @@ interface IERC20 { + event Approval(address indexed owner, address indexed spender, uint256 value); + } + +-// src/core/contracts/dependencies/openzeppelin/upgradeability/Proxy.sol ++// src/contracts/dependencies/openzeppelin/upgradeability/Proxy.sol + + /** + * @title Proxy +@@ -378,7 +378,7 @@ abstract contract Proxy { + } + } + +-// src/core/contracts/interfaces/IAaveIncentivesController.sol ++// src/contracts/interfaces/IAaveIncentivesController.sol + + /** + * @title IAaveIncentivesController +@@ -397,7 +397,7 @@ interface IAaveIncentivesController { + function handleAction(address user, uint256 totalSupply, uint256 userBalance) external; + } + +-// src/core/contracts/interfaces/IPoolAddressesProvider.sol ++// src/contracts/interfaces/IPoolAddressesProvider.sol + + /** + * @title IPoolAddressesProvider +@@ -624,7 +624,7 @@ interface IPoolAddressesProvider { + function setPoolDataProvider(address newDataProvider) external; + } + +-// src/core/contracts/protocol/libraries/aave-upgradeability/VersionedInitializable.sol ++// src/contracts/misc/aave-upgradeability/VersionedInitializable.sol + + /** + * @title VersionedInitializable +@@ -701,7 +701,7 @@ abstract contract VersionedInitializable { + uint256[50] private ______gap; + } + +-// src/core/contracts/protocol/libraries/helpers/Errors.sol ++// src/contracts/protocol/libraries/helpers/Errors.sol + + /** + * @title Errors library +@@ -739,17 +739,14 @@ library Errors { + string public constant RESERVE_FROZEN = '28'; // 'Action cannot be performed because the reserve is frozen' + string public constant RESERVE_PAUSED = '29'; // 'Action cannot be performed because the reserve is paused' + string public constant BORROWING_NOT_ENABLED = '30'; // 'Borrowing is not enabled' +- string public constant STABLE_BORROWING_NOT_ENABLED = '31'; // 'Stable borrowing is not enabled' + string public constant NOT_ENOUGH_AVAILABLE_USER_BALANCE = '32'; // 'User cannot withdraw more than the available balance' + string public constant INVALID_INTEREST_RATE_MODE_SELECTED = '33'; // 'Invalid interest rate mode selected' + string public constant COLLATERAL_BALANCE_IS_ZERO = '34'; // 'The collateral balance is 0' + string public constant HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD = '35'; // 'Health factor is lesser than the liquidation threshold' + string public constant COLLATERAL_CANNOT_COVER_NEW_BORROW = '36'; // 'There is not enough collateral to cover a new borrow' + string public constant COLLATERAL_SAME_AS_BORROWING_CURRENCY = '37'; // 'Collateral is (mostly) the same currency that is being borrowed' +- string public constant AMOUNT_BIGGER_THAN_MAX_LOAN_SIZE_STABLE = '38'; // 'The requested amount is greater than the max loan size in stable rate mode' + string public constant NO_DEBT_OF_SELECTED_TYPE = '39'; // 'For repayment of a specific type of debt, the user needs to have debt that type' + string public constant NO_EXPLICIT_AMOUNT_TO_REPAY_ON_BEHALF = '40'; // 'To repay on behalf of a user an explicit amount to repay is needed' +- string public constant NO_OUTSTANDING_STABLE_DEBT = '41'; // 'User does not have outstanding stable rate debt on this reserve' + string public constant NO_OUTSTANDING_VARIABLE_DEBT = '42'; // 'User does not have outstanding variable rate debt on this reserve' + string public constant UNDERLYING_BALANCE_ZERO = '43'; // 'The underlying balance needs to be greater than 0' + string public constant INTEREST_RATE_REBALANCE_CONDITIONS_NOT_MET = '44'; // 'Interest rate rebalance conditions were not met' +@@ -762,7 +759,6 @@ library Errors { + string public constant UNBACKED_MINT_CAP_EXCEEDED = '52'; // 'Unbacked mint cap is exceeded' + string public constant DEBT_CEILING_EXCEEDED = '53'; // 'Debt ceiling is exceeded' + string public constant UNDERLYING_CLAIMABLE_RIGHTS_NOT_ZERO = '54'; // 'Claimable rights over underlying not zero (aToken supply or accruedToTreasury)' +- string public constant STABLE_DEBT_NOT_ZERO = '55'; // 'Stable debt supply is not zero' + string public constant VARIABLE_DEBT_SUPPLY_NOT_ZERO = '56'; // 'Variable debt supply is not zero' + string public constant LTV_VALIDATION_FAILED = '57'; // 'Ltv validation failed' + string public constant INCONSISTENT_EMODE_CATEGORY = '58'; // 'Inconsistent eMode category' +@@ -791,11 +787,9 @@ library Errors { + string public constant DEBT_CEILING_NOT_ZERO = '81'; // 'Debt ceiling is not zero' + string public constant ASSET_NOT_LISTED = '82'; // 'Asset is not listed' + string public constant INVALID_OPTIMAL_USAGE_RATIO = '83'; // 'Invalid optimal usage ratio' +- string public constant INVALID_OPTIMAL_STABLE_TO_TOTAL_DEBT_RATIO = '84'; // 'Invalid optimal stable to total debt ratio' + string public constant UNDERLYING_CANNOT_BE_RESCUED = '85'; // 'The underlying asset cannot be rescued' + string public constant ADDRESSES_PROVIDER_ALREADY_ADDED = '86'; // 'Reserve has already been added to reserve list' + string public constant POOL_ADDRESSES_DO_NOT_MATCH = '87'; // 'The token implementation pool address and the pool address provided by the initializing pool do not match' +- string public constant STABLE_BORROWING_ENABLED = '88'; // 'Stable borrowing is enabled' + string public constant SILOED_BORROWING_VIOLATION = '89'; // 'User is trying to borrow multiple assets including a siloed one' + string public constant RESERVE_DEBT_NOT_ZERO = '90'; // the total debt of the reserve needs to be 0 + string public constant FLASHLOAN_DISABLED = '91'; // FlashLoaning for this asset is disabled +@@ -807,9 +801,10 @@ library Errors { + string public constant LIQUIDATION_GRACE_SENTINEL_CHECK_FAILED = '97'; // 'Liquidation grace sentinel validation failed' + string public constant INVALID_GRACE_PERIOD = '98'; // Grace period above a valid range + string public constant INVALID_FREEZE_STATE = '99'; // Reserve is already in the passed freeze state ++ string public constant NOT_BORROWABLE_IN_EMODE = '100'; // Asset not borrowable in eMode + } + +-// src/core/contracts/protocol/libraries/math/PercentageMath.sol ++// src/contracts/protocol/libraries/math/PercentageMath.sol + + /** + * @title PercentageMath library +@@ -870,12 +865,11 @@ library PercentageMath { + } + } + +-// src/core/contracts/protocol/libraries/types/ConfiguratorInputTypes.sol ++// src/contracts/protocol/libraries/types/ConfiguratorInputTypes.sol + + library ConfiguratorInputTypes { + struct InitReserveInput { + address aTokenImpl; +- address stableDebtTokenImpl; + address variableDebtTokenImpl; + bool useVirtualBalance; + address interestRateStrategyAddress; +@@ -886,8 +880,6 @@ library ConfiguratorInputTypes { + string aTokenSymbol; + string variableDebtTokenName; + string variableDebtTokenSymbol; +- string stableDebtTokenName; +- string stableDebtTokenSymbol; + bytes params; + bytes interestRateData; + } +@@ -912,7 +904,7 @@ library ConfiguratorInputTypes { + } + } + +-// src/core/contracts/protocol/libraries/types/DataTypes.sol ++// src/contracts/protocol/libraries/types/DataTypes.sol + + library DataTypes { + /** +@@ -930,7 +922,7 @@ library DataTypes { + uint128 variableBorrowIndex; + //the current variable borrow rate. Expressed in ray + uint128 currentVariableBorrowRate; +- //the current stable borrow rate. Expressed in ray ++ // DEPRECATED on v3.2.0 + uint128 currentStableBorrowRate; + //timestamp of last update + uint40 lastUpdateTimestamp; +@@ -938,7 +930,7 @@ library DataTypes { + uint16 id; + //aToken address + address aTokenAddress; +- //stableDebtToken address ++ // DEPRECATED on v3.2.0 + address stableDebtTokenAddress; + //variableDebtToken address + address variableDebtTokenAddress; +@@ -963,8 +955,8 @@ library DataTypes { + uint128 variableBorrowIndex; + //the current variable borrow rate. Expressed in ray + uint128 currentVariableBorrowRate; +- //the current stable borrow rate. Expressed in ray +- uint128 currentStableBorrowRate; ++ // DEPRECATED on v3.2.0 ++ uint128 __deprecatedStableBorrowRate; + //timestamp of last update + uint40 lastUpdateTimestamp; + //the id of the reserve. Represents the position in the list of the active reserves +@@ -973,8 +965,8 @@ library DataTypes { + uint40 liquidationGracePeriodUntil; + //aToken address + address aTokenAddress; +- //stableDebtToken address +- address stableDebtTokenAddress; ++ // DEPRECATED on v3.2.0 ++ address __deprecatedStableDebtTokenAddress; + //variableDebtToken address + address variableDebtTokenAddress; + //address of the interest rate strategy +@@ -997,7 +989,7 @@ library DataTypes { + //bit 56: reserve is active + //bit 57: reserve is frozen + //bit 58: borrowing is enabled +- //bit 59: stable rate borrowing enabled ++ //bit 59: DEPRECATED: stable rate borrowing enabled + //bit 60: asset is paused + //bit 61: borrowing in isolation mode is enabled + //bit 62: siloed borrowing enabled +@@ -1006,7 +998,7 @@ library DataTypes { + //bit 80-115: borrow cap in whole tokens, borrowCap == 0 => no cap + //bit 116-151: supply cap in whole tokens, supplyCap == 0 => no cap + //bit 152-167: liquidation protocol fee +- //bit 168-175: eMode category ++ //bit 168-175: DEPRECATED: eMode category + //bit 176-211: unbacked mint cap in whole tokens, unbackedMintCap == 0 => minting disabled + //bit 212-251: debt ceiling for isolation mode with (ReserveConfiguration::DEBT_CEILING_DECIMALS) decimals + //bit 252: virtual accounting is enabled for the reserve +@@ -1024,30 +1016,49 @@ library DataTypes { + uint256 data; + } + +- struct EModeCategory { ++ // DEPRECATED: kept for backwards compatibility, might be removed in a future version ++ struct EModeCategoryLegacy { + // each eMode category has a custom ltv and liquidation threshold + uint16 ltv; + uint16 liquidationThreshold; + uint16 liquidationBonus; +- // each eMode category may or may not have a custom oracle to override the individual assets price oracles ++ // DEPRECATED + address priceSource; + string label; + } + ++ struct CollateralConfig { ++ uint16 ltv; ++ uint16 liquidationThreshold; ++ uint16 liquidationBonus; ++ } ++ ++ struct EModeCategoryBaseConfiguration { ++ uint16 ltv; ++ uint16 liquidationThreshold; ++ uint16 liquidationBonus; ++ string label; ++ } ++ ++ struct EModeCategory { ++ // each eMode category has a custom ltv and liquidation threshold ++ uint16 ltv; ++ uint16 liquidationThreshold; ++ uint16 liquidationBonus; ++ uint128 collateralBitmap; ++ string label; ++ uint128 borrowableBitmap; ++ } ++ + enum InterestRateMode { + NONE, +- STABLE, ++ __DEPRECATED, + VARIABLE + } + + struct ReserveCache { + uint256 currScaledVariableDebt; + uint256 nextScaledVariableDebt; +- uint256 currPrincipalStableDebt; +- uint256 currAvgStableBorrowRate; +- uint256 currTotalStableDebt; +- uint256 nextAvgStableBorrowRate; +- uint256 nextTotalStableDebt; + uint256 currLiquidityIndex; + uint256 nextLiquidityIndex; + uint256 currVariableBorrowIndex; +@@ -1057,10 +1068,8 @@ library DataTypes { + uint256 reserveFactor; + ReserveConfigurationMap reserveConfiguration; + address aTokenAddress; +- address stableDebtTokenAddress; + address variableDebtTokenAddress; + uint40 reserveLastUpdateTimestamp; +- uint40 stableDebtLastUpdateTimestamp; + } + + struct ExecuteLiquidationCallParams { +@@ -1090,7 +1099,6 @@ library DataTypes { + InterestRateMode interestRateMode; + uint16 referralCode; + bool releaseUnderlying; +- uint256 maxStableRateBorrowSizePercent; + uint256 reservesCount; + address oracle; + uint8 userEModeCategory; +@@ -1142,7 +1150,6 @@ library DataTypes { + uint16 referralCode; + uint256 flashLoanPremiumToProtocol; + uint256 flashLoanPremiumTotal; +- uint256 maxStableRateBorrowSizePercent; + uint256 reservesCount; + address addressesProvider; + address pool; +@@ -1184,7 +1191,6 @@ library DataTypes { + address userAddress; + uint256 amount; + InterestRateMode interestRateMode; +- uint256 maxStableLoanPercent; + uint256 reservesCount; + address oracle; + uint8 userEModeCategory; +@@ -1205,9 +1211,7 @@ library DataTypes { + uint256 unbacked; + uint256 liquidityAdded; + uint256 liquidityTaken; +- uint256 totalStableDebt; +- uint256 totalVariableDebt; +- uint256 averageStableBorrowRate; ++ uint256 totalDebt; + uint256 reserveFactor; + address reserve; + bool usingVirtualBalance; +@@ -1217,7 +1221,6 @@ library DataTypes { + struct InitReserveParams { + address asset; + address aTokenAddress; +- address stableDebtAddress; + address variableDebtAddress; + address interestRateStrategyAddress; + uint16 reservesCount; +@@ -1225,7 +1228,7 @@ library DataTypes { + } + } + +-// src/core/contracts/dependencies/openzeppelin/contracts/IERC20Detailed.sol ++// src/contracts/dependencies/openzeppelin/contracts/IERC20Detailed.sol + + interface IERC20Detailed is IERC20 { + function name() external view returns (string memory); +@@ -1235,7 +1238,7 @@ interface IERC20Detailed is IERC20 { + function decimals() external view returns (uint8); + } + +-// src/core/contracts/interfaces/IACLManager.sol ++// src/contracts/interfaces/IACLManager.sol + + /** + * @title IACLManager +@@ -1408,7 +1411,7 @@ interface IACLManager { + function isAssetListingAdmin(address admin) external view returns (bool); + } + +-// src/core/contracts/interfaces/IPoolDataProvider.sol ++// src/contracts/interfaces/IPoolDataProvider.sol + + /** + * @title IPoolDataProvider +@@ -1473,13 +1476,6 @@ interface IPoolDataProvider { + bool isFrozen + ); + +- /** +- * @notice Returns the efficiency mode category of the reserve +- * @param asset The address of the underlying asset of the reserve +- * @return The eMode id of the reserve +- */ +- function getReserveEModeCategory(address asset) external view returns (uint256); +- + /** + * @notice Returns the caps parameters of the reserve + * @param asset The address of the underlying asset of the reserve +@@ -1618,7 +1614,7 @@ interface IPoolDataProvider { + * @notice Returns the token addresses of the reserve + * @param asset The address of the underlying asset of the reserve + * @return aTokenAddress The AToken address of the reserve +- * @return stableDebtTokenAddress The StableDebtToken address of the reserve ++ * @return stableDebtTokenAddress DEPRECATED in v3.2.0 + * @return variableDebtTokenAddress The VariableDebtToken address of the reserve + */ + function getReserveTokensAddresses( +@@ -1663,7 +1659,7 @@ interface IPoolDataProvider { + function getVirtualUnderlyingBalance(address asset) external view returns (uint256); + } + +-// src/core/contracts/interfaces/IReserveInterestRateStrategy.sol ++// src/contracts/interfaces/IReserveInterestRateStrategy.sol + + /** + * @title IReserveInterestRateStrategy +@@ -1683,15 +1679,14 @@ interface IReserveInterestRateStrategy { + * @notice Calculates the interest rates depending on the reserve's state and configurations + * @param params The parameters needed to calculate interest rates + * @return liquidityRate The liquidity rate expressed in ray +- * @return stableBorrowRate The stable borrow rate expressed in ray + * @return variableBorrowRate The variable borrow rate expressed in ray + */ + function calculateInterestRates( + DataTypes.CalculateInterestRatesParams memory params +- ) external view returns (uint256, uint256, uint256); ++ ) external view returns (uint256, uint256); + } + +-// src/core/contracts/dependencies/openzeppelin/upgradeability/BaseUpgradeabilityProxy.sol ++// src/contracts/dependencies/openzeppelin/upgradeability/BaseUpgradeabilityProxy.sol + + /** + * @title BaseUpgradeabilityProxy +@@ -1754,7 +1749,7 @@ contract BaseUpgradeabilityProxy is Proxy { + } + } + +-// src/core/contracts/interfaces/IPool.sol ++// src/contracts/interfaces/IPool.sol + + /** + * @title IPool +@@ -1819,7 +1814,7 @@ interface IPool { + * initiator of the transaction on flashLoan() + * @param onBehalfOf The address that will be getting the debt + * @param amount The amount borrowed out +- * @param interestRateMode The rate mode: 1 for Stable, 2 for Variable ++ * @param interestRateMode The rate mode: 2 for Variable, 1 is deprecated (changed on v3.2.0) + * @param borrowRate The numeric rate at which the user has borrowed, expressed in ray + * @param referralCode The referral code used + */ +@@ -1849,18 +1844,6 @@ interface IPool { + bool useATokens + ); + +- /** +- * @dev Emitted on swapBorrowRateMode() +- * @param reserve The address of the underlying asset of the reserve +- * @param user The address of the user swapping his rate mode +- * @param interestRateMode The current interest rate mode of the position being swapped: 1 for Stable, 2 for Variable +- */ +- event SwapBorrowRateMode( +- address indexed reserve, +- address indexed user, +- DataTypes.InterestRateMode interestRateMode +- ); +- + /** + * @dev Emitted on borrow(), repay() and liquidationCall() when using isolated assets + * @param asset The address of the underlying asset of the reserve +@@ -1889,20 +1872,14 @@ interface IPool { + */ + event ReserveUsedAsCollateralDisabled(address indexed reserve, address indexed user); + +- /** +- * @dev Emitted on rebalanceStableBorrowRate() +- * @param reserve The address of the underlying asset of the reserve +- * @param user The address of the user for which the rebalance has been executed +- */ +- event RebalanceStableBorrowRate(address indexed reserve, address indexed user); +- + /** + * @dev Emitted on flashLoan() + * @param target The address of the flash loan receiver contract + * @param initiator The address initiating the flash loan + * @param asset The address of the asset being flash borrowed + * @param amount The amount flash borrowed +- * @param interestRateMode The flashloan mode: 0 for regular flashloan, 1 for Stable debt, 2 for Variable debt ++ * @param interestRateMode The flashloan mode: 0 for regular flashloan, ++ * 1 for Stable (Deprecated on v3.2.0), 2 for Variable + * @param premium The fee flash borrowed + * @param referralCode The referral code used + */ +@@ -1941,7 +1918,7 @@ interface IPool { + * @dev Emitted when the state of a reserve is updated. + * @param reserve The address of the underlying asset of the reserve + * @param liquidityRate The next liquidity rate +- * @param stableBorrowRate The next stable borrow rate ++ * @param stableBorrowRate The next stable borrow rate @note deprecated on v3.2.0 + * @param variableBorrowRate The next variable borrow rate + * @param liquidityIndex The next liquidity index + * @param variableBorrowIndex The next variable borrow index +@@ -2040,13 +2017,12 @@ interface IPool { + + /** + * @notice Allows users to borrow a specific `amount` of the reserve underlying asset, provided that the borrower +- * already supplied enough collateral, or he was given enough allowance by a credit delegator on the +- * corresponding debt token (StableDebtToken or VariableDebtToken) ++ * already supplied enough collateral, or he was given enough allowance by a credit delegator on the VariableDebtToken + * - E.g. User borrows 100 USDC passing as `onBehalfOf` his own address, receiving the 100 USDC in his wallet +- * and 100 stable/variable debt tokens, depending on the `interestRateMode` ++ * and 100 variable debt tokens + * @param asset The address of the underlying asset to borrow + * @param amount The amount to be borrowed +- * @param interestRateMode The interest rate mode at which the user wants to borrow: 1 for Stable, 2 for Variable ++ * @param interestRateMode 2 for Variable, 1 is deprecated on v3.2.0 + * @param referralCode The code used to register the integrator originating the operation, for potential rewards. + * 0 if the action is executed directly by the user, without any middle-man + * @param onBehalfOf The address of the user who will receive the debt. Should be the address of the borrower itself +@@ -2063,11 +2039,11 @@ interface IPool { + + /** + * @notice Repays a borrowed `amount` on a specific reserve, burning the equivalent debt tokens owned +- * - E.g. User repays 100 USDC, burning 100 variable/stable debt tokens of the `onBehalfOf` address ++ * - E.g. User repays 100 USDC, burning 100 variable debt tokens of the `onBehalfOf` address + * @param asset The address of the borrowed underlying asset previously borrowed + * @param amount The amount to repay + * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode` +- * @param interestRateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable ++ * @param interestRateMode 2 for Variable, 1 is deprecated on v3.2.0 + * @param onBehalfOf The address of the user who will get his debt reduced/removed. Should be the address of the + * user calling the function if he wants to reduce/remove his own debt, or the address of any other + * other borrower whose debt should be removed +@@ -2086,7 +2062,7 @@ interface IPool { + * @param asset The address of the borrowed underlying asset previously borrowed + * @param amount The amount to repay + * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode` +- * @param interestRateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable ++ * @param interestRateMode 2 for Variable, 1 is deprecated on v3.2.0 + * @param onBehalfOf Address of the user who will get his debt reduced/removed. Should be the address of the + * user calling the function if he wants to reduce/remove his own debt, or the address of any other + * other borrower whose debt should be removed +@@ -2110,13 +2086,13 @@ interface IPool { + /** + * @notice Repays a borrowed `amount` on a specific reserve using the reserve aTokens, burning the + * equivalent debt tokens +- * - E.g. User repays 100 USDC using 100 aUSDC, burning 100 variable/stable debt tokens ++ * - E.g. User repays 100 USDC using 100 aUSDC, burning 100 variable debt tokens + * @dev Passing uint256.max as amount will clean up any residual aToken dust balance, if the user aToken + * balance is not enough to cover the whole debt + * @param asset The address of the borrowed underlying asset previously borrowed + * @param amount The amount to repay + * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode` +- * @param interestRateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable ++ * @param interestRateMode DEPRECATED in v3.2.0 + * @return The final amount repaid + */ + function repayWithATokens( +@@ -2125,32 +2101,6 @@ interface IPool { + uint256 interestRateMode + ) external returns (uint256); + +- /** +- * @notice Allows a borrower to swap his debt between stable and variable mode, or vice versa +- * @param asset The address of the underlying asset borrowed +- * @param interestRateMode The current interest rate mode of the position being swapped: 1 for Stable, 2 for Variable +- */ +- function swapBorrowRateMode(address asset, uint256 interestRateMode) external; +- +- /** +- * @notice Permissionless method which allows anyone to swap a users stable debt to variable debt +- * @dev Introduced in favor of stable rate deprecation +- * @param asset The address of the underlying asset borrowed +- * @param user The address of the user whose debt will be swapped from stable to variable +- */ +- function swapToVariable(address asset, address user) external; +- +- /** +- * @notice Rebalances the stable interest rate of a user to the current stable rate defined on the reserve. +- * - Users can be rebalanced if the following conditions are satisfied: +- * 1. Usage ratio is above 95% +- * 2. the current supply APY is below REBALANCE_UP_THRESHOLD * maxVariableBorrowRate, which means that too +- * much has been borrowed at a stable rate and suppliers are not earning enough +- * @param asset The address of the underlying asset borrowed +- * @param user The address of the user to be rebalanced +- */ +- function rebalanceStableBorrowRate(address asset, address user) external; +- + /** + * @notice Allows suppliers to enable/disable a specific supplied asset as collateral + * @param asset The address of the underlying asset supplied +@@ -2187,9 +2137,9 @@ interface IPool { + * @param amounts The amounts of the assets being flash-borrowed + * @param interestRateModes Types of the debt to open if the flash loan is not returned: + * 0 -> Don't open any debt, just revert if funds can't be transferred from the receiver +- * 1 -> Open debt at stable rate for the value of the amount flash-borrowed to the `onBehalfOf` address ++ * 1 -> Deprecated on v3.2.0 + * 2 -> Open debt at variable rate for the value of the amount flash-borrowed to the `onBehalfOf` address +- * @param onBehalfOf The address that will receive the debt in the case of using on `modes` 1 or 2 ++ * @param onBehalfOf The address that will receive the debt in the case of using 2 on `modes` + * @param params Variadic packed params to pass to the receiver as extra information + * @param referralCode The code used to register the integrator originating the operation, for potential rewards. + * 0 if the action is executed directly by the user, without any middle-man +@@ -2254,14 +2204,12 @@ interface IPool { + * @dev Only callable by the PoolConfigurator contract + * @param asset The address of the underlying asset of the reserve + * @param aTokenAddress The address of the aToken that will be assigned to the reserve +- * @param stableDebtAddress The address of the StableDebtToken that will be assigned to the reserve + * @param variableDebtAddress The address of the VariableDebtToken that will be assigned to the reserve + * @param interestRateStrategyAddress The address of the interest rate strategy contract + */ + function initReserve( + address asset, + address aTokenAddress, +- address stableDebtAddress, + address variableDebtAddress, + address interestRateStrategyAddress + ) external; +@@ -2269,6 +2217,7 @@ interface IPool { + /** + * @notice Drop a reserve + * @dev Only callable by the PoolConfigurator contract ++ * @dev Does not reset eMode flags, which must be considered when reusing the same reserve id for a different reserve. + * @param asset The address of the underlying asset of the reserve + */ + function dropReserve(address asset) external; +@@ -2359,6 +2308,7 @@ interface IPool { + + /** + * @notice Returns the state and configuration of the reserve, including extra data included with Aave v3.1 ++ * @dev DEPRECATED use independent getters instead (getReserveData, getLiquidationGracePeriod) + * @param asset The address of the underlying asset of the reserve + * @return The state and configuration data of the reserve with virtual accounting + */ +@@ -2441,20 +2391,70 @@ interface IPool { + ) external; + + /** +- * @notice Configures a new category for the eMode. ++ * @notice Configures a new or alters an existing collateral configuration of an eMode. + * @dev In eMode, the protocol allows very high borrowing power to borrow assets of the same category. + * The category 0 is reserved as it's the default for volatile assets + * @param id The id of the category + * @param config The configuration of the category + */ +- function configureEModeCategory(uint8 id, DataTypes.EModeCategory memory config) external; ++ function configureEModeCategory( ++ uint8 id, ++ DataTypes.EModeCategoryBaseConfiguration memory config ++ ) external; ++ ++ /** ++ * @notice Replaces the current eMode collateralBitmap. ++ * @param id The id of the category ++ * @param collateralBitmap The collateralBitmap of the category ++ */ ++ function configureEModeCategoryCollateralBitmap(uint8 id, uint128 collateralBitmap) external; ++ ++ /** ++ * @notice Replaces the current eMode borrowableBitmap. ++ * @param id The id of the category ++ * @param borrowableBitmap The borrowableBitmap of the category ++ */ ++ function configureEModeCategoryBorrowableBitmap(uint8 id, uint128 borrowableBitmap) external; + + /** + * @notice Returns the data of an eMode category ++ * @dev DEPRECATED use independent getters instead + * @param id The id of the category + * @return The configuration data of the category + */ +- function getEModeCategoryData(uint8 id) external view returns (DataTypes.EModeCategory memory); ++ function getEModeCategoryData( ++ uint8 id ++ ) external view returns (DataTypes.EModeCategoryLegacy memory); ++ ++ /** ++ * @notice Returns the label of an eMode category ++ * @param id The id of the category ++ * @return The label of the category ++ */ ++ function getEModeCategoryLabel(uint8 id) external view returns (string memory); ++ ++ /** ++ * @notice Returns the collateral config of an eMode category ++ * @param id The id of the category ++ * @return The ltv,lt,lb of the category ++ */ ++ function getEModeCategoryCollateralConfig( ++ uint8 id ++ ) external view returns (DataTypes.CollateralConfig memory); ++ ++ /** ++ * @notice Returns the collateralBitmap of an eMode category ++ * @param id The id of the category ++ * @return The collateralBitmap of the category ++ */ ++ function getEModeCategoryCollateralBitmap(uint8 id) external view returns (uint128); ++ ++ /** ++ * @notice Returns the borrowableBitmap of an eMode category ++ * @param id The id of the category ++ * @return The borrowableBitmap of the category ++ */ ++ function getEModeCategoryBorrowableBitmap(uint8 id) external view returns (uint128); + + /** + * @notice Allows a user to use the protocol in eMode +@@ -2492,12 +2492,6 @@ interface IPool { + **/ + function getLiquidationGracePeriod(address asset) external returns (uint40); + +- /** +- * @notice Returns the percentage of available liquidity that can be borrowed at once at stable rate +- * @return The percentage of available liquidity to borrow, expressed in bps +- */ +- function MAX_STABLE_RATE_BORROW_SIZE_PERCENT() external view returns (uint256); +- + /** + * @notice Returns the total fee on flash loans + * @return The total fee on flashloans +@@ -2586,7 +2580,7 @@ interface IPool { + function getSupplyLogic() external view returns (address); + } + +-// src/core/contracts/protocol/libraries/configuration/ReserveConfiguration.sol ++// src/contracts/protocol/libraries/configuration/ReserveConfiguration.sol + + /** + * @title ReserveConfiguration library +@@ -2601,7 +2595,7 @@ library ReserveConfiguration { + uint256 internal constant ACTIVE_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFF; // prettier-ignore + uint256 internal constant FROZEN_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFFFFFFFFFFFFFF; // prettier-ignore + uint256 internal constant BORROWING_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFFFFFFFFFFFF; // prettier-ignore +- uint256 internal constant STABLE_BORROWING_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFFFFF; // prettier-ignore ++ // @notice there is an unoccupied hole of 1 bit at position 59 from pre 3.2 stableBorrowRateEnabled + uint256 internal constant PAUSED_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFF; // prettier-ignore + uint256 internal constant BORROWABLE_IN_ISOLATION_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFFFFFFFFFFFFFFF; // prettier-ignore + uint256 internal constant SILOED_BORROWING_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFFFFFFFFFFFFF; // prettier-ignore +@@ -2610,7 +2604,7 @@ library ReserveConfiguration { + uint256 internal constant BORROW_CAP_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000FFFFFFFFFFFFFFFFFFFF; // prettier-ignore + uint256 internal constant SUPPLY_CAP_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFF000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // prettier-ignore + uint256 internal constant LIQUIDATION_PROTOCOL_FEE_MASK = 0xFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // prettier-ignore +- uint256 internal constant EMODE_CATEGORY_MASK = 0xFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // prettier-ignore ++ // @notice there is an unoccupied hole of 8 bits from 168 to 176 left from pre 3.2 eModeCategory + uint256 internal constant UNBACKED_MINT_CAP_MASK = 0xFFFFFFFFFFF000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // prettier-ignore + uint256 internal constant DEBT_CEILING_MASK = 0xF0000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // prettier-ignore + uint256 internal constant VIRTUAL_ACC_ACTIVE_MASK = 0xEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // prettier-ignore +@@ -2622,7 +2616,6 @@ library ReserveConfiguration { + uint256 internal constant IS_ACTIVE_START_BIT_POSITION = 56; + uint256 internal constant IS_FROZEN_START_BIT_POSITION = 57; + uint256 internal constant BORROWING_ENABLED_START_BIT_POSITION = 58; +- uint256 internal constant STABLE_BORROWING_ENABLED_START_BIT_POSITION = 59; + uint256 internal constant IS_PAUSED_START_BIT_POSITION = 60; + uint256 internal constant BORROWABLE_IN_ISOLATION_START_BIT_POSITION = 61; + uint256 internal constant SILOED_BORROWING_START_BIT_POSITION = 62; +@@ -2631,7 +2624,7 @@ library ReserveConfiguration { + uint256 internal constant BORROW_CAP_START_BIT_POSITION = 80; + uint256 internal constant SUPPLY_CAP_START_BIT_POSITION = 116; + uint256 internal constant LIQUIDATION_PROTOCOL_FEE_START_BIT_POSITION = 152; +- uint256 internal constant EMODE_CATEGORY_START_BIT_POSITION = 168; ++ //@notice there is an unoccupied hole of 8 bits from 168 to 176 left from pre 3.2 eModeCategory + uint256 internal constant UNBACKED_MINT_CAP_START_BIT_POSITION = 176; + uint256 internal constant DEBT_CEILING_START_BIT_POSITION = 212; + uint256 internal constant VIRTUAL_ACC_START_BIT_POSITION = 252; +@@ -2644,7 +2637,6 @@ library ReserveConfiguration { + uint256 internal constant MAX_VALID_BORROW_CAP = 68719476735; + uint256 internal constant MAX_VALID_SUPPLY_CAP = 68719476735; + uint256 internal constant MAX_VALID_LIQUIDATION_PROTOCOL_FEE = 65535; +- uint256 internal constant MAX_VALID_EMODE_CATEGORY = 255; + uint256 internal constant MAX_VALID_UNBACKED_MINT_CAP = 68719476735; + uint256 internal constant MAX_VALID_DEBT_CEILING = 1099511627775; + +@@ -2895,31 +2887,6 @@ library ReserveConfiguration { + return (self.data & ~BORROWING_MASK) != 0; + } + +- /** +- * @notice Enables or disables stable rate borrowing on the reserve +- * @param self The reserve configuration +- * @param enabled True if the stable rate borrowing needs to be enabled, false otherwise +- */ +- function setStableRateBorrowingEnabled( +- DataTypes.ReserveConfigurationMap memory self, +- bool enabled +- ) internal pure { +- self.data = +- (self.data & STABLE_BORROWING_MASK) | +- (uint256(enabled ? 1 : 0) << STABLE_BORROWING_ENABLED_START_BIT_POSITION); +- } +- +- /** +- * @notice Gets the stable rate borrowing state of the reserve +- * @param self The reserve configuration +- * @return The stable rate borrowing state +- */ +- function getStableRateBorrowingEnabled( +- DataTypes.ReserveConfigurationMap memory self +- ) internal pure returns (bool) { +- return (self.data & ~STABLE_BORROWING_MASK) != 0; +- } +- + /** + * @notice Sets the reserve factor of the reserve + * @param self The reserve configuration +@@ -3080,31 +3047,6 @@ library ReserveConfiguration { + return (self.data & ~UNBACKED_MINT_CAP_MASK) >> UNBACKED_MINT_CAP_START_BIT_POSITION; + } + +- /** +- * @notice Sets the eMode asset category +- * @param self The reserve configuration +- * @param category The asset category when the user selects the eMode +- */ +- function setEModeCategory( +- DataTypes.ReserveConfigurationMap memory self, +- uint256 category +- ) internal pure { +- require(category <= MAX_VALID_EMODE_CATEGORY, Errors.INVALID_EMODE_CATEGORY); +- +- self.data = (self.data & EMODE_CATEGORY_MASK) | (category << EMODE_CATEGORY_START_BIT_POSITION); +- } +- +- /** +- * @dev Gets the eMode asset category +- * @param self The reserve configuration +- * @return The eMode category for the asset +- */ +- function getEModeCategory( +- DataTypes.ReserveConfigurationMap memory self +- ) internal pure returns (uint256) { +- return (self.data & ~EMODE_CATEGORY_MASK) >> EMODE_CATEGORY_START_BIT_POSITION; +- } +- + /** + * @notice Sets the flashloanable flag for the reserve + * @param self The reserve configuration +@@ -3163,19 +3105,17 @@ library ReserveConfiguration { + * @return The state flag representing active + * @return The state flag representing frozen + * @return The state flag representing borrowing enabled +- * @return The state flag representing stableRateBorrowing enabled + * @return The state flag representing paused + */ + function getFlags( + DataTypes.ReserveConfigurationMap memory self +- ) internal pure returns (bool, bool, bool, bool, bool) { ++ ) internal pure returns (bool, bool, bool, bool) { + uint256 dataLocal = self.data; + + return ( + (dataLocal & ~ACTIVE_MASK) != 0, + (dataLocal & ~FROZEN_MASK) != 0, + (dataLocal & ~BORROWING_MASK) != 0, +- (dataLocal & ~STABLE_BORROWING_MASK) != 0, + (dataLocal & ~PAUSED_MASK) != 0 + ); + } +@@ -3188,11 +3128,10 @@ library ReserveConfiguration { + * @return The state param representing liquidation bonus + * @return The state param representing reserve decimals + * @return The state param representing reserve factor +- * @return The state param representing eMode category + */ + function getParams( + DataTypes.ReserveConfigurationMap memory self +- ) internal pure returns (uint256, uint256, uint256, uint256, uint256, uint256) { ++ ) internal pure returns (uint256, uint256, uint256, uint256, uint256) { + uint256 dataLocal = self.data; + + return ( +@@ -3200,8 +3139,7 @@ library ReserveConfiguration { + (dataLocal & ~LIQUIDATION_THRESHOLD_MASK) >> LIQUIDATION_THRESHOLD_START_BIT_POSITION, + (dataLocal & ~LIQUIDATION_BONUS_MASK) >> LIQUIDATION_BONUS_START_BIT_POSITION, + (dataLocal & ~DECIMALS_MASK) >> RESERVE_DECIMALS_START_BIT_POSITION, +- (dataLocal & ~RESERVE_FACTOR_MASK) >> RESERVE_FACTOR_START_BIT_POSITION, +- (dataLocal & ~EMODE_CATEGORY_MASK) >> EMODE_CATEGORY_START_BIT_POSITION ++ (dataLocal & ~RESERVE_FACTOR_MASK) >> RESERVE_FACTOR_START_BIT_POSITION + ); + } + +@@ -3223,7 +3161,7 @@ library ReserveConfiguration { + } + } + +-// src/core/contracts/dependencies/openzeppelin/upgradeability/InitializableUpgradeabilityProxy.sol ++// src/contracts/dependencies/openzeppelin/upgradeability/InitializableUpgradeabilityProxy.sol + + /** + * @title InitializableUpgradeabilityProxy +@@ -3250,7 +3188,7 @@ contract InitializableUpgradeabilityProxy is BaseUpgradeabilityProxy { + } + } + +-// src/core/contracts/interfaces/IDefaultInterestRateStrategyV2.sol ++// src/contracts/interfaces/IDefaultInterestRateStrategyV2.sol + + /** + * @title IDefaultInterestRateStrategyV2 +@@ -3258,16 +3196,6 @@ contract InitializableUpgradeabilityProxy is BaseUpgradeabilityProxy { + * @notice Interface of the default interest rate strategy used by the Aave protocol + */ + interface IDefaultInterestRateStrategyV2 is IReserveInterestRateStrategy { +- struct CalcInterestRatesLocalVars { +- uint256 availableLiquidity; +- uint256 totalDebt; +- uint256 currentVariableBorrowRate; +- uint256 currentLiquidityRate; +- uint256 borrowUsageRatio; +- uint256 supplyUsageRatio; +- uint256 availableLiquidityPlusDebt; +- } +- + /** + * @notice Holds the interest rate data for a given reserve + * +@@ -3418,7 +3346,7 @@ interface IDefaultInterestRateStrategyV2 is IReserveInterestRateStrategy { + function setInterestRateParams(address reserve, InterestRateData calldata rateData) external; + } + +-// src/core/contracts/protocol/libraries/aave-upgradeability/BaseImmutableAdminUpgradeabilityProxy.sol ++// src/contracts/misc/aave-upgradeability/BaseImmutableAdminUpgradeabilityProxy.sol + + /** + * @title BaseImmutableAdminUpgradeabilityProxy +@@ -3501,7 +3429,56 @@ contract BaseImmutableAdminUpgradeabilityProxy is BaseUpgradeabilityProxy { + } + } + +-// src/core/contracts/interfaces/IInitializableAToken.sol ++// src/contracts/protocol/libraries/configuration/EModeConfiguration.sol ++ ++/** ++ * @title EModeConfiguration library ++ * @author BGD Labs ++ * @notice Implements the bitmap logic to handle the eMode configuration ++ */ ++library EModeConfiguration { ++ /** ++ * @notice Sets a bit in a given bitmap that represents the reserve index range ++ * @dev The supplied bitmap is supposed to be a uint128 in which each bit represents a reserve ++ * @param bitmap The bitmap ++ * @param reserveIndex The index of the reserve in the bitmap ++ * @param enabled True if the reserveIndex should be enabled on the bitmap, false otherwise ++ * @return The altered bitmap ++ */ ++ function setReserveBitmapBit( ++ uint128 bitmap, ++ uint256 reserveIndex, ++ bool enabled ++ ) internal pure returns (uint128) { ++ unchecked { ++ require(reserveIndex < ReserveConfiguration.MAX_RESERVES_COUNT, Errors.INVALID_RESERVE_INDEX); ++ uint128 bit = uint128(1 << reserveIndex); ++ if (enabled) { ++ return bitmap | bit; ++ } else { ++ return bitmap & ~bit; ++ } ++ } ++ } ++ ++ /** ++ * @notice Validates if a reserveIndex is flagged as enabled on a given bitmap ++ * @param bitmap The bitmap ++ * @param reserveIndex The index of the reserve in the bitmap ++ * @return True if the reserveindex is flagged true ++ */ ++ function isReserveEnabledOnBitmap( ++ uint128 bitmap, ++ uint256 reserveIndex ++ ) internal pure returns (bool) { ++ unchecked { ++ require(reserveIndex < ReserveConfiguration.MAX_RESERVES_COUNT, Errors.INVALID_RESERVE_INDEX); ++ return (bitmap >> reserveIndex) & 1 != 0; ++ } ++ } ++} ++ ++// src/contracts/interfaces/IInitializableAToken.sol + + /** + * @title IInitializableAToken +@@ -3554,7 +3531,7 @@ interface IInitializableAToken { + ) external; + } + +-// src/core/contracts/interfaces/IInitializableDebtToken.sol ++// src/contracts/interfaces/IInitializableDebtToken.sol + + /** + * @title IInitializableDebtToken +@@ -3603,7 +3580,7 @@ interface IInitializableDebtToken { + ) external; + } + +-// src/core/contracts/interfaces/IPoolConfigurator.sol ++// src/contracts/interfaces/IPoolConfigurator.sol + + /** + * @title IPoolConfigurator +@@ -3615,7 +3592,7 @@ interface IPoolConfigurator { + * @dev Emitted when a reserve is initialized. + * @param asset The address of the underlying asset of the reserve + * @param aToken The address of the associated aToken contract +- * @param stableDebtToken The address of the associated stable rate debt token ++ * @param stableDebtToken, DEPRECATED in v3.2.0 + * @param variableDebtToken The address of the associated variable rate debt token + * @param interestRateStrategyAddress The address of the interest rate strategy for the reserve + */ +@@ -3662,13 +3639,6 @@ interface IPoolConfigurator { + uint256 liquidationBonus + ); + +- /** +- * @dev Emitted when stable rate borrowing is enabled or disabled on a reserve +- * @param asset The address of the underlying asset of the reserve +- * @param enabled True if stable rate borrowing is enabled, false otherwise +- */ +- event ReserveStableRateBorrowing(address indexed asset, bool enabled); +- + /** + * @dev Emitted when a reserve is activated or deactivated + * @param asset The address of the underlying asset of the reserve +@@ -3758,20 +3728,28 @@ interface IPoolConfigurator { + ); + + /** +- * @dev Emitted when the category of an asset in eMode is changed. ++ * @dev Emitted when an collateral configuration of an asset in an eMode is changed. ++ * @param asset The address of the underlying asset of the reserve ++ * @param categoryId The eMode category ++ * @param collateral True if the asset is enabled as collateral in the eMode, false otherwise. ++ */ ++ event AssetCollateralInEModeChanged(address indexed asset, uint8 categoryId, bool collateral); ++ ++ /** ++ * @dev Emitted when the borrowable configuration of an asset in an eMode changed. + * @param asset The address of the underlying asset of the reserve +- * @param oldCategoryId The old eMode asset category +- * @param newCategoryId The new eMode asset category ++ * @param categoryId The eMode category ++ * @param borrowable True if the asset is enabled as borrowable in the eMode, false otherwise. + */ +- event EModeAssetCategoryChanged(address indexed asset, uint8 oldCategoryId, uint8 newCategoryId); ++ event AssetBorrowableInEModeChanged(address indexed asset, uint8 categoryId, bool borrowable); + + /** +- * @dev Emitted when a new eMode category is added. ++ * @dev Emitted when a new eMode category is added or an existing category is altered. + * @param categoryId The new eMode category id + * @param ltv The ltv for the asset category in eMode + * @param liquidationThreshold The liquidationThreshold for the asset category in eMode + * @param liquidationBonus The liquidationBonus for the asset category in eMode +- * @param oracle The optional address of the price oracle specific for this category ++ * @param oracle DEPRECATED in v3.2.0 + * @param label A human readable identifier for the category + */ + event EModeCategoryAdded( +@@ -3814,18 +3792,6 @@ interface IPoolConfigurator { + address indexed implementation + ); + +- /** +- * @dev Emitted when the implementation of a stable debt token is upgraded. +- * @param asset The address of the underlying asset of the reserve +- * @param proxy The stable debt token proxy address +- * @param implementation The new aToken implementation +- */ +- event StableDebtTokenUpgraded( +- address indexed asset, +- address indexed proxy, +- address indexed implementation +- ); +- + /** + * @dev Emitted when the implementation of a variable debt token is upgraded. + * @param asset The address of the underlying asset of the reserve +@@ -3902,14 +3868,6 @@ interface IPoolConfigurator { + */ + function updateAToken(ConfiguratorInputTypes.UpdateATokenInput calldata input) external; + +- /** +- * @notice Updates the stable debt token implementation for the reserve. +- * @param input The stableDebtToken update parameters +- */ +- function updateStableDebtToken( +- ConfiguratorInputTypes.UpdateDebtTokenInput calldata input +- ) external; +- + /** + * @notice Updates the variable debt token implementation for the asset. + * @param input The variableDebtToken update parameters +@@ -3920,7 +3878,6 @@ interface IPoolConfigurator { + + /** + * @notice Configures borrowing on a reserve. +- * @dev Can only be disabled (set to false) if stable borrowing is disabled + * @param asset The address of the underlying asset of the reserve + * @param enabled True if borrowing needs to be enabled, false otherwise + */ +@@ -3942,14 +3899,6 @@ interface IPoolConfigurator { + uint256 liquidationBonus + ) external; + +- /** +- * @notice Enable or disable stable rate borrowing on a reserve. +- * @dev Can only be enabled (set to true) if borrowing is enabled +- * @param asset The address of the underlying asset of the reserve +- * @param enabled True if stable rate borrowing needs to be enabled, false otherwise +- */ +- function setReserveStableRateBorrowing(address asset, bool enabled) external; +- + /** + * @notice Enable or disable flashloans on a reserve + * @param asset The address of the underlying asset of the reserve +@@ -4087,23 +4036,28 @@ interface IPoolConfigurator { + function setUnbackedMintCap(address asset, uint256 newUnbackedMintCap) external; + + /** +- * @notice Assign an efficiency mode (eMode) category to asset. ++ * @notice Enables/disables an asset to be borrowable in a selected eMode. ++ * - eMode.borrowable always has less priority then reserve.borrowable ++ * @param asset The address of the underlying asset of the reserve ++ * @param categoryId The eMode categoryId ++ * @param borrowable True if the asset should be borrowable in the given eMode category, false otherwise. ++ */ ++ function setAssetBorrowableInEMode(address asset, uint8 categoryId, bool borrowable) external; ++ ++ /** ++ * @notice Enables/disables an asset to be collateral in a selected eMode. + * @param asset The address of the underlying asset of the reserve +- * @param newCategoryId The new category id of the asset ++ * @param categoryId The eMode categoryId ++ * @param collateral True if the asset should be collateral in the given eMode category, false otherwise. + */ +- function setAssetEModeCategory(address asset, uint8 newCategoryId) external; ++ function setAssetCollateralInEMode(address asset, uint8 categoryId, bool collateral) external; + + /** +- * @notice Adds a new efficiency mode (eMode) category. +- * @dev If zero is provided as oracle address, the default asset oracles will be used to compute the overall debt and +- * overcollateralization of the users using this category. +- * @dev The new ltv and liquidation threshold must be greater than the base +- * ltvs and liquidation thresholds of all assets within the eMode category ++ * @notice Adds a new efficiency mode (eMode) category or alters a existing one. + * @param categoryId The id of the category to be configured + * @param ltv The ltv associated with the category + * @param liquidationThreshold The liquidation threshold associated with the category + * @param liquidationBonus The liquidation bonus associated with the category +- * @param oracle The oracle associated with the category + * @param label A label identifying the category + */ + function setEModeCategory( +@@ -4111,7 +4065,6 @@ interface IPoolConfigurator { + uint16 ltv, + uint16 liquidationThreshold, + uint16 liquidationBonus, +- address oracle, + string calldata label + ) external; + +@@ -4175,7 +4128,7 @@ interface IPoolConfigurator { + function MAX_GRACE_PERIOD() external view returns (uint40); + } + +-// src/core/contracts/protocol/libraries/aave-upgradeability/InitializableImmutableAdminUpgradeabilityProxy.sol ++// src/contracts/misc/aave-upgradeability/InitializableImmutableAdminUpgradeabilityProxy.sol + + /** + * @title InitializableAdminUpgradeabilityProxy +@@ -4200,7 +4153,7 @@ contract InitializableImmutableAdminUpgradeabilityProxy is + } + } + +-// src/core/contracts/protocol/libraries/logic/ConfiguratorLogic.sol ++// src/contracts/protocol/libraries/logic/ConfiguratorLogic.sol + + /** + * @title ConfiguratorLogic library +@@ -4223,11 +4176,6 @@ library ConfiguratorLogic { + address indexed proxy, + address indexed implementation + ); +- event StableDebtTokenUpgraded( +- address indexed asset, +- address indexed proxy, +- address indexed implementation +- ); + event VariableDebtTokenUpgraded( + address indexed asset, + address indexed proxy, +@@ -4235,7 +4183,7 @@ library ConfiguratorLogic { + ); + + /** +- * @notice Initialize a reserve by creating and initializing aToken, stable debt token and variable debt token ++ * @notice Initialize a reserve by creating and initializing aToken and variable debt token + * @dev Emits the `ReserveInitialized` event + * @param pool The Pool in which the reserve will be initialized + * @param input The needed parameters for the initialization +@@ -4263,20 +4211,6 @@ library ConfiguratorLogic { + ) + ); + +- address stableDebtTokenProxyAddress = _initTokenWithProxy( +- input.stableDebtTokenImpl, +- abi.encodeWithSelector( +- IInitializableDebtToken.initialize.selector, +- pool, +- input.underlyingAsset, +- input.incentivesController, +- underlyingAssetDecimals, +- input.stableDebtTokenName, +- input.stableDebtTokenSymbol, +- input.params +- ) +- ); +- + address variableDebtTokenProxyAddress = _initTokenWithProxy( + input.variableDebtTokenImpl, + abi.encodeWithSelector( +@@ -4294,7 +4228,6 @@ library ConfiguratorLogic { + pool.initReserve( + input.underlyingAsset, + aTokenProxyAddress, +- stableDebtTokenProxyAddress, + variableDebtTokenProxyAddress, + input.interestRateStrategyAddress + ); +@@ -4318,7 +4251,7 @@ library ConfiguratorLogic { + emit ReserveInitialized( + input.underlyingAsset, + aTokenProxyAddress, +- stableDebtTokenProxyAddress, ++ address(0), + variableDebtTokenProxyAddress, + input.interestRateStrategyAddress + ); +@@ -4336,7 +4269,7 @@ library ConfiguratorLogic { + ) external { + DataTypes.ReserveDataLegacy memory reserveData = cachedPool.getReserveData(input.asset); + +- (, , , uint256 decimals, , ) = cachedPool.getConfiguration(input.asset).getParams(); ++ (, , , uint256 decimals, ) = cachedPool.getConfiguration(input.asset).getParams(); + + bytes memory encodedCall = abi.encodeWithSelector( + IInitializableAToken.initialize.selector, +@@ -4355,44 +4288,6 @@ library ConfiguratorLogic { + emit ATokenUpgraded(input.asset, reserveData.aTokenAddress, input.implementation); + } + +- /** +- * @notice Updates the stable debt token implementation and initializes it +- * @dev Emits the `StableDebtTokenUpgraded` event +- * @param cachedPool The Pool containing the reserve with the stable debt token +- * @param input The parameters needed for the initialize call +- */ +- function executeUpdateStableDebtToken( +- IPool cachedPool, +- ConfiguratorInputTypes.UpdateDebtTokenInput calldata input +- ) external { +- DataTypes.ReserveDataLegacy memory reserveData = cachedPool.getReserveData(input.asset); +- +- (, , , uint256 decimals, , ) = cachedPool.getConfiguration(input.asset).getParams(); +- +- bytes memory encodedCall = abi.encodeWithSelector( +- IInitializableDebtToken.initialize.selector, +- cachedPool, +- input.asset, +- input.incentivesController, +- decimals, +- input.name, +- input.symbol, +- input.params +- ); +- +- _upgradeTokenImplementation( +- reserveData.stableDebtTokenAddress, +- input.implementation, +- encodedCall +- ); +- +- emit StableDebtTokenUpgraded( +- input.asset, +- reserveData.stableDebtTokenAddress, +- input.implementation +- ); +- } +- + /** + * @notice Updates the variable debt token implementation and initializes it + * @dev Emits the `VariableDebtTokenUpgraded` event +@@ -4405,7 +4300,7 @@ library ConfiguratorLogic { + ) external { + DataTypes.ReserveDataLegacy memory reserveData = cachedPool.getReserveData(input.asset); + +- (, , , uint256 decimals, , ) = cachedPool.getConfiguration(input.asset).getParams(); ++ (, , , uint256 decimals, ) = cachedPool.getConfiguration(input.asset).getParams(); + + bytes memory encodedCall = abi.encodeWithSelector( + IInitializableDebtToken.initialize.selector, +@@ -4470,7 +4365,7 @@ library ConfiguratorLogic { + } + } + +-// src/core/contracts/protocol/pool/PoolConfigurator.sol ++// src/contracts/protocol/pool/PoolConfigurator.sol + + /** + * @title PoolConfigurator +@@ -4559,13 +4454,6 @@ abstract contract PoolConfigurator is VersionedInitializable, IPoolConfigurator + ConfiguratorLogic.executeUpdateAToken(_pool, input); + } + +- /// @inheritdoc IPoolConfigurator +- function updateStableDebtToken( +- ConfiguratorInputTypes.UpdateDebtTokenInput calldata input +- ) external override onlyPoolAdmin { +- ConfiguratorLogic.executeUpdateStableDebtToken(_pool, input); +- } +- + /// @inheritdoc IPoolConfigurator + function updateVariableDebtToken( + ConfiguratorInputTypes.UpdateDebtTokenInput calldata input +@@ -4576,9 +4464,6 @@ abstract contract PoolConfigurator is VersionedInitializable, IPoolConfigurator + /// @inheritdoc IPoolConfigurator + function setReserveBorrowing(address asset, bool enabled) external override onlyRiskOrPoolAdmins { + DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); +- if (!enabled) { +- require(!currentConfig.getStableRateBorrowingEnabled(), Errors.STABLE_BORROWING_ENABLED); +- } + currentConfig.setBorrowingEnabled(enabled); + _pool.setConfiguration(asset, currentConfig); + emit ReserveBorrowing(asset, enabled); +@@ -4636,20 +4521,6 @@ abstract contract PoolConfigurator is VersionedInitializable, IPoolConfigurator + emit CollateralConfigurationChanged(asset, newLtv, liquidationThreshold, liquidationBonus); + } + +- /// @inheritdoc IPoolConfigurator +- function setReserveStableRateBorrowing( +- address asset, +- bool enabled +- ) external override onlyRiskOrPoolAdmins { +- DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); +- if (enabled) { +- require(currentConfig.getBorrowingEnabled(), Errors.BORROWING_NOT_ENABLED); +- } +- currentConfig.setStableRateBorrowingEnabled(enabled); +- _pool.setConfiguration(asset, currentConfig); +- emit ReserveStableRateBorrowing(asset, enabled); +- } +- + /// @inheritdoc IPoolConfigurator + function setReserveFlashLoaning( + address asset, +@@ -4852,7 +4723,6 @@ abstract contract PoolConfigurator is VersionedInitializable, IPoolConfigurator + uint16 ltv, + uint16 liquidationThreshold, + uint16 liquidationBonus, +- address oracle, + string calldata label + ) external override onlyRiskOrPoolAdmins { + require(ltv != 0, Errors.INVALID_EMODE_CATEGORY_PARAMS); +@@ -4875,53 +4745,57 @@ abstract contract PoolConfigurator is VersionedInitializable, IPoolConfigurator + Errors.INVALID_EMODE_CATEGORY_PARAMS + ); + +- address[] memory reserves = _pool.getReservesList(); +- for (uint256 i = 0; i < reserves.length; i++) { +- DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(reserves[i]); +- if (categoryId == currentConfig.getEModeCategory()) { +- uint256 currentLtv = currentConfig.getFrozen() +- ? _pendingLtv[reserves[i]] +- : currentConfig.getLtv(); +- require(ltv > currentLtv, Errors.INVALID_EMODE_CATEGORY_PARAMS); +- +- require( +- liquidationThreshold > currentConfig.getLiquidationThreshold(), +- Errors.INVALID_EMODE_CATEGORY_PARAMS +- ); +- } +- } ++ DataTypes.EModeCategoryBaseConfiguration memory categoryData; ++ categoryData.ltv = ltv; ++ categoryData.liquidationThreshold = liquidationThreshold; ++ categoryData.liquidationBonus = liquidationBonus; ++ categoryData.label = label; + +- _pool.configureEModeCategory( ++ _pool.configureEModeCategory(categoryId, categoryData); ++ emit EModeCategoryAdded( + categoryId, +- DataTypes.EModeCategory({ +- ltv: ltv, +- liquidationThreshold: liquidationThreshold, +- liquidationBonus: liquidationBonus, +- priceSource: oracle, +- label: label +- }) ++ ltv, ++ liquidationThreshold, ++ liquidationBonus, ++ address(0), ++ label + ); +- emit EModeCategoryAdded(categoryId, ltv, liquidationThreshold, liquidationBonus, oracle, label); + } + + /// @inheritdoc IPoolConfigurator +- function setAssetEModeCategory( ++ function setAssetCollateralInEMode( + address asset, +- uint8 newCategoryId ++ uint8 categoryId, ++ bool allowed + ) external override onlyRiskOrPoolAdmins { +- DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); ++ uint128 collateralBitmap = _pool.getEModeCategoryCollateralBitmap(categoryId); ++ DataTypes.ReserveDataLegacy memory reserveData = _pool.getReserveData(asset); ++ require(reserveData.id != 0 || _pool.getReservesList()[0] == asset, Errors.ASSET_NOT_LISTED); ++ collateralBitmap = EModeConfiguration.setReserveBitmapBit( ++ collateralBitmap, ++ reserveData.id, ++ allowed ++ ); ++ _pool.configureEModeCategoryCollateralBitmap(categoryId, collateralBitmap); ++ emit AssetCollateralInEModeChanged(asset, categoryId, allowed); ++ } + +- if (newCategoryId != 0) { +- DataTypes.EModeCategory memory categoryData = _pool.getEModeCategoryData(newCategoryId); +- require( +- categoryData.liquidationThreshold > currentConfig.getLiquidationThreshold(), +- Errors.INVALID_EMODE_CATEGORY_ASSIGNMENT +- ); +- } +- uint256 oldCategoryId = currentConfig.getEModeCategory(); +- currentConfig.setEModeCategory(newCategoryId); +- _pool.setConfiguration(asset, currentConfig); +- emit EModeAssetCategoryChanged(asset, uint8(oldCategoryId), newCategoryId); ++ /// @inheritdoc IPoolConfigurator ++ function setAssetBorrowableInEMode( ++ address asset, ++ uint8 categoryId, ++ bool borrowable ++ ) external override onlyRiskOrPoolAdmins { ++ uint128 borrowableBitmap = _pool.getEModeCategoryBorrowableBitmap(categoryId); ++ DataTypes.ReserveDataLegacy memory reserveData = _pool.getReserveData(asset); ++ require(reserveData.id != 0 || _pool.getReservesList()[0] == asset, Errors.ASSET_NOT_LISTED); ++ borrowableBitmap = EModeConfiguration.setReserveBitmapBit( ++ borrowableBitmap, ++ reserveData.id, ++ borrowable ++ ); ++ _pool.configureEModeCategoryBorrowableBitmap(categoryId, borrowableBitmap); ++ emit AssetBorrowableInEModeChanged(asset, categoryId, borrowable); + } + + /// @inheritdoc IPoolConfigurator +@@ -5104,10 +4978,10 @@ abstract contract PoolConfigurator is VersionedInitializable, IPoolConfigurator + } + } + +-// src/core/instances/PoolConfiguratorInstance.sol ++// src/contracts/instances/PoolConfiguratorInstance.sol + + contract PoolConfiguratorInstance is PoolConfigurator { +- uint256 public constant CONFIGURATOR_REVISION = 3; ++ uint256 public constant CONFIGURATOR_REVISION = 4; + + /// @inheritdoc VersionedInitializable + function getRevision() internal pure virtual override returns (uint256) { +``` diff --git a/docs/3.2/3.1_3.2_L2PoolDiff.md b/docs/3.2/3.1_3.2_L2PoolDiff.md new file mode 100644 index 00000000..a46cd214 --- /dev/null +++ b/docs/3.2/3.1_3.2_L2PoolDiff.md @@ -0,0 +1,2852 @@ +```diff +diff --git a/tmp/L2PoolFlattened.sol b/tmp/L2PoolFlattened_3.2.sol +index c022808..e5871a1 100644 +--- a/tmp/L2PoolFlattened.sol ++++ b/tmp/L2PoolFlattened_3.2.sol +@@ -1,7 +1,7 @@ + // SPDX-License-Identifier: MIT + pragma solidity ^0.8.0 ^0.8.10; + +-// src/core/contracts/dependencies/openzeppelin/contracts/Address.sol ++// src/contracts/dependencies/openzeppelin/contracts/Address.sol + + // OpenZeppelin Contracts v4.4.1 (utils/Address.sol) + +@@ -221,7 +221,7 @@ library Address { + } + } + +-// src/core/contracts/dependencies/openzeppelin/contracts/Context.sol ++// src/contracts/dependencies/openzeppelin/contracts/Context.sol + + /* + * @dev Provides information about the current execution context, including the +@@ -244,7 +244,7 @@ abstract contract Context { + } + } + +-// src/core/contracts/dependencies/openzeppelin/contracts/IAccessControl.sol ++// src/contracts/dependencies/openzeppelin/contracts/IAccessControl.sol + + /** + * @dev External interface of AccessControl declared to support ERC165 detection. +@@ -334,7 +334,7 @@ interface IAccessControl { + function renounceRole(bytes32 role, address account) external; + } + +-// src/core/contracts/dependencies/openzeppelin/contracts/IERC20.sol ++// src/contracts/dependencies/openzeppelin/contracts/IERC20.sol + + /** + * @dev Interface of the ERC20 standard as defined in the EIP. +@@ -410,7 +410,7 @@ interface IERC20 { + event Approval(address indexed owner, address indexed spender, uint256 value); + } + +-// src/core/contracts/dependencies/openzeppelin/contracts/SafeCast.sol ++// src/contracts/dependencies/openzeppelin/contracts/SafeCast.sol + + // OpenZeppelin Contracts v4.4.1 (utils/math/SafeCast.sol) + +@@ -666,7 +666,7 @@ library SafeCast { + } + } + +-// src/core/contracts/interfaces/IAaveIncentivesController.sol ++// src/contracts/interfaces/IAaveIncentivesController.sol + + /** + * @title IAaveIncentivesController +@@ -685,7 +685,7 @@ interface IAaveIncentivesController { + function handleAction(address user, uint256 totalSupply, uint256 userBalance) external; + } + +-// src/core/contracts/interfaces/IL2Pool.sol ++// src/contracts/interfaces/IL2Pool.sol + + /** + * @title IL2Pool +@@ -778,24 +778,6 @@ interface IL2Pool { + */ + function repayWithATokens(bytes32 args) external returns (uint256); + +- /** +- * @notice Calldata efficient wrapper of the swapBorrowRateMode function +- * @param args Arguments for the swapBorrowRateMode function packed in one bytes32 +- * 232 bits 8 bits 16 bits +- * | 0-padding | shortenedInterestRateMode | assetId | +- * @dev assetId is the index of the asset in the reservesList. +- */ +- function swapBorrowRateMode(bytes32 args) external; +- +- /** +- * @notice Calldata efficient wrapper of the rebalanceStableBorrowRate function +- * @param args Arguments for the rebalanceStableBorrowRate function packed in one bytes32 +- * 80 bits 160 bits 16 bits +- * | 0-padding | user address | assetId | +- * @dev assetId is the index of the asset in the reservesList. +- */ +- function rebalanceStableBorrowRate(bytes32 args) external; +- + /** + * @notice Calldata efficient wrapper of the setUserUseReserveAsCollateral function + * @param args Arguments for the setUserUseReserveAsCollateral function packed in one bytes32 +@@ -819,7 +801,7 @@ interface IL2Pool { + function liquidationCall(bytes32 args1, bytes32 args2) external; + } + +-// src/core/contracts/interfaces/IPoolAddressesProvider.sol ++// src/contracts/interfaces/IPoolAddressesProvider.sol + + /** + * @title IPoolAddressesProvider +@@ -1046,7 +1028,7 @@ interface IPoolAddressesProvider { + function setPoolDataProvider(address newDataProvider) external; + } + +-// src/core/contracts/interfaces/IPriceOracleGetter.sol ++// src/contracts/interfaces/IPriceOracleGetter.sol + + /** + * @title IPriceOracleGetter +@@ -1076,7 +1058,7 @@ interface IPriceOracleGetter { + function getAssetPrice(address asset) external view returns (uint256); + } + +-// src/core/contracts/interfaces/IScaledBalanceToken.sol ++// src/contracts/interfaces/IScaledBalanceToken.sol + + /** + * @title IScaledBalanceToken +@@ -1148,7 +1130,7 @@ interface IScaledBalanceToken { + function getPreviousIndex(address user) external view returns (uint256); + } + +-// src/core/contracts/protocol/libraries/aave-upgradeability/VersionedInitializable.sol ++// src/contracts/misc/aave-upgradeability/VersionedInitializable.sol + + /** + * @title VersionedInitializable +@@ -1225,7 +1207,7 @@ abstract contract VersionedInitializable { + uint256[50] private ______gap; + } + +-// src/core/contracts/protocol/libraries/helpers/Errors.sol ++// src/contracts/protocol/libraries/helpers/Errors.sol + + /** + * @title Errors library +@@ -1263,17 +1245,14 @@ library Errors { + string public constant RESERVE_FROZEN = '28'; // 'Action cannot be performed because the reserve is frozen' + string public constant RESERVE_PAUSED = '29'; // 'Action cannot be performed because the reserve is paused' + string public constant BORROWING_NOT_ENABLED = '30'; // 'Borrowing is not enabled' +- string public constant STABLE_BORROWING_NOT_ENABLED = '31'; // 'Stable borrowing is not enabled' + string public constant NOT_ENOUGH_AVAILABLE_USER_BALANCE = '32'; // 'User cannot withdraw more than the available balance' + string public constant INVALID_INTEREST_RATE_MODE_SELECTED = '33'; // 'Invalid interest rate mode selected' + string public constant COLLATERAL_BALANCE_IS_ZERO = '34'; // 'The collateral balance is 0' + string public constant HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD = '35'; // 'Health factor is lesser than the liquidation threshold' + string public constant COLLATERAL_CANNOT_COVER_NEW_BORROW = '36'; // 'There is not enough collateral to cover a new borrow' + string public constant COLLATERAL_SAME_AS_BORROWING_CURRENCY = '37'; // 'Collateral is (mostly) the same currency that is being borrowed' +- string public constant AMOUNT_BIGGER_THAN_MAX_LOAN_SIZE_STABLE = '38'; // 'The requested amount is greater than the max loan size in stable rate mode' + string public constant NO_DEBT_OF_SELECTED_TYPE = '39'; // 'For repayment of a specific type of debt, the user needs to have debt that type' + string public constant NO_EXPLICIT_AMOUNT_TO_REPAY_ON_BEHALF = '40'; // 'To repay on behalf of a user an explicit amount to repay is needed' +- string public constant NO_OUTSTANDING_STABLE_DEBT = '41'; // 'User does not have outstanding stable rate debt on this reserve' + string public constant NO_OUTSTANDING_VARIABLE_DEBT = '42'; // 'User does not have outstanding variable rate debt on this reserve' + string public constant UNDERLYING_BALANCE_ZERO = '43'; // 'The underlying balance needs to be greater than 0' + string public constant INTEREST_RATE_REBALANCE_CONDITIONS_NOT_MET = '44'; // 'Interest rate rebalance conditions were not met' +@@ -1286,7 +1265,6 @@ library Errors { + string public constant UNBACKED_MINT_CAP_EXCEEDED = '52'; // 'Unbacked mint cap is exceeded' + string public constant DEBT_CEILING_EXCEEDED = '53'; // 'Debt ceiling is exceeded' + string public constant UNDERLYING_CLAIMABLE_RIGHTS_NOT_ZERO = '54'; // 'Claimable rights over underlying not zero (aToken supply or accruedToTreasury)' +- string public constant STABLE_DEBT_NOT_ZERO = '55'; // 'Stable debt supply is not zero' + string public constant VARIABLE_DEBT_SUPPLY_NOT_ZERO = '56'; // 'Variable debt supply is not zero' + string public constant LTV_VALIDATION_FAILED = '57'; // 'Ltv validation failed' + string public constant INCONSISTENT_EMODE_CATEGORY = '58'; // 'Inconsistent eMode category' +@@ -1315,11 +1293,9 @@ library Errors { + string public constant DEBT_CEILING_NOT_ZERO = '81'; // 'Debt ceiling is not zero' + string public constant ASSET_NOT_LISTED = '82'; // 'Asset is not listed' + string public constant INVALID_OPTIMAL_USAGE_RATIO = '83'; // 'Invalid optimal usage ratio' +- string public constant INVALID_OPTIMAL_STABLE_TO_TOTAL_DEBT_RATIO = '84'; // 'Invalid optimal stable to total debt ratio' + string public constant UNDERLYING_CANNOT_BE_RESCUED = '85'; // 'The underlying asset cannot be rescued' + string public constant ADDRESSES_PROVIDER_ALREADY_ADDED = '86'; // 'Reserve has already been added to reserve list' + string public constant POOL_ADDRESSES_DO_NOT_MATCH = '87'; // 'The token implementation pool address and the pool address provided by the initializing pool do not match' +- string public constant STABLE_BORROWING_ENABLED = '88'; // 'Stable borrowing is enabled' + string public constant SILOED_BORROWING_VIOLATION = '89'; // 'User is trying to borrow multiple assets including a siloed one' + string public constant RESERVE_DEBT_NOT_ZERO = '90'; // the total debt of the reserve needs to be 0 + string public constant FLASHLOAN_DISABLED = '91'; // FlashLoaning for this asset is disabled +@@ -1331,9 +1307,10 @@ library Errors { + string public constant LIQUIDATION_GRACE_SENTINEL_CHECK_FAILED = '97'; // 'Liquidation grace sentinel validation failed' + string public constant INVALID_GRACE_PERIOD = '98'; // Grace period above a valid range + string public constant INVALID_FREEZE_STATE = '99'; // Reserve is already in the passed freeze state ++ string public constant NOT_BORROWABLE_IN_EMODE = '100'; // Asset not borrowable in eMode + } + +-// src/core/contracts/protocol/libraries/logic/CalldataLogic.sol ++// src/contracts/protocol/libraries/logic/CalldataLogic.sol + + /** + * @title CalldataLogic library +@@ -1420,7 +1397,7 @@ library CalldataLogic { + * @param args The packed borrow params + * @return The address of the underlying reserve + * @return The amount to borrow +- * @return The interestRateMode, 1 for stable or 2 for variable debt ++ * @return The interestRateMode, 2 for variable debt, 1 is deprecated (changed on v3.2.0) + * @return The referralCode + */ + function decodeBorrowParams( +@@ -1448,7 +1425,7 @@ library CalldataLogic { + * @param args The packed repay params + * @return The address of the underlying reserve + * @return The amount to repay +- * @return The interestRateMode, 1 for stable or 2 for variable debt ++ * @return The interestRateMode, 2 for variable debt, 1 is deprecated (changed on v3.2.0) + */ + function decodeRepayParams( + mapping(uint256 => address) storage reservesList, +@@ -1477,7 +1454,7 @@ library CalldataLogic { + * @param args The packed repay with permit params + * @return The address of the underlying reserve + * @return The amount to repay +- * @return The interestRateMode, 1 for stable or 2 for variable debt ++ * @return The interestRateMode, 2 for variable debt, 1 is deprecated (changed on v3.2.0) + * @return The deadline of the permit + * @return The V value of the permit signature + */ +@@ -1501,48 +1478,6 @@ library CalldataLogic { + return (asset, amount, interestRateMode, deadline, permitV); + } + +- /** +- * @notice Decodes compressed swap borrow rate mode params to standard params +- * @param reservesList The addresses of all the active reserves +- * @param args The packed swap borrow rate mode params +- * @return The address of the underlying reserve +- * @return The interest rate mode, 1 for stable 2 for variable debt +- */ +- function decodeSwapBorrowRateModeParams( +- mapping(uint256 => address) storage reservesList, +- bytes32 args +- ) internal view returns (address, uint256) { +- uint16 assetId; +- uint256 interestRateMode; +- +- assembly { +- assetId := and(args, 0xFFFF) +- interestRateMode := and(shr(16, args), 0xFF) +- } +- +- return (reservesList[assetId], interestRateMode); +- } +- +- /** +- * @notice Decodes compressed rebalance stable borrow rate params to standard params +- * @param reservesList The addresses of all the active reserves +- * @param args The packed rabalance stable borrow rate params +- * @return The address of the underlying reserve +- * @return The address of the user to rebalance +- */ +- function decodeRebalanceStableBorrowRateParams( +- mapping(uint256 => address) storage reservesList, +- bytes32 args +- ) internal view returns (address, address) { +- uint16 assetId; +- address user; +- assembly { +- assetId := and(args, 0xFFFF) +- user := and(shr(16, args), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) +- } +- return (reservesList[assetId], user); +- } +- + /** + * @notice Decodes compressed set user use reserve as collateral params to standard params + * @param reservesList The addresses of all the active reserves +@@ -1608,7 +1543,7 @@ library CalldataLogic { + } + } + +-// src/core/contracts/protocol/libraries/math/PercentageMath.sol ++// src/contracts/protocol/libraries/math/PercentageMath.sol + + /** + * @title PercentageMath library +@@ -1669,7 +1604,7 @@ library PercentageMath { + } + } + +-// src/core/contracts/protocol/libraries/math/WadRayMath.sol ++// src/contracts/protocol/libraries/math/WadRayMath.sol + + /** + * @title WadRayMath library +@@ -1795,7 +1730,7 @@ library WadRayMath { + } + } + +-// src/core/contracts/protocol/libraries/types/DataTypes.sol ++// src/contracts/protocol/libraries/types/DataTypes.sol + + library DataTypes { + /** +@@ -1813,7 +1748,7 @@ library DataTypes { + uint128 variableBorrowIndex; + //the current variable borrow rate. Expressed in ray + uint128 currentVariableBorrowRate; +- //the current stable borrow rate. Expressed in ray ++ // DEPRECATED on v3.2.0 + uint128 currentStableBorrowRate; + //timestamp of last update + uint40 lastUpdateTimestamp; +@@ -1821,7 +1756,7 @@ library DataTypes { + uint16 id; + //aToken address + address aTokenAddress; +- //stableDebtToken address ++ // DEPRECATED on v3.2.0 + address stableDebtTokenAddress; + //variableDebtToken address + address variableDebtTokenAddress; +@@ -1846,8 +1781,8 @@ library DataTypes { + uint128 variableBorrowIndex; + //the current variable borrow rate. Expressed in ray + uint128 currentVariableBorrowRate; +- //the current stable borrow rate. Expressed in ray +- uint128 currentStableBorrowRate; ++ // DEPRECATED on v3.2.0 ++ uint128 __deprecatedStableBorrowRate; + //timestamp of last update + uint40 lastUpdateTimestamp; + //the id of the reserve. Represents the position in the list of the active reserves +@@ -1856,8 +1791,8 @@ library DataTypes { + uint40 liquidationGracePeriodUntil; + //aToken address + address aTokenAddress; +- //stableDebtToken address +- address stableDebtTokenAddress; ++ // DEPRECATED on v3.2.0 ++ address __deprecatedStableDebtTokenAddress; + //variableDebtToken address + address variableDebtTokenAddress; + //address of the interest rate strategy +@@ -1880,7 +1815,7 @@ library DataTypes { + //bit 56: reserve is active + //bit 57: reserve is frozen + //bit 58: borrowing is enabled +- //bit 59: stable rate borrowing enabled ++ //bit 59: DEPRECATED: stable rate borrowing enabled + //bit 60: asset is paused + //bit 61: borrowing in isolation mode is enabled + //bit 62: siloed borrowing enabled +@@ -1889,7 +1824,7 @@ library DataTypes { + //bit 80-115: borrow cap in whole tokens, borrowCap == 0 => no cap + //bit 116-151: supply cap in whole tokens, supplyCap == 0 => no cap + //bit 152-167: liquidation protocol fee +- //bit 168-175: eMode category ++ //bit 168-175: DEPRECATED: eMode category + //bit 176-211: unbacked mint cap in whole tokens, unbackedMintCap == 0 => minting disabled + //bit 212-251: debt ceiling for isolation mode with (ReserveConfiguration::DEBT_CEILING_DECIMALS) decimals + //bit 252: virtual accounting is enabled for the reserve +@@ -1907,30 +1842,49 @@ library DataTypes { + uint256 data; + } + +- struct EModeCategory { ++ // DEPRECATED: kept for backwards compatibility, might be removed in a future version ++ struct EModeCategoryLegacy { + // each eMode category has a custom ltv and liquidation threshold + uint16 ltv; + uint16 liquidationThreshold; + uint16 liquidationBonus; +- // each eMode category may or may not have a custom oracle to override the individual assets price oracles ++ // DEPRECATED + address priceSource; + string label; + } + ++ struct CollateralConfig { ++ uint16 ltv; ++ uint16 liquidationThreshold; ++ uint16 liquidationBonus; ++ } ++ ++ struct EModeCategoryBaseConfiguration { ++ uint16 ltv; ++ uint16 liquidationThreshold; ++ uint16 liquidationBonus; ++ string label; ++ } ++ ++ struct EModeCategory { ++ // each eMode category has a custom ltv and liquidation threshold ++ uint16 ltv; ++ uint16 liquidationThreshold; ++ uint16 liquidationBonus; ++ uint128 collateralBitmap; ++ string label; ++ uint128 borrowableBitmap; ++ } ++ + enum InterestRateMode { + NONE, +- STABLE, ++ __DEPRECATED, + VARIABLE + } + + struct ReserveCache { + uint256 currScaledVariableDebt; + uint256 nextScaledVariableDebt; +- uint256 currPrincipalStableDebt; +- uint256 currAvgStableBorrowRate; +- uint256 currTotalStableDebt; +- uint256 nextAvgStableBorrowRate; +- uint256 nextTotalStableDebt; + uint256 currLiquidityIndex; + uint256 nextLiquidityIndex; + uint256 currVariableBorrowIndex; +@@ -1940,10 +1894,8 @@ library DataTypes { + uint256 reserveFactor; + ReserveConfigurationMap reserveConfiguration; + address aTokenAddress; +- address stableDebtTokenAddress; + address variableDebtTokenAddress; + uint40 reserveLastUpdateTimestamp; +- uint40 stableDebtLastUpdateTimestamp; + } + + struct ExecuteLiquidationCallParams { +@@ -1973,7 +1925,6 @@ library DataTypes { + InterestRateMode interestRateMode; + uint16 referralCode; + bool releaseUnderlying; +- uint256 maxStableRateBorrowSizePercent; + uint256 reservesCount; + address oracle; + uint8 userEModeCategory; +@@ -2025,7 +1976,6 @@ library DataTypes { + uint16 referralCode; + uint256 flashLoanPremiumToProtocol; + uint256 flashLoanPremiumTotal; +- uint256 maxStableRateBorrowSizePercent; + uint256 reservesCount; + address addressesProvider; + address pool; +@@ -2067,7 +2017,6 @@ library DataTypes { + address userAddress; + uint256 amount; + InterestRateMode interestRateMode; +- uint256 maxStableLoanPercent; + uint256 reservesCount; + address oracle; + uint8 userEModeCategory; +@@ -2088,9 +2037,7 @@ library DataTypes { + uint256 unbacked; + uint256 liquidityAdded; + uint256 liquidityTaken; +- uint256 totalStableDebt; +- uint256 totalVariableDebt; +- uint256 averageStableBorrowRate; ++ uint256 totalDebt; + uint256 reserveFactor; + address reserve; + bool usingVirtualBalance; +@@ -2100,7 +2047,6 @@ library DataTypes { + struct InitReserveParams { + address asset; + address aTokenAddress; +- address stableDebtAddress; + address variableDebtAddress; + address interestRateStrategyAddress; + uint16 reservesCount; +@@ -2108,7 +2054,7 @@ library DataTypes { + } + } + +-// src/core/contracts/dependencies/gnosis/contracts/GPv2SafeERC20.sol ++// src/contracts/dependencies/gnosis/contracts/GPv2SafeERC20.sol + + /// @title Gnosis Protocol v2 Safe ERC20 Transfer Library + /// @author Gnosis Developers +@@ -2221,7 +2167,7 @@ library GPv2SafeERC20 { + } + } + +-// src/core/contracts/dependencies/openzeppelin/contracts/IERC20Detailed.sol ++// src/contracts/dependencies/openzeppelin/contracts/IERC20Detailed.sol + + interface IERC20Detailed is IERC20 { + function name() external view returns (string memory); +@@ -2231,7 +2177,7 @@ interface IERC20Detailed is IERC20 { + function decimals() external view returns (uint8); + } + +-// src/core/contracts/interfaces/IACLManager.sol ++// src/contracts/interfaces/IACLManager.sol + + /** + * @title IACLManager +@@ -2404,7 +2350,7 @@ interface IACLManager { + function isAssetListingAdmin(address admin) external view returns (bool); + } + +-// src/core/contracts/interfaces/IERC20WithPermit.sol ++// src/contracts/interfaces/IERC20WithPermit.sol + + /** + * @title IERC20WithPermit +@@ -2435,7 +2381,7 @@ interface IERC20WithPermit is IERC20 { + ) external; + } + +-// src/core/contracts/interfaces/IPriceOracleSentinel.sol ++// src/contracts/interfaces/IPriceOracleSentinel.sol + + /** + * @title IPriceOracleSentinel +@@ -2500,7 +2446,7 @@ interface IPriceOracleSentinel { + function getGracePeriod() external view returns (uint256); + } + +-// src/core/contracts/interfaces/IReserveInterestRateStrategy.sol ++// src/contracts/interfaces/IReserveInterestRateStrategy.sol + + /** + * @title IReserveInterestRateStrategy +@@ -2520,15 +2466,14 @@ interface IReserveInterestRateStrategy { + * @notice Calculates the interest rates depending on the reserve's state and configurations + * @param params The parameters needed to calculate interest rates + * @return liquidityRate The liquidity rate expressed in ray +- * @return stableBorrowRate The stable borrow rate expressed in ray + * @return variableBorrowRate The variable borrow rate expressed in ray + */ + function calculateInterestRates( + DataTypes.CalculateInterestRatesParams memory params +- ) external view returns (uint256, uint256, uint256); ++ ) external view returns (uint256, uint256); + } + +-// src/core/contracts/protocol/libraries/math/MathUtils.sol ++// src/contracts/protocol/libraries/math/MathUtils.sol + + /** + * @title MathUtils library +@@ -2625,7 +2570,7 @@ library MathUtils { + } + } + +-// src/core/contracts/interfaces/IPool.sol ++// src/contracts/interfaces/IPool.sol + + /** + * @title IPool +@@ -2690,7 +2635,7 @@ interface IPool { + * initiator of the transaction on flashLoan() + * @param onBehalfOf The address that will be getting the debt + * @param amount The amount borrowed out +- * @param interestRateMode The rate mode: 1 for Stable, 2 for Variable ++ * @param interestRateMode The rate mode: 2 for Variable, 1 is deprecated (changed on v3.2.0) + * @param borrowRate The numeric rate at which the user has borrowed, expressed in ray + * @param referralCode The referral code used + */ +@@ -2720,18 +2665,6 @@ interface IPool { + bool useATokens + ); + +- /** +- * @dev Emitted on swapBorrowRateMode() +- * @param reserve The address of the underlying asset of the reserve +- * @param user The address of the user swapping his rate mode +- * @param interestRateMode The current interest rate mode of the position being swapped: 1 for Stable, 2 for Variable +- */ +- event SwapBorrowRateMode( +- address indexed reserve, +- address indexed user, +- DataTypes.InterestRateMode interestRateMode +- ); +- + /** + * @dev Emitted on borrow(), repay() and liquidationCall() when using isolated assets + * @param asset The address of the underlying asset of the reserve +@@ -2760,20 +2693,14 @@ interface IPool { + */ + event ReserveUsedAsCollateralDisabled(address indexed reserve, address indexed user); + +- /** +- * @dev Emitted on rebalanceStableBorrowRate() +- * @param reserve The address of the underlying asset of the reserve +- * @param user The address of the user for which the rebalance has been executed +- */ +- event RebalanceStableBorrowRate(address indexed reserve, address indexed user); +- + /** + * @dev Emitted on flashLoan() + * @param target The address of the flash loan receiver contract + * @param initiator The address initiating the flash loan + * @param asset The address of the asset being flash borrowed + * @param amount The amount flash borrowed +- * @param interestRateMode The flashloan mode: 0 for regular flashloan, 1 for Stable debt, 2 for Variable debt ++ * @param interestRateMode The flashloan mode: 0 for regular flashloan, ++ * 1 for Stable (Deprecated on v3.2.0), 2 for Variable + * @param premium The fee flash borrowed + * @param referralCode The referral code used + */ +@@ -2812,7 +2739,7 @@ interface IPool { + * @dev Emitted when the state of a reserve is updated. + * @param reserve The address of the underlying asset of the reserve + * @param liquidityRate The next liquidity rate +- * @param stableBorrowRate The next stable borrow rate ++ * @param stableBorrowRate The next stable borrow rate @note deprecated on v3.2.0 + * @param variableBorrowRate The next variable borrow rate + * @param liquidityIndex The next liquidity index + * @param variableBorrowIndex The next variable borrow index +@@ -2911,13 +2838,12 @@ interface IPool { + + /** + * @notice Allows users to borrow a specific `amount` of the reserve underlying asset, provided that the borrower +- * already supplied enough collateral, or he was given enough allowance by a credit delegator on the +- * corresponding debt token (StableDebtToken or VariableDebtToken) ++ * already supplied enough collateral, or he was given enough allowance by a credit delegator on the VariableDebtToken + * - E.g. User borrows 100 USDC passing as `onBehalfOf` his own address, receiving the 100 USDC in his wallet +- * and 100 stable/variable debt tokens, depending on the `interestRateMode` ++ * and 100 variable debt tokens + * @param asset The address of the underlying asset to borrow + * @param amount The amount to be borrowed +- * @param interestRateMode The interest rate mode at which the user wants to borrow: 1 for Stable, 2 for Variable ++ * @param interestRateMode 2 for Variable, 1 is deprecated on v3.2.0 + * @param referralCode The code used to register the integrator originating the operation, for potential rewards. + * 0 if the action is executed directly by the user, without any middle-man + * @param onBehalfOf The address of the user who will receive the debt. Should be the address of the borrower itself +@@ -2934,11 +2860,11 @@ interface IPool { + + /** + * @notice Repays a borrowed `amount` on a specific reserve, burning the equivalent debt tokens owned +- * - E.g. User repays 100 USDC, burning 100 variable/stable debt tokens of the `onBehalfOf` address ++ * - E.g. User repays 100 USDC, burning 100 variable debt tokens of the `onBehalfOf` address + * @param asset The address of the borrowed underlying asset previously borrowed + * @param amount The amount to repay + * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode` +- * @param interestRateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable ++ * @param interestRateMode 2 for Variable, 1 is deprecated on v3.2.0 + * @param onBehalfOf The address of the user who will get his debt reduced/removed. Should be the address of the + * user calling the function if he wants to reduce/remove his own debt, or the address of any other + * other borrower whose debt should be removed +@@ -2957,7 +2883,7 @@ interface IPool { + * @param asset The address of the borrowed underlying asset previously borrowed + * @param amount The amount to repay + * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode` +- * @param interestRateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable ++ * @param interestRateMode 2 for Variable, 1 is deprecated on v3.2.0 + * @param onBehalfOf Address of the user who will get his debt reduced/removed. Should be the address of the + * user calling the function if he wants to reduce/remove his own debt, or the address of any other + * other borrower whose debt should be removed +@@ -2981,13 +2907,13 @@ interface IPool { + /** + * @notice Repays a borrowed `amount` on a specific reserve using the reserve aTokens, burning the + * equivalent debt tokens +- * - E.g. User repays 100 USDC using 100 aUSDC, burning 100 variable/stable debt tokens ++ * - E.g. User repays 100 USDC using 100 aUSDC, burning 100 variable debt tokens + * @dev Passing uint256.max as amount will clean up any residual aToken dust balance, if the user aToken + * balance is not enough to cover the whole debt + * @param asset The address of the borrowed underlying asset previously borrowed + * @param amount The amount to repay + * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode` +- * @param interestRateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable ++ * @param interestRateMode DEPRECATED in v3.2.0 + * @return The final amount repaid + */ + function repayWithATokens( +@@ -2996,32 +2922,6 @@ interface IPool { + uint256 interestRateMode + ) external returns (uint256); + +- /** +- * @notice Allows a borrower to swap his debt between stable and variable mode, or vice versa +- * @param asset The address of the underlying asset borrowed +- * @param interestRateMode The current interest rate mode of the position being swapped: 1 for Stable, 2 for Variable +- */ +- function swapBorrowRateMode(address asset, uint256 interestRateMode) external; +- +- /** +- * @notice Permissionless method which allows anyone to swap a users stable debt to variable debt +- * @dev Introduced in favor of stable rate deprecation +- * @param asset The address of the underlying asset borrowed +- * @param user The address of the user whose debt will be swapped from stable to variable +- */ +- function swapToVariable(address asset, address user) external; +- +- /** +- * @notice Rebalances the stable interest rate of a user to the current stable rate defined on the reserve. +- * - Users can be rebalanced if the following conditions are satisfied: +- * 1. Usage ratio is above 95% +- * 2. the current supply APY is below REBALANCE_UP_THRESHOLD * maxVariableBorrowRate, which means that too +- * much has been borrowed at a stable rate and suppliers are not earning enough +- * @param asset The address of the underlying asset borrowed +- * @param user The address of the user to be rebalanced +- */ +- function rebalanceStableBorrowRate(address asset, address user) external; +- + /** + * @notice Allows suppliers to enable/disable a specific supplied asset as collateral + * @param asset The address of the underlying asset supplied +@@ -3058,9 +2958,9 @@ interface IPool { + * @param amounts The amounts of the assets being flash-borrowed + * @param interestRateModes Types of the debt to open if the flash loan is not returned: + * 0 -> Don't open any debt, just revert if funds can't be transferred from the receiver +- * 1 -> Open debt at stable rate for the value of the amount flash-borrowed to the `onBehalfOf` address ++ * 1 -> Deprecated on v3.2.0 + * 2 -> Open debt at variable rate for the value of the amount flash-borrowed to the `onBehalfOf` address +- * @param onBehalfOf The address that will receive the debt in the case of using on `modes` 1 or 2 ++ * @param onBehalfOf The address that will receive the debt in the case of using 2 on `modes` + * @param params Variadic packed params to pass to the receiver as extra information + * @param referralCode The code used to register the integrator originating the operation, for potential rewards. + * 0 if the action is executed directly by the user, without any middle-man +@@ -3125,14 +3025,12 @@ interface IPool { + * @dev Only callable by the PoolConfigurator contract + * @param asset The address of the underlying asset of the reserve + * @param aTokenAddress The address of the aToken that will be assigned to the reserve +- * @param stableDebtAddress The address of the StableDebtToken that will be assigned to the reserve + * @param variableDebtAddress The address of the VariableDebtToken that will be assigned to the reserve + * @param interestRateStrategyAddress The address of the interest rate strategy contract + */ + function initReserve( + address asset, + address aTokenAddress, +- address stableDebtAddress, + address variableDebtAddress, + address interestRateStrategyAddress + ) external; +@@ -3140,6 +3038,7 @@ interface IPool { + /** + * @notice Drop a reserve + * @dev Only callable by the PoolConfigurator contract ++ * @dev Does not reset eMode flags, which must be considered when reusing the same reserve id for a different reserve. + * @param asset The address of the underlying asset of the reserve + */ + function dropReserve(address asset) external; +@@ -3230,6 +3129,7 @@ interface IPool { + + /** + * @notice Returns the state and configuration of the reserve, including extra data included with Aave v3.1 ++ * @dev DEPRECATED use independent getters instead (getReserveData, getLiquidationGracePeriod) + * @param asset The address of the underlying asset of the reserve + * @return The state and configuration data of the reserve with virtual accounting + */ +@@ -3312,20 +3212,70 @@ interface IPool { + ) external; + + /** +- * @notice Configures a new category for the eMode. ++ * @notice Configures a new or alters an existing collateral configuration of an eMode. + * @dev In eMode, the protocol allows very high borrowing power to borrow assets of the same category. + * The category 0 is reserved as it's the default for volatile assets + * @param id The id of the category + * @param config The configuration of the category + */ +- function configureEModeCategory(uint8 id, DataTypes.EModeCategory memory config) external; ++ function configureEModeCategory( ++ uint8 id, ++ DataTypes.EModeCategoryBaseConfiguration memory config ++ ) external; ++ ++ /** ++ * @notice Replaces the current eMode collateralBitmap. ++ * @param id The id of the category ++ * @param collateralBitmap The collateralBitmap of the category ++ */ ++ function configureEModeCategoryCollateralBitmap(uint8 id, uint128 collateralBitmap) external; ++ ++ /** ++ * @notice Replaces the current eMode borrowableBitmap. ++ * @param id The id of the category ++ * @param borrowableBitmap The borrowableBitmap of the category ++ */ ++ function configureEModeCategoryBorrowableBitmap(uint8 id, uint128 borrowableBitmap) external; + + /** + * @notice Returns the data of an eMode category ++ * @dev DEPRECATED use independent getters instead + * @param id The id of the category + * @return The configuration data of the category + */ +- function getEModeCategoryData(uint8 id) external view returns (DataTypes.EModeCategory memory); ++ function getEModeCategoryData( ++ uint8 id ++ ) external view returns (DataTypes.EModeCategoryLegacy memory); ++ ++ /** ++ * @notice Returns the label of an eMode category ++ * @param id The id of the category ++ * @return The label of the category ++ */ ++ function getEModeCategoryLabel(uint8 id) external view returns (string memory); ++ ++ /** ++ * @notice Returns the collateral config of an eMode category ++ * @param id The id of the category ++ * @return The ltv,lt,lb of the category ++ */ ++ function getEModeCategoryCollateralConfig( ++ uint8 id ++ ) external view returns (DataTypes.CollateralConfig memory); ++ ++ /** ++ * @notice Returns the collateralBitmap of an eMode category ++ * @param id The id of the category ++ * @return The collateralBitmap of the category ++ */ ++ function getEModeCategoryCollateralBitmap(uint8 id) external view returns (uint128); ++ ++ /** ++ * @notice Returns the borrowableBitmap of an eMode category ++ * @param id The id of the category ++ * @return The borrowableBitmap of the category ++ */ ++ function getEModeCategoryBorrowableBitmap(uint8 id) external view returns (uint128); + + /** + * @notice Allows a user to use the protocol in eMode +@@ -3363,12 +3313,6 @@ interface IPool { + **/ + function getLiquidationGracePeriod(address asset) external returns (uint40); + +- /** +- * @notice Returns the percentage of available liquidity that can be borrowed at once at stable rate +- * @return The percentage of available liquidity to borrow, expressed in bps +- */ +- function MAX_STABLE_RATE_BORROW_SIZE_PERCENT() external view returns (uint256); +- + /** + * @notice Returns the total fee on flash loans + * @return The total fee on flashloans +@@ -3457,7 +3401,7 @@ interface IPool { + function getSupplyLogic() external view returns (address); + } + +-// src/core/contracts/protocol/libraries/configuration/ReserveConfiguration.sol ++// src/contracts/protocol/libraries/configuration/ReserveConfiguration.sol + + /** + * @title ReserveConfiguration library +@@ -3472,7 +3416,7 @@ library ReserveConfiguration { + uint256 internal constant ACTIVE_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFF; // prettier-ignore + uint256 internal constant FROZEN_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFFFFFFFFFFFFFF; // prettier-ignore + uint256 internal constant BORROWING_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFFFFFFFFFFFF; // prettier-ignore +- uint256 internal constant STABLE_BORROWING_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFFFFF; // prettier-ignore ++ // @notice there is an unoccupied hole of 1 bit at position 59 from pre 3.2 stableBorrowRateEnabled + uint256 internal constant PAUSED_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFF; // prettier-ignore + uint256 internal constant BORROWABLE_IN_ISOLATION_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFFFFFFFFFFFFFFF; // prettier-ignore + uint256 internal constant SILOED_BORROWING_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFFFFFFFFFFFFF; // prettier-ignore +@@ -3481,7 +3425,7 @@ library ReserveConfiguration { + uint256 internal constant BORROW_CAP_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000FFFFFFFFFFFFFFFFFFFF; // prettier-ignore + uint256 internal constant SUPPLY_CAP_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFF000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // prettier-ignore + uint256 internal constant LIQUIDATION_PROTOCOL_FEE_MASK = 0xFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // prettier-ignore +- uint256 internal constant EMODE_CATEGORY_MASK = 0xFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // prettier-ignore ++ // @notice there is an unoccupied hole of 8 bits from 168 to 176 left from pre 3.2 eModeCategory + uint256 internal constant UNBACKED_MINT_CAP_MASK = 0xFFFFFFFFFFF000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // prettier-ignore + uint256 internal constant DEBT_CEILING_MASK = 0xF0000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // prettier-ignore + uint256 internal constant VIRTUAL_ACC_ACTIVE_MASK = 0xEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // prettier-ignore +@@ -3493,7 +3437,6 @@ library ReserveConfiguration { + uint256 internal constant IS_ACTIVE_START_BIT_POSITION = 56; + uint256 internal constant IS_FROZEN_START_BIT_POSITION = 57; + uint256 internal constant BORROWING_ENABLED_START_BIT_POSITION = 58; +- uint256 internal constant STABLE_BORROWING_ENABLED_START_BIT_POSITION = 59; + uint256 internal constant IS_PAUSED_START_BIT_POSITION = 60; + uint256 internal constant BORROWABLE_IN_ISOLATION_START_BIT_POSITION = 61; + uint256 internal constant SILOED_BORROWING_START_BIT_POSITION = 62; +@@ -3502,7 +3445,7 @@ library ReserveConfiguration { + uint256 internal constant BORROW_CAP_START_BIT_POSITION = 80; + uint256 internal constant SUPPLY_CAP_START_BIT_POSITION = 116; + uint256 internal constant LIQUIDATION_PROTOCOL_FEE_START_BIT_POSITION = 152; +- uint256 internal constant EMODE_CATEGORY_START_BIT_POSITION = 168; ++ //@notice there is an unoccupied hole of 8 bits from 168 to 176 left from pre 3.2 eModeCategory + uint256 internal constant UNBACKED_MINT_CAP_START_BIT_POSITION = 176; + uint256 internal constant DEBT_CEILING_START_BIT_POSITION = 212; + uint256 internal constant VIRTUAL_ACC_START_BIT_POSITION = 252; +@@ -3515,7 +3458,6 @@ library ReserveConfiguration { + uint256 internal constant MAX_VALID_BORROW_CAP = 68719476735; + uint256 internal constant MAX_VALID_SUPPLY_CAP = 68719476735; + uint256 internal constant MAX_VALID_LIQUIDATION_PROTOCOL_FEE = 65535; +- uint256 internal constant MAX_VALID_EMODE_CATEGORY = 255; + uint256 internal constant MAX_VALID_UNBACKED_MINT_CAP = 68719476735; + uint256 internal constant MAX_VALID_DEBT_CEILING = 1099511627775; + +@@ -3766,31 +3708,6 @@ library ReserveConfiguration { + return (self.data & ~BORROWING_MASK) != 0; + } + +- /** +- * @notice Enables or disables stable rate borrowing on the reserve +- * @param self The reserve configuration +- * @param enabled True if the stable rate borrowing needs to be enabled, false otherwise +- */ +- function setStableRateBorrowingEnabled( +- DataTypes.ReserveConfigurationMap memory self, +- bool enabled +- ) internal pure { +- self.data = +- (self.data & STABLE_BORROWING_MASK) | +- (uint256(enabled ? 1 : 0) << STABLE_BORROWING_ENABLED_START_BIT_POSITION); +- } +- +- /** +- * @notice Gets the stable rate borrowing state of the reserve +- * @param self The reserve configuration +- * @return The stable rate borrowing state +- */ +- function getStableRateBorrowingEnabled( +- DataTypes.ReserveConfigurationMap memory self +- ) internal pure returns (bool) { +- return (self.data & ~STABLE_BORROWING_MASK) != 0; +- } +- + /** + * @notice Sets the reserve factor of the reserve + * @param self The reserve configuration +@@ -3951,31 +3868,6 @@ library ReserveConfiguration { + return (self.data & ~UNBACKED_MINT_CAP_MASK) >> UNBACKED_MINT_CAP_START_BIT_POSITION; + } + +- /** +- * @notice Sets the eMode asset category +- * @param self The reserve configuration +- * @param category The asset category when the user selects the eMode +- */ +- function setEModeCategory( +- DataTypes.ReserveConfigurationMap memory self, +- uint256 category +- ) internal pure { +- require(category <= MAX_VALID_EMODE_CATEGORY, Errors.INVALID_EMODE_CATEGORY); +- +- self.data = (self.data & EMODE_CATEGORY_MASK) | (category << EMODE_CATEGORY_START_BIT_POSITION); +- } +- +- /** +- * @dev Gets the eMode asset category +- * @param self The reserve configuration +- * @return The eMode category for the asset +- */ +- function getEModeCategory( +- DataTypes.ReserveConfigurationMap memory self +- ) internal pure returns (uint256) { +- return (self.data & ~EMODE_CATEGORY_MASK) >> EMODE_CATEGORY_START_BIT_POSITION; +- } +- + /** + * @notice Sets the flashloanable flag for the reserve + * @param self The reserve configuration +@@ -4034,19 +3926,17 @@ library ReserveConfiguration { + * @return The state flag representing active + * @return The state flag representing frozen + * @return The state flag representing borrowing enabled +- * @return The state flag representing stableRateBorrowing enabled + * @return The state flag representing paused + */ + function getFlags( + DataTypes.ReserveConfigurationMap memory self +- ) internal pure returns (bool, bool, bool, bool, bool) { ++ ) internal pure returns (bool, bool, bool, bool) { + uint256 dataLocal = self.data; + + return ( + (dataLocal & ~ACTIVE_MASK) != 0, + (dataLocal & ~FROZEN_MASK) != 0, + (dataLocal & ~BORROWING_MASK) != 0, +- (dataLocal & ~STABLE_BORROWING_MASK) != 0, + (dataLocal & ~PAUSED_MASK) != 0 + ); + } +@@ -4059,11 +3949,10 @@ library ReserveConfiguration { + * @return The state param representing liquidation bonus + * @return The state param representing reserve decimals + * @return The state param representing reserve factor +- * @return The state param representing eMode category + */ + function getParams( + DataTypes.ReserveConfigurationMap memory self +- ) internal pure returns (uint256, uint256, uint256, uint256, uint256, uint256) { ++ ) internal pure returns (uint256, uint256, uint256, uint256, uint256) { + uint256 dataLocal = self.data; + + return ( +@@ -4071,8 +3960,7 @@ library ReserveConfiguration { + (dataLocal & ~LIQUIDATION_THRESHOLD_MASK) >> LIQUIDATION_THRESHOLD_START_BIT_POSITION, + (dataLocal & ~LIQUIDATION_BONUS_MASK) >> LIQUIDATION_BONUS_START_BIT_POSITION, + (dataLocal & ~DECIMALS_MASK) >> RESERVE_DECIMALS_START_BIT_POSITION, +- (dataLocal & ~RESERVE_FACTOR_MASK) >> RESERVE_FACTOR_START_BIT_POSITION, +- (dataLocal & ~EMODE_CATEGORY_MASK) >> EMODE_CATEGORY_START_BIT_POSITION ++ (dataLocal & ~RESERVE_FACTOR_MASK) >> RESERVE_FACTOR_START_BIT_POSITION + ); + } + +@@ -4094,32 +3982,7 @@ library ReserveConfiguration { + } + } + +-// src/core/contracts/protocol/libraries/helpers/Helpers.sol +- +-/** +- * @title Helpers library +- * @author Aave +- */ +-library Helpers { +- /** +- * @notice Fetches the user current stable and variable debt balances +- * @param user The user address +- * @param reserveCache The reserve cache data object +- * @return The stable debt balance +- * @return The variable debt balance +- */ +- function getUserCurrentDebt( +- address user, +- DataTypes.ReserveCache memory reserveCache +- ) internal view returns (uint256, uint256) { +- return ( +- IERC20(reserveCache.stableDebtTokenAddress).balanceOf(user), +- IERC20(reserveCache.variableDebtTokenAddress).balanceOf(user) +- ); +- } +-} +- +-// src/core/contracts/flashloan/interfaces/IFlashLoanReceiver.sol ++// src/contracts/misc/flashloan/interfaces/IFlashLoanReceiver.sol + + /** + * @title IFlashLoanReceiver +@@ -4152,7 +4015,7 @@ interface IFlashLoanReceiver { + function POOL() external view returns (IPool); + } + +-// src/core/contracts/flashloan/interfaces/IFlashLoanSimpleReceiver.sol ++// src/contracts/misc/flashloan/interfaces/IFlashLoanSimpleReceiver.sol + + /** + * @title IFlashLoanSimpleReceiver +@@ -4185,7 +4048,56 @@ interface IFlashLoanSimpleReceiver { + function POOL() external view returns (IPool); + } + +-// src/core/contracts/protocol/libraries/configuration/UserConfiguration.sol ++// src/contracts/protocol/libraries/configuration/EModeConfiguration.sol ++ ++/** ++ * @title EModeConfiguration library ++ * @author BGD Labs ++ * @notice Implements the bitmap logic to handle the eMode configuration ++ */ ++library EModeConfiguration { ++ /** ++ * @notice Sets a bit in a given bitmap that represents the reserve index range ++ * @dev The supplied bitmap is supposed to be a uint128 in which each bit represents a reserve ++ * @param bitmap The bitmap ++ * @param reserveIndex The index of the reserve in the bitmap ++ * @param enabled True if the reserveIndex should be enabled on the bitmap, false otherwise ++ * @return The altered bitmap ++ */ ++ function setReserveBitmapBit( ++ uint128 bitmap, ++ uint256 reserveIndex, ++ bool enabled ++ ) internal pure returns (uint128) { ++ unchecked { ++ require(reserveIndex < ReserveConfiguration.MAX_RESERVES_COUNT, Errors.INVALID_RESERVE_INDEX); ++ uint128 bit = uint128(1 << reserveIndex); ++ if (enabled) { ++ return bitmap | bit; ++ } else { ++ return bitmap & ~bit; ++ } ++ } ++ } ++ ++ /** ++ * @notice Validates if a reserveIndex is flagged as enabled on a given bitmap ++ * @param bitmap The bitmap ++ * @param reserveIndex The index of the reserve in the bitmap ++ * @return True if the reserveindex is flagged true ++ */ ++ function isReserveEnabledOnBitmap( ++ uint128 bitmap, ++ uint256 reserveIndex ++ ) internal pure returns (bool) { ++ unchecked { ++ require(reserveIndex < ReserveConfiguration.MAX_RESERVES_COUNT, Errors.INVALID_RESERVE_INDEX); ++ return (bitmap >> reserveIndex) & 1 != 0; ++ } ++ } ++} ++ ++// src/contracts/protocol/libraries/configuration/UserConfiguration.sol + + /** + * @title UserConfiguration library +@@ -4417,7 +4329,7 @@ library UserConfiguration { + } + } + +-// src/core/contracts/interfaces/IInitializableAToken.sol ++// src/contracts/interfaces/IInitializableAToken.sol + + /** + * @title IInitializableAToken +@@ -4470,7 +4382,7 @@ interface IInitializableAToken { + ) external; + } + +-// src/core/contracts/interfaces/IInitializableDebtToken.sol ++// src/contracts/interfaces/IInitializableDebtToken.sol + + /** + * @title IInitializableDebtToken +@@ -4519,144 +4431,7 @@ interface IInitializableDebtToken { + ) external; + } + +-// src/core/contracts/interfaces/IStableDebtToken.sol +- +-/** +- * @title IStableDebtToken +- * @author Aave +- * @notice Defines the interface for the stable debt token +- * @dev It does not inherit from IERC20 to save in code size +- */ +-interface IStableDebtToken is IInitializableDebtToken { +- /** +- * @dev Emitted when new stable debt is minted +- * @param user The address of the user who triggered the minting +- * @param onBehalfOf The recipient of stable debt tokens +- * @param amount The amount minted (user entered amount + balance increase from interest) +- * @param currentBalance The balance of the user based on the previous balance and balance increase from interest +- * @param balanceIncrease The increase in balance since the last action of the user 'onBehalfOf' +- * @param newRate The rate of the debt after the minting +- * @param avgStableRate The next average stable rate after the minting +- * @param newTotalSupply The next total supply of the stable debt token after the action +- */ +- event Mint( +- address indexed user, +- address indexed onBehalfOf, +- uint256 amount, +- uint256 currentBalance, +- uint256 balanceIncrease, +- uint256 newRate, +- uint256 avgStableRate, +- uint256 newTotalSupply +- ); +- +- /** +- * @dev Emitted when new stable debt is burned +- * @param from The address from which the debt will be burned +- * @param amount The amount being burned (user entered amount - balance increase from interest) +- * @param currentBalance The balance of the user based on the previous balance and balance increase from interest +- * @param balanceIncrease The increase in balance since the last action of 'from' +- * @param avgStableRate The next average stable rate after the burning +- * @param newTotalSupply The next total supply of the stable debt token after the action +- */ +- event Burn( +- address indexed from, +- uint256 amount, +- uint256 currentBalance, +- uint256 balanceIncrease, +- uint256 avgStableRate, +- uint256 newTotalSupply +- ); +- +- /** +- * @notice Mints debt token to the `onBehalfOf` address. +- * @dev The resulting rate is the weighted average between the rate of the new debt +- * and the rate of the previous debt +- * @param user The address receiving the borrowed underlying, being the delegatee in case +- * of credit delegate, or same as `onBehalfOf` otherwise +- * @param onBehalfOf The address receiving the debt tokens +- * @param amount The amount of debt tokens to mint +- * @param rate The rate of the debt being minted +- * @return True if it is the first borrow, false otherwise +- * @return The total stable debt +- * @return The average stable borrow rate +- */ +- function mint( +- address user, +- address onBehalfOf, +- uint256 amount, +- uint256 rate +- ) external returns (bool, uint256, uint256); +- +- /** +- * @notice Burns debt of `user` +- * @dev The resulting rate is the weighted average between the rate of the new debt +- * and the rate of the previous debt +- * @dev In some instances, a burn transaction will emit a mint event +- * if the amount to burn is less than the interest the user earned +- * @param from The address from which the debt will be burned +- * @param amount The amount of debt tokens getting burned +- * @return The total stable debt +- * @return The average stable borrow rate +- */ +- function burn(address from, uint256 amount) external returns (uint256, uint256); +- +- /** +- * @notice Returns the average rate of all the stable rate loans. +- * @return The average stable rate +- */ +- function getAverageStableRate() external view returns (uint256); +- +- /** +- * @notice Returns the stable rate of the user debt +- * @param user The address of the user +- * @return The stable rate of the user +- */ +- function getUserStableRate(address user) external view returns (uint256); +- +- /** +- * @notice Returns the timestamp of the last update of the user +- * @param user The address of the user +- * @return The timestamp +- */ +- function getUserLastUpdated(address user) external view returns (uint40); +- +- /** +- * @notice Returns the principal, the total supply, the average stable rate and the timestamp for the last update +- * @return The principal +- * @return The total supply +- * @return The average stable rate +- * @return The timestamp of the last update +- */ +- function getSupplyData() external view returns (uint256, uint256, uint256, uint40); +- +- /** +- * @notice Returns the timestamp of the last update of the total supply +- * @return The timestamp +- */ +- function getTotalSupplyLastUpdated() external view returns (uint40); +- +- /** +- * @notice Returns the total supply and the average stable rate +- * @return The total supply +- * @return The average rate +- */ +- function getTotalSupplyAndAvgRate() external view returns (uint256, uint256); +- +- /** +- * @notice Returns the principal debt balance of the user +- * @return The debt balance of the user since the last burn/mint action +- */ +- function principalBalanceOf(address user) external view returns (uint256); +- +- /** +- * @notice Returns the address of the underlying asset of this stableDebtToken (E.g. WETH for stableDebtWETH) +- * @return The address of the underlying asset +- */ +- function UNDERLYING_ASSET_ADDRESS() external view returns (address); +-} +- +-// src/core/contracts/protocol/libraries/logic/IsolationModeLogic.sol ++// src/contracts/protocol/libraries/logic/IsolationModeLogic.sol + + /** + * @title IsolationModeLogic library +@@ -4715,7 +4490,7 @@ library IsolationModeLogic { + } + } + +-// src/core/contracts/interfaces/IVariableDebtToken.sol ++// src/contracts/interfaces/IVariableDebtToken.sol + + /** + * @title IVariableDebtToken +@@ -4758,7 +4533,7 @@ interface IVariableDebtToken is IScaledBalanceToken, IInitializableDebtToken { + function UNDERLYING_ASSET_ADDRESS() external view returns (address); + } + +-// src/core/contracts/interfaces/IAToken.sol ++// src/contracts/interfaces/IAToken.sol + + /** + * @title IAToken +@@ -4892,7 +4667,7 @@ interface IAToken is IERC20, IScaledBalanceToken, IInitializableAToken { + function rescueTokens(address token, address to, uint256 amount) external; + } + +-// src/core/contracts/protocol/tokenization/base/IncentivizedERC20.sol ++// src/contracts/protocol/tokenization/base/IncentivizedERC20.sol + + /** + * @title IncentivizedERC20 +@@ -4923,8 +4698,7 @@ abstract contract IncentivizedERC20 is Context, IERC20Detailed { + /** + * @dev UserState - additionalData is a flexible field. + * ATokens and VariableDebtTokens use this field store the index of the +- * user's last supply/withdrawal/borrow/repayment. StableDebtTokens use +- * this field to store the user's stable rate. ++ * user's last supply/withdrawal/borrow/repayment. + */ + struct UserState { + uint128 balance; +@@ -5116,7 +4890,7 @@ abstract contract IncentivizedERC20 is Context, IERC20Detailed { + } + } + +-// src/core/contracts/protocol/libraries/logic/ReserveLogic.sol ++// src/contracts/protocol/libraries/logic/ReserveLogic.sol + + /** + * @title ReserveLogic library +@@ -5237,14 +5011,12 @@ library ReserveLogic { + * @notice Initializes a reserve. + * @param reserve The reserve object + * @param aTokenAddress The address of the overlying atoken contract +- * @param stableDebtTokenAddress The address of the overlying stable debt token contract + * @param variableDebtTokenAddress The address of the overlying variable debt token contract + * @param interestRateStrategyAddress The address of the interest rate strategy contract + */ + function init( + DataTypes.ReserveData storage reserve, + address aTokenAddress, +- address stableDebtTokenAddress, + address variableDebtTokenAddress, + address interestRateStrategyAddress + ) internal { +@@ -5253,20 +5025,12 @@ library ReserveLogic { + reserve.liquidityIndex = uint128(WadRayMath.RAY); + reserve.variableBorrowIndex = uint128(WadRayMath.RAY); + reserve.aTokenAddress = aTokenAddress; +- reserve.stableDebtTokenAddress = stableDebtTokenAddress; + reserve.variableDebtTokenAddress = variableDebtTokenAddress; + reserve.interestRateStrategyAddress = interestRateStrategyAddress; + } + +- struct UpdateInterestRatesAndVirtualBalanceLocalVars { +- uint256 nextLiquidityRate; +- uint256 nextStableRate; +- uint256 nextVariableRate; +- uint256 totalVariableDebt; +- } +- + /** +- * @notice Updates the reserve current stable borrow rate, the current variable borrow rate and the current liquidity rate. ++ * @notice Updates the reserve current variable borrow rate and the current liquidity rate. + * @param reserve The reserve reserve to be updated + * @param reserveCache The caching layer for the reserve data + * @param reserveAddress The address of the reserve to be updated +@@ -5280,34 +5044,27 @@ library ReserveLogic { + uint256 liquidityAdded, + uint256 liquidityTaken + ) internal { +- UpdateInterestRatesAndVirtualBalanceLocalVars memory vars; +- +- vars.totalVariableDebt = reserveCache.nextScaledVariableDebt.rayMul( ++ uint256 totalVariableDebt = reserveCache.nextScaledVariableDebt.rayMul( + reserveCache.nextVariableBorrowIndex + ); + +- ( +- vars.nextLiquidityRate, +- vars.nextStableRate, +- vars.nextVariableRate +- ) = IReserveInterestRateStrategy(reserve.interestRateStrategyAddress).calculateInterestRates( +- DataTypes.CalculateInterestRatesParams({ +- unbacked: reserve.unbacked, +- liquidityAdded: liquidityAdded, +- liquidityTaken: liquidityTaken, +- totalStableDebt: reserveCache.nextTotalStableDebt, +- totalVariableDebt: vars.totalVariableDebt, +- averageStableBorrowRate: reserveCache.nextAvgStableBorrowRate, +- reserveFactor: reserveCache.reserveFactor, +- reserve: reserveAddress, +- usingVirtualBalance: reserve.configuration.getIsVirtualAccActive(), +- virtualUnderlyingBalance: reserve.virtualUnderlyingBalance +- }) +- ); ++ (uint256 nextLiquidityRate, uint256 nextVariableRate) = IReserveInterestRateStrategy( ++ reserve.interestRateStrategyAddress ++ ).calculateInterestRates( ++ DataTypes.CalculateInterestRatesParams({ ++ unbacked: reserve.unbacked, ++ liquidityAdded: liquidityAdded, ++ liquidityTaken: liquidityTaken, ++ totalDebt: totalVariableDebt, ++ reserveFactor: reserveCache.reserveFactor, ++ reserve: reserveAddress, ++ usingVirtualBalance: reserve.configuration.getIsVirtualAccActive(), ++ virtualUnderlyingBalance: reserve.virtualUnderlyingBalance ++ }) ++ ); + +- reserve.currentLiquidityRate = vars.nextLiquidityRate.toUint128(); +- reserve.currentStableBorrowRate = vars.nextStableRate.toUint128(); +- reserve.currentVariableBorrowRate = vars.nextVariableRate.toUint128(); ++ reserve.currentLiquidityRate = nextLiquidityRate.toUint128(); ++ reserve.currentVariableBorrowRate = nextVariableRate.toUint128(); + + // Only affect virtual balance if the reserve uses it + if (reserve.configuration.getIsVirtualAccActive()) { +@@ -5321,23 +5078,14 @@ library ReserveLogic { + + emit ReserveDataUpdated( + reserveAddress, +- vars.nextLiquidityRate, +- vars.nextStableRate, +- vars.nextVariableRate, ++ nextLiquidityRate, ++ 0, ++ nextVariableRate, + reserveCache.nextLiquidityIndex, + reserveCache.nextVariableBorrowIndex + ); + } + +- struct AccrueToTreasuryLocalVars { +- uint256 prevTotalStableDebt; +- uint256 prevTotalVariableDebt; +- uint256 currTotalVariableDebt; +- uint256 cumulatedStableInterest; +- uint256 totalDebtAccrued; +- uint256 amountToMint; +- } +- + /** + * @notice Mints part of the repaid interest to the reserve treasury as a function of the reserve factor for the + * specific asset. +@@ -5348,47 +5096,27 @@ library ReserveLogic { + DataTypes.ReserveData storage reserve, + DataTypes.ReserveCache memory reserveCache + ) internal { +- AccrueToTreasuryLocalVars memory vars; +- + if (reserveCache.reserveFactor == 0) { + return; + } + + //calculate the total variable debt at moment of the last interaction +- vars.prevTotalVariableDebt = reserveCache.currScaledVariableDebt.rayMul( ++ uint256 prevTotalVariableDebt = reserveCache.currScaledVariableDebt.rayMul( + reserveCache.currVariableBorrowIndex + ); + + //calculate the new total variable debt after accumulation of the interest on the index +- vars.currTotalVariableDebt = reserveCache.currScaledVariableDebt.rayMul( ++ uint256 currTotalVariableDebt = reserveCache.currScaledVariableDebt.rayMul( + reserveCache.nextVariableBorrowIndex + ); + +- //calculate the stable debt until the last timestamp update +- vars.cumulatedStableInterest = MathUtils.calculateCompoundedInterest( +- reserveCache.currAvgStableBorrowRate, +- reserveCache.stableDebtLastUpdateTimestamp, +- reserveCache.reserveLastUpdateTimestamp +- ); ++ //debt accrued is the sum of the current debt minus the sum of the debt at the last update ++ uint256 totalDebtAccrued = currTotalVariableDebt - prevTotalVariableDebt; + +- vars.prevTotalStableDebt = reserveCache.currPrincipalStableDebt.rayMul( +- vars.cumulatedStableInterest +- ); ++ uint256 amountToMint = totalDebtAccrued.percentMul(reserveCache.reserveFactor); + +- //debt accrued is the sum of the current debt minus the sum of the debt at the last update +- vars.totalDebtAccrued = +- vars.currTotalVariableDebt + +- reserveCache.currTotalStableDebt - +- vars.prevTotalVariableDebt - +- vars.prevTotalStableDebt; +- +- vars.amountToMint = vars.totalDebtAccrued.percentMul(reserveCache.reserveFactor); +- +- if (vars.amountToMint != 0) { +- reserve.accruedToTreasury += vars +- .amountToMint +- .rayDiv(reserveCache.nextLiquidityIndex) +- .toUint128(); ++ if (amountToMint != 0) { ++ reserve.accruedToTreasury += amountToMint.rayDiv(reserveCache.nextLiquidityIndex).toUint128(); + } + } + +@@ -5451,7 +5179,6 @@ library ReserveLogic { + reserveCache.currVariableBorrowRate = reserve.currentVariableBorrowRate; + + reserveCache.aTokenAddress = reserve.aTokenAddress; +- reserveCache.stableDebtTokenAddress = reserve.stableDebtTokenAddress; + reserveCache.variableDebtTokenAddress = reserve.variableDebtTokenAddress; + + reserveCache.reserveLastUpdateTimestamp = reserve.lastUpdateTimestamp; +@@ -5460,23 +5187,11 @@ library ReserveLogic { + reserveCache.variableDebtTokenAddress + ).scaledTotalSupply(); + +- ( +- reserveCache.currPrincipalStableDebt, +- reserveCache.currTotalStableDebt, +- reserveCache.currAvgStableBorrowRate, +- reserveCache.stableDebtLastUpdateTimestamp +- ) = IStableDebtToken(reserveCache.stableDebtTokenAddress).getSupplyData(); +- +- // by default the actions are considered as not affecting the debt balances. +- // if the action involves mint/burn of debt, the cache needs to be updated +- reserveCache.nextTotalStableDebt = reserveCache.currTotalStableDebt; +- reserveCache.nextAvgStableBorrowRate = reserveCache.currAvgStableBorrowRate; +- + return reserveCache; + } + } + +-// src/core/contracts/protocol/pool/PoolStorage.sol ++// src/contracts/protocol/pool/PoolStorage.sol + + /** + * @title PoolStorage +@@ -5515,14 +5230,14 @@ contract PoolStorage { + // FlashLoan premium paid to protocol treasury, expressed in bps + uint128 internal _flashLoanPremiumToProtocol; + +- // Available liquidity that can be borrowed at once at stable rate, expressed in bps +- uint64 internal _maxStableRateBorrowSizePercent; ++ // DEPRECATED on v3.2.0 ++ uint64 internal __DEPRECATED_maxStableRateBorrowSizePercent; + + // Maximum number of active reserves there have been in the protocol. It is the upper bound of the reserves list + uint16 internal _reservesCount; + } + +-// src/core/contracts/protocol/libraries/logic/EModeLogic.sol ++// src/contracts/protocol/libraries/logic/EModeLogic.sol + + /** + * @title EModeLogic library +@@ -5559,71 +5274,32 @@ library EModeLogic { + DataTypes.UserConfigurationMap storage userConfig, + DataTypes.ExecuteSetUserEModeParams memory params + ) external { ++ if (usersEModeCategory[msg.sender] == params.categoryId) return; ++ + ValidationLogic.validateSetUserEMode( +- reservesData, +- reservesList, + eModeCategories, + userConfig, + params.reservesCount, + params.categoryId + ); + +- uint8 prevCategoryId = usersEModeCategory[msg.sender]; + usersEModeCategory[msg.sender] = params.categoryId; + +- if (prevCategoryId != 0) { +- ValidationLogic.validateHealthFactor( +- reservesData, +- reservesList, +- eModeCategories, +- userConfig, +- msg.sender, +- params.categoryId, +- params.reservesCount, +- params.oracle +- ); +- } ++ ValidationLogic.validateHealthFactor( ++ reservesData, ++ reservesList, ++ eModeCategories, ++ userConfig, ++ msg.sender, ++ params.categoryId, ++ params.reservesCount, ++ params.oracle ++ ); + emit UserEModeSet(msg.sender, params.categoryId); + } +- +- /** +- * @notice Gets the eMode configuration and calculates the eMode asset price if a custom oracle is configured +- * @dev The eMode asset price returned is 0 if no oracle is specified +- * @param category The user eMode category +- * @param oracle The price oracle +- * @return The eMode ltv +- * @return The eMode liquidation threshold +- * @return The eMode asset price +- */ +- function getEModeConfiguration( +- DataTypes.EModeCategory storage category, +- IPriceOracleGetter oracle +- ) internal view returns (uint256, uint256, uint256) { +- uint256 eModeAssetPrice = 0; +- address eModePriceSource = category.priceSource; +- +- if (eModePriceSource != address(0)) { +- eModeAssetPrice = oracle.getAssetPrice(eModePriceSource); +- } +- +- return (category.ltv, category.liquidationThreshold, eModeAssetPrice); +- } +- +- /** +- * @notice Checks if eMode is active for a user and if yes, if the asset belongs to the eMode category chosen +- * @param eModeUserCategory The user eMode category +- * @param eModeAssetCategory The asset eMode category +- * @return True if eMode is active and the asset belongs to the eMode category chosen by the user, false otherwise +- */ +- function isInEModeCategory( +- uint256 eModeUserCategory, +- uint256 eModeAssetCategory +- ) internal pure returns (bool) { +- return (eModeUserCategory != 0 && eModeAssetCategory == eModeUserCategory); +- } + } + +-// src/core/contracts/protocol/libraries/logic/GenericLogic.sol ++// src/contracts/protocol/libraries/logic/GenericLogic.sol + + /** + * @title GenericLogic library +@@ -5650,10 +5326,8 @@ library GenericLogic { + uint256 totalDebtInBaseCurrency; + uint256 avgLtv; + uint256 avgLiquidationThreshold; +- uint256 eModeAssetPrice; + uint256 eModeLtv; + uint256 eModeLiqThreshold; +- uint256 eModeAssetCategory; + address currentReserveAddress; + bool hasZeroLtvCollateral; + bool isInEModeCategory; +@@ -5687,11 +5361,8 @@ library GenericLogic { + CalculateUserAccountDataVars memory vars; + + if (params.userEModeCategory != 0) { +- (vars.eModeLtv, vars.eModeLiqThreshold, vars.eModeAssetPrice) = EModeLogic +- .getEModeConfiguration( +- eModeCategories[params.userEModeCategory], +- IPriceOracleGetter(params.oracle) +- ); ++ vars.eModeLtv = eModeCategories[params.userEModeCategory].ltv; ++ vars.eModeLiqThreshold = eModeCategories[params.userEModeCategory].liquidationThreshold; + } + + while (vars.i < params.reservesCount) { +@@ -5713,23 +5384,15 @@ library GenericLogic { + + DataTypes.ReserveData storage currentReserve = reservesData[vars.currentReserveAddress]; + +- ( +- vars.ltv, +- vars.liquidationThreshold, +- , +- vars.decimals, +- , +- vars.eModeAssetCategory +- ) = currentReserve.configuration.getParams(); ++ (vars.ltv, vars.liquidationThreshold, , vars.decimals, ) = currentReserve ++ .configuration ++ .getParams(); + + unchecked { + vars.assetUnit = 10 ** vars.decimals; + } + +- vars.assetPrice = vars.eModeAssetPrice != 0 && +- params.userEModeCategory == vars.eModeAssetCategory +- ? vars.eModeAssetPrice +- : IPriceOracleGetter(params.oracle).getAssetPrice(vars.currentReserveAddress); ++ vars.assetPrice = IPriceOracleGetter(params.oracle).getAssetPrice(vars.currentReserveAddress); + + if (vars.liquidationThreshold != 0 && params.userConfig.isUsingAsCollateral(vars.i)) { + vars.userBalanceInBaseCurrency = _getUserBalanceInBaseCurrency( +@@ -5741,10 +5404,12 @@ library GenericLogic { + + vars.totalCollateralInBaseCurrency += vars.userBalanceInBaseCurrency; + +- vars.isInEModeCategory = EModeLogic.isInEModeCategory( +- params.userEModeCategory, +- vars.eModeAssetCategory +- ); ++ vars.isInEModeCategory = ++ params.userEModeCategory != 0 && ++ EModeConfiguration.isReserveEnabledOnBitmap( ++ eModeCategories[params.userEModeCategory].collateralBitmap, ++ vars.i ++ ); + + if (vars.ltv != 0) { + vars.avgLtv += +@@ -5812,7 +5477,7 @@ library GenericLogic { + ) internal pure returns (uint256) { + uint256 availableBorrowsInBaseCurrency = totalCollateralInBaseCurrency.percentMul(ltv); + +- if (availableBorrowsInBaseCurrency < totalDebtInBaseCurrency) { ++ if (availableBorrowsInBaseCurrency <= totalDebtInBaseCurrency) { + return 0; + } + +@@ -5822,7 +5487,7 @@ library GenericLogic { + + /** + * @notice Calculates total debt of the user in the based currency used to normalize the values of the assets +- * @dev This fetches the `balanceOf` of the stable and variable debt tokens for the user. For gas reasons, the ++ * @dev This fetches the `balanceOf` of the variable debt token for the user. For gas reasons, the + * variable debt balance is calculated by fetching `scaledBalancesOf` normalized debt, which is cheaper than + * fetching `balanceOf` + * @param user The address of the user +@@ -5841,14 +5506,11 @@ library GenericLogic { + uint256 userTotalDebt = IScaledBalanceToken(reserve.variableDebtTokenAddress).scaledBalanceOf( + user + ); +- if (userTotalDebt != 0) { +- userTotalDebt = userTotalDebt.rayMul(reserve.getNormalizedDebt()); ++ if (userTotalDebt == 0) { ++ return 0; + } + +- userTotalDebt = userTotalDebt + IERC20(reserve.stableDebtTokenAddress).balanceOf(user); +- +- userTotalDebt = assetPrice * userTotalDebt; +- ++ userTotalDebt = userTotalDebt.rayMul(reserve.getNormalizedDebt()) * assetPrice; + unchecked { + return userTotalDebt / assetUnit; + } +@@ -5881,7 +5543,7 @@ library GenericLogic { + } + } + +-// src/core/contracts/protocol/libraries/logic/ValidationLogic.sol ++// src/contracts/protocol/libraries/logic/ValidationLogic.sol + + /** + * @title ReserveLogic library +@@ -5931,9 +5593,7 @@ library ValidationLogic { + ) internal view { + require(amount != 0, Errors.INVALID_AMOUNT); + +- (bool isActive, bool isFrozen, , , bool isPaused) = reserveCache +- .reserveConfiguration +- .getFlags(); ++ (bool isActive, bool isFrozen, , bool isPaused) = reserveCache.reserveConfiguration.getFlags(); + require(isActive, Errors.RESERVE_INACTIVE); + require(!isPaused, Errors.RESERVE_PAUSED); + require(!isFrozen, Errors.RESERVE_FROZEN); +@@ -5963,7 +5623,7 @@ library ValidationLogic { + require(amount != 0, Errors.INVALID_AMOUNT); + require(amount <= userBalance, Errors.NOT_ENOUGH_AVAILABLE_USER_BALANCE); + +- (bool isActive, , , , bool isPaused) = reserveCache.reserveConfiguration.getFlags(); ++ (bool isActive, , , bool isPaused) = reserveCache.reserveConfiguration.getFlags(); + require(isActive, Errors.RESERVE_INACTIVE); + require(!isPaused, Errors.RESERVE_PAUSED); + } +@@ -5981,13 +5641,11 @@ library ValidationLogic { + uint256 borrowCap; + uint256 amountInBaseCurrency; + uint256 assetUnit; +- address eModePriceSource; + address siloedBorrowingAddress; + bool isActive; + bool isFrozen; + bool isPaused; + bool borrowingEnabled; +- bool stableRateBorrowingEnabled; + bool siloedBorrowingEnabled; + } + +@@ -6008,13 +5666,10 @@ library ValidationLogic { + + ValidateBorrowLocalVars memory vars; + +- ( +- vars.isActive, +- vars.isFrozen, +- vars.borrowingEnabled, +- vars.stableRateBorrowingEnabled, +- vars.isPaused +- ) = params.reserveCache.reserveConfiguration.getFlags(); ++ (vars.isActive, vars.isFrozen, vars.borrowingEnabled, vars.isPaused) = params ++ .reserveCache ++ .reserveConfiguration ++ .getFlags(); + + require(vars.isActive, Errors.RESERVE_INACTIVE); + require(!vars.isPaused, Errors.RESERVE_PAUSED); +@@ -6034,8 +5689,7 @@ library ValidationLogic { + + //validate interest rate mode + require( +- params.interestRateMode == DataTypes.InterestRateMode.VARIABLE || +- params.interestRateMode == DataTypes.InterestRateMode.STABLE, ++ params.interestRateMode == DataTypes.InterestRateMode.VARIABLE, + Errors.INVALID_INTEREST_RATE_MODE_SELECTED + ); + +@@ -6050,10 +5704,7 @@ library ValidationLogic { + params.reserveCache.nextVariableBorrowIndex + ); + +- vars.totalDebt = +- params.reserveCache.currTotalStableDebt + +- vars.totalSupplyVariableDebt + +- params.amount; ++ vars.totalDebt = vars.totalSupplyVariableDebt + params.amount; + + unchecked { + require(vars.totalDebt <= vars.borrowCap * vars.assetUnit, Errors.BORROW_CAP_EXCEEDED); +@@ -6080,10 +5731,12 @@ library ValidationLogic { + + if (params.userEModeCategory != 0) { + require( +- params.reserveCache.reserveConfiguration.getEModeCategory() == params.userEModeCategory, +- Errors.INCONSISTENT_EMODE_CATEGORY ++ EModeConfiguration.isReserveEnabledOnBitmap( ++ eModeCategories[params.userEModeCategory].borrowableBitmap, ++ reservesData[params.asset].id ++ ), ++ Errors.NOT_BORROWABLE_IN_EMODE + ); +- vars.eModePriceSource = eModeCategories[params.userEModeCategory].priceSource; + } + + ( +@@ -6115,9 +5768,7 @@ library ValidationLogic { + ); + + vars.amountInBaseCurrency = +- IPriceOracleGetter(params.oracle).getAssetPrice( +- vars.eModePriceSource != address(0) ? vars.eModePriceSource : params.asset +- ) * ++ IPriceOracleGetter(params.oracle).getAssetPrice(params.asset) * + params.amount; + unchecked { + vars.amountInBaseCurrency /= vars.assetUnit; +@@ -6132,35 +5783,6 @@ library ValidationLogic { + Errors.COLLATERAL_CANNOT_COVER_NEW_BORROW + ); + +- /** +- * Following conditions need to be met if the user is borrowing at a stable rate: +- * 1. Reserve must be enabled for stable rate borrowing +- * 2. Users cannot borrow from the reserve if their collateral is (mostly) the same currency +- * they are borrowing, to prevent abuses. +- * 3. Users will be able to borrow only a portion of the total available liquidity +- */ +- +- if (params.interestRateMode == DataTypes.InterestRateMode.STABLE) { +- //check if the borrow mode is stable and if stable rate borrowing is enabled on this reserve +- +- require(vars.stableRateBorrowingEnabled, Errors.STABLE_BORROWING_NOT_ENABLED); +- +- require( +- !params.userConfig.isUsingAsCollateral(reservesData[params.asset].id) || +- params.reserveCache.reserveConfiguration.getLtv() == 0 || +- params.amount > IERC20(params.reserveCache.aTokenAddress).balanceOf(params.userAddress), +- Errors.COLLATERAL_SAME_AS_BORROWING_CURRENCY +- ); +- +- vars.availableLiquidity = reservesData[params.asset].virtualUnderlyingBalance; +- +- //calculate the max available loan size in stable rate mode as a percentage of the +- //available liquidity +- uint256 maxLoanSizeStable = vars.availableLiquidity.percentMul(params.maxStableLoanPercent); +- +- require(params.amount <= maxLoanSizeStable, Errors.AMOUNT_BIGGER_THAN_MAX_LOAN_SIZE_STABLE); +- } +- + if (params.userConfig.isBorrowingAny()) { + (vars.siloedBorrowingEnabled, vars.siloedBorrowingAddress) = params + .userConfig +@@ -6181,125 +5803,31 @@ library ValidationLogic { + * @notice Validates a repay action. + * @param reserveCache The cached data of the reserve + * @param amountSent The amount sent for the repayment. Can be an actual value or uint(-1) +- * @param interestRateMode The interest rate mode of the debt being repaid + * @param onBehalfOf The address of the user msg.sender is repaying for +- * @param stableDebt The borrow balance of the user +- * @param variableDebt The borrow balance of the user ++ * @param debt The borrow balance of the user + */ + function validateRepay( + DataTypes.ReserveCache memory reserveCache, + uint256 amountSent, + DataTypes.InterestRateMode interestRateMode, + address onBehalfOf, +- uint256 stableDebt, +- uint256 variableDebt ++ uint256 debt + ) internal view { + require(amountSent != 0, Errors.INVALID_AMOUNT); + require( +- amountSent != type(uint256).max || msg.sender == onBehalfOf, +- Errors.NO_EXPLICIT_AMOUNT_TO_REPAY_ON_BEHALF ++ interestRateMode == DataTypes.InterestRateMode.VARIABLE, ++ Errors.INVALID_INTEREST_RATE_MODE_SELECTED + ); +- +- (bool isActive, , , , bool isPaused) = reserveCache.reserveConfiguration.getFlags(); +- require(isActive, Errors.RESERVE_INACTIVE); +- require(!isPaused, Errors.RESERVE_PAUSED); +- + require( +- (stableDebt != 0 && interestRateMode == DataTypes.InterestRateMode.STABLE) || +- (variableDebt != 0 && interestRateMode == DataTypes.InterestRateMode.VARIABLE), +- Errors.NO_DEBT_OF_SELECTED_TYPE ++ amountSent != type(uint256).max || msg.sender == onBehalfOf, ++ Errors.NO_EXPLICIT_AMOUNT_TO_REPAY_ON_BEHALF + ); +- } + +- /** +- * @notice Validates a swap of borrow rate mode. +- * @param reserve The reserve state on which the user is swapping the rate +- * @param reserveCache The cached data of the reserve +- * @param userConfig The user reserves configuration +- * @param stableDebt The stable debt of the user +- * @param variableDebt The variable debt of the user +- * @param currentRateMode The rate mode of the debt being swapped +- */ +- function validateSwapRateMode( +- DataTypes.ReserveData storage reserve, +- DataTypes.ReserveCache memory reserveCache, +- DataTypes.UserConfigurationMap storage userConfig, +- uint256 stableDebt, +- uint256 variableDebt, +- DataTypes.InterestRateMode currentRateMode +- ) internal view { +- (bool isActive, , , bool stableRateEnabled, bool isPaused) = reserveCache +- .reserveConfiguration +- .getFlags(); +- require(isActive, Errors.RESERVE_INACTIVE); +- require(!isPaused, Errors.RESERVE_PAUSED); +- +- if (currentRateMode == DataTypes.InterestRateMode.STABLE) { +- require(stableDebt != 0, Errors.NO_OUTSTANDING_STABLE_DEBT); +- } else if (currentRateMode == DataTypes.InterestRateMode.VARIABLE) { +- require(variableDebt != 0, Errors.NO_OUTSTANDING_VARIABLE_DEBT); +- /** +- * user wants to swap to stable, before swapping we need to ensure that +- * 1. stable borrow rate is enabled on the reserve +- * 2. user is not trying to abuse the reserve by supplying +- * more collateral than he is borrowing, artificially lowering +- * the interest rate, borrowing at variable, and switching to stable +- */ +- require(stableRateEnabled, Errors.STABLE_BORROWING_NOT_ENABLED); +- +- require( +- !userConfig.isUsingAsCollateral(reserve.id) || +- reserveCache.reserveConfiguration.getLtv() == 0 || +- stableDebt + variableDebt > IERC20(reserveCache.aTokenAddress).balanceOf(msg.sender), +- Errors.COLLATERAL_SAME_AS_BORROWING_CURRENCY +- ); +- } else { +- revert(Errors.INVALID_INTEREST_RATE_MODE_SELECTED); +- } +- } +- +- /** +- * @notice Validates a stable borrow rate rebalance action. +- * @dev Rebalancing is accepted when depositors are earning <= 90% of their earnings in pure supply/demand market (variable rate only) +- * For this to be the case, there has to be quite large stable debt with an interest rate below the current variable rate. +- * @param reserve The reserve state on which the user is getting rebalanced +- * @param reserveCache The cached state of the reserve +- * @param reserveAddress The address of the reserve +- */ +- function validateRebalanceStableBorrowRate( +- DataTypes.ReserveData storage reserve, +- DataTypes.ReserveCache memory reserveCache, +- address reserveAddress +- ) internal view { +- (bool isActive, , , , bool isPaused) = reserveCache.reserveConfiguration.getFlags(); ++ (bool isActive, , , bool isPaused) = reserveCache.reserveConfiguration.getFlags(); + require(isActive, Errors.RESERVE_INACTIVE); + require(!isPaused, Errors.RESERVE_PAUSED); + +- uint256 totalDebt = IERC20(reserveCache.stableDebtTokenAddress).totalSupply() + +- IERC20(reserveCache.variableDebtTokenAddress).totalSupply(); +- +- (uint256 liquidityRateVariableDebtOnly, , ) = IReserveInterestRateStrategy( +- reserve.interestRateStrategyAddress +- ).calculateInterestRates( +- DataTypes.CalculateInterestRatesParams({ +- unbacked: reserve.unbacked, +- liquidityAdded: 0, +- liquidityTaken: 0, +- totalStableDebt: 0, +- totalVariableDebt: totalDebt, +- averageStableBorrowRate: 0, +- reserveFactor: reserveCache.reserveFactor, +- reserve: reserveAddress, +- usingVirtualBalance: reserve.configuration.getIsVirtualAccActive(), +- virtualUnderlyingBalance: reserve.virtualUnderlyingBalance +- }) +- ); +- +- require( +- reserveCache.currLiquidityRate <= +- liquidityRateVariableDebtOnly.percentMul(REBALANCE_UP_LIQUIDITY_RATE_THRESHOLD), +- Errors.INTEREST_RATE_REBALANCE_CONDITIONS_NOT_MET +- ); ++ require(debt != 0, Errors.NO_DEBT_OF_SELECTED_TYPE); + } + + /** +@@ -6313,7 +5841,7 @@ library ValidationLogic { + ) internal pure { + require(userBalance != 0, Errors.UNDERLYING_BALANCE_ZERO); + +- (bool isActive, , , , bool isPaused) = reserveCache.reserveConfiguration.getFlags(); ++ (bool isActive, , , bool isPaused) = reserveCache.reserveConfiguration.getFlags(); + require(isActive, Errors.RESERVE_INACTIVE); + require(!isPaused, Errors.RESERVE_PAUSED); + } +@@ -6380,11 +5908,11 @@ library ValidationLogic { + ) internal view { + ValidateLiquidationCallLocalVars memory vars; + +- (vars.collateralReserveActive, , , , vars.collateralReservePaused) = collateralReserve ++ (vars.collateralReserveActive, , , vars.collateralReservePaused) = collateralReserve + .configuration + .getFlags(); + +- (vars.principalReserveActive, , , , vars.principalReservePaused) = params ++ (vars.principalReserveActive, , , vars.principalReservePaused) = params + .debtReserveCache + .reserveConfiguration + .getFlags(); +@@ -6525,7 +6053,6 @@ library ValidationLogic { + ) internal view { + require(asset != address(0), Errors.ZERO_ADDRESS_NOT_VALID); + require(reserve.id != 0 || reservesList[0] == asset, Errors.ASSET_NOT_LISTED); +- require(IERC20(reserve.stableDebtTokenAddress).totalSupply() == 0, Errors.STABLE_DEBT_NOT_ZERO); + require( + IERC20(reserve.variableDebtTokenAddress).totalSupply() == 0, + Errors.VARIABLE_DEBT_SUPPLY_NOT_ZERO +@@ -6538,24 +6065,21 @@ library ValidationLogic { + + /** + * @notice Validates the action of setting efficiency mode. +- * @param reservesData The state of all the reserves +- * @param reservesList The addresses of all the active reserves + * @param eModeCategories a mapping storing configurations for all efficiency mode categories + * @param userConfig the user configuration + * @param reservesCount The total number of valid reserves + * @param categoryId The id of the category + */ + function validateSetUserEMode( +- mapping(address => DataTypes.ReserveData) storage reservesData, +- mapping(uint256 => address) storage reservesList, + mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories, + DataTypes.UserConfigurationMap memory userConfig, + uint256 reservesCount, + uint8 categoryId + ) internal view { ++ DataTypes.EModeCategory storage eModeCategory = eModeCategories[categoryId]; + // category is invalid if the liq threshold is not set + require( +- categoryId == 0 || eModeCategories[categoryId].liquidationThreshold != 0, ++ categoryId == 0 || eModeCategory.liquidationThreshold != 0, + Errors.INCONSISTENT_EMODE_CATEGORY + ); + +@@ -6570,11 +6094,9 @@ library ValidationLogic { + unchecked { + for (uint256 i = 0; i < reservesCount; i++) { + if (userConfig.isBorrowing(i)) { +- DataTypes.ReserveConfigurationMap memory configuration = reservesData[reservesList[i]] +- .configuration; + require( +- configuration.getEModeCategory() == categoryId, +- Errors.INCONSISTENT_EMODE_CATEGORY ++ EModeConfiguration.isReserveEnabledOnBitmap(eModeCategory.borrowableBitmap, i), ++ Errors.NOT_BORROWABLE_IN_EMODE + ); + } + } +@@ -6641,7 +6163,7 @@ library ValidationLogic { + } + } + +-// src/core/contracts/protocol/libraries/logic/BridgeLogic.sol ++// src/contracts/protocol/libraries/logic/BridgeLogic.sol + + library BridgeLogic { + using ReserveLogic for DataTypes.ReserveCache; +@@ -6778,7 +6300,7 @@ library BridgeLogic { + } + } + +-// src/core/contracts/protocol/libraries/logic/PoolLogic.sol ++// src/contracts/protocol/libraries/logic/PoolLogic.sol + + /** + * @title PoolLogic library +@@ -6810,7 +6332,6 @@ library PoolLogic { + require(Address.isContract(params.asset), Errors.NOT_CONTRACT); + reservesData[params.asset].init( + params.aTokenAddress, +- params.stableDebtAddress, + params.variableDebtAddress, + params.interestRateStrategyAddress + ); +@@ -6968,7 +6489,7 @@ library PoolLogic { + } + } + +-// src/core/contracts/protocol/libraries/logic/SupplyLogic.sol ++// src/contracts/protocol/libraries/logic/SupplyLogic.sol + + /** + * @title SupplyLogic library +@@ -7256,7 +6777,7 @@ library SupplyLogic { + } + } + +-// src/core/contracts/protocol/libraries/logic/BorrowLogic.sol ++// src/contracts/protocol/libraries/logic/BorrowLogic.sol + + /** + * @title BorrowLogic library +@@ -7288,12 +6809,6 @@ library BorrowLogic { + uint256 amount, + bool useATokens + ); +- event RebalanceStableBorrowRate(address indexed reserve, address indexed user); +- event SwapBorrowRateMode( +- address indexed reserve, +- address indexed user, +- DataTypes.InterestRateMode interestRateMode +- ); + event IsolationModeTotalDebtUpdated(address indexed asset, uint256 totalDebt); + event ReserveUsedAsCollateralDisabled(address indexed reserve, address indexed user); + +@@ -7337,7 +6852,6 @@ library BorrowLogic { + userAddress: params.onBehalfOf, + amount: params.amount, + interestRateMode: params.interestRateMode, +- maxStableLoanPercent: params.maxStableRateBorrowSizePercent, + reservesCount: params.reservesCount, + oracle: params.oracle, + userEModeCategory: params.userEModeCategory, +@@ -7348,27 +6862,11 @@ library BorrowLogic { + }) + ); + +- uint256 currentStableRate = 0; + bool isFirstBorrowing = false; + +- if (params.interestRateMode == DataTypes.InterestRateMode.STABLE) { +- currentStableRate = reserve.currentStableBorrowRate; +- +- ( +- isFirstBorrowing, +- reserveCache.nextTotalStableDebt, +- reserveCache.nextAvgStableBorrowRate +- ) = IStableDebtToken(reserveCache.stableDebtTokenAddress).mint( +- params.user, +- params.onBehalfOf, +- params.amount, +- currentStableRate +- ); +- } else { +- (isFirstBorrowing, reserveCache.nextScaledVariableDebt) = IVariableDebtToken( +- reserveCache.variableDebtTokenAddress +- ).mint(params.user, params.onBehalfOf, params.amount, reserveCache.nextVariableBorrowIndex); +- } ++ (isFirstBorrowing, reserveCache.nextScaledVariableDebt) = IVariableDebtToken( ++ reserveCache.variableDebtTokenAddress ++ ).mint(params.user, params.onBehalfOf, params.amount, reserveCache.nextVariableBorrowIndex); + + if (isFirstBorrowing) { + userConfig.setBorrowing(reserve.id, true); +@@ -7402,10 +6900,8 @@ library BorrowLogic { + params.user, + params.onBehalfOf, + params.amount, +- params.interestRateMode, +- params.interestRateMode == DataTypes.InterestRateMode.STABLE +- ? currentStableRate +- : reserve.currentVariableBorrowRate, ++ DataTypes.InterestRateMode.VARIABLE, ++ reserve.currentVariableBorrowRate, + params.referralCode + ); + } +@@ -7431,9 +6927,8 @@ library BorrowLogic { + DataTypes.ReserveCache memory reserveCache = reserve.cache(); + reserve.updateState(reserveCache); + +- (uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt( +- params.onBehalfOf, +- reserveCache ++ uint256 variableDebt = IERC20(reserveCache.variableDebtTokenAddress).balanceOf( ++ params.onBehalfOf + ); + + ValidationLogic.validateRepay( +@@ -7441,13 +6936,10 @@ library BorrowLogic { + params.amount, + params.interestRateMode, + params.onBehalfOf, +- stableDebt, + variableDebt + ); + +- uint256 paybackAmount = params.interestRateMode == DataTypes.InterestRateMode.STABLE +- ? stableDebt +- : variableDebt; ++ uint256 paybackAmount = variableDebt; + + // Allows a user to repay with aTokens without leaving dust from interest. + if (params.useATokens && params.amount == type(uint256).max) { +@@ -7458,15 +6950,8 @@ library BorrowLogic { + paybackAmount = params.amount; + } + +- if (params.interestRateMode == DataTypes.InterestRateMode.STABLE) { +- (reserveCache.nextTotalStableDebt, reserveCache.nextAvgStableBorrowRate) = IStableDebtToken( +- reserveCache.stableDebtTokenAddress +- ).burn(params.onBehalfOf, paybackAmount); +- } else { +- reserveCache.nextScaledVariableDebt = IVariableDebtToken( +- reserveCache.variableDebtTokenAddress +- ).burn(params.onBehalfOf, paybackAmount, reserveCache.nextVariableBorrowIndex); +- } ++ reserveCache.nextScaledVariableDebt = IVariableDebtToken(reserveCache.variableDebtTokenAddress) ++ .burn(params.onBehalfOf, paybackAmount, reserveCache.nextVariableBorrowIndex); + + reserve.updateInterestRatesAndVirtualBalance( + reserveCache, +@@ -7475,7 +6960,7 @@ library BorrowLogic { + 0 + ); + +- if (stableDebt + variableDebt - paybackAmount == 0) { ++ if (variableDebt - paybackAmount == 0) { + userConfig.setBorrowing(reserve.id, false); + } + +@@ -7512,95 +6997,9 @@ library BorrowLogic { + + return paybackAmount; + } +- +- /** +- * @notice Implements the rebalance stable borrow rate feature. In case of liquidity crunches on the protocol, stable +- * rate borrows might need to be rebalanced to bring back equilibrium between the borrow and supply APYs. +- * @dev The rules that define if a position can be rebalanced are implemented in `ValidationLogic.validateRebalanceStableBorrowRate()` +- * @dev Emits the `RebalanceStableBorrowRate()` event +- * @param reserve The state of the reserve of the asset being repaid +- * @param asset The asset of the position being rebalanced +- * @param user The user being rebalanced +- */ +- function executeRebalanceStableBorrowRate( +- DataTypes.ReserveData storage reserve, +- address asset, +- address user +- ) external { +- DataTypes.ReserveCache memory reserveCache = reserve.cache(); +- reserve.updateState(reserveCache); +- +- ValidationLogic.validateRebalanceStableBorrowRate(reserve, reserveCache, asset); +- +- IStableDebtToken stableDebtToken = IStableDebtToken(reserveCache.stableDebtTokenAddress); +- uint256 stableDebt = IERC20(address(stableDebtToken)).balanceOf(user); +- +- stableDebtToken.burn(user, stableDebt); +- +- (, reserveCache.nextTotalStableDebt, reserveCache.nextAvgStableBorrowRate) = stableDebtToken +- .mint(user, user, stableDebt, reserve.currentStableBorrowRate); +- +- reserve.updateInterestRatesAndVirtualBalance(reserveCache, asset, 0, 0); +- +- emit RebalanceStableBorrowRate(asset, user); +- } +- +- /** +- * @notice Implements the swap borrow rate feature. Borrowers can swap from variable to stable positions at any time. +- * @dev Emits the `Swap()` event +- * @param reserve The of the reserve of the asset being repaid +- * @param userConfig The user configuration mapping that tracks the supplied/borrowed assets +- * @param asset The asset of the position being swapped +- * @param user The user whose debt position is being swapped +- * @param interestRateMode The current interest rate mode of the position being swapped +- */ +- function executeSwapBorrowRateMode( +- DataTypes.ReserveData storage reserve, +- DataTypes.UserConfigurationMap storage userConfig, +- address asset, +- address user, +- DataTypes.InterestRateMode interestRateMode +- ) external { +- DataTypes.ReserveCache memory reserveCache = reserve.cache(); +- +- reserve.updateState(reserveCache); +- +- (uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt(user, reserveCache); +- +- ValidationLogic.validateSwapRateMode( +- reserve, +- reserveCache, +- userConfig, +- stableDebt, +- variableDebt, +- interestRateMode +- ); +- +- if (interestRateMode == DataTypes.InterestRateMode.STABLE) { +- (reserveCache.nextTotalStableDebt, reserveCache.nextAvgStableBorrowRate) = IStableDebtToken( +- reserveCache.stableDebtTokenAddress +- ).burn(user, stableDebt); +- +- (, reserveCache.nextScaledVariableDebt) = IVariableDebtToken( +- reserveCache.variableDebtTokenAddress +- ).mint(user, user, stableDebt, reserveCache.nextVariableBorrowIndex); +- } else { +- reserveCache.nextScaledVariableDebt = IVariableDebtToken( +- reserveCache.variableDebtTokenAddress +- ).burn(user, variableDebt, reserveCache.nextVariableBorrowIndex); +- +- (, reserveCache.nextTotalStableDebt, reserveCache.nextAvgStableBorrowRate) = IStableDebtToken( +- reserveCache.stableDebtTokenAddress +- ).mint(user, user, variableDebt, reserve.currentStableBorrowRate); +- } +- +- reserve.updateInterestRatesAndVirtualBalance(reserveCache, asset, 0, 0); +- +- emit SwapBorrowRateMode(asset, user, interestRateMode); +- } + } + +-// src/core/contracts/protocol/libraries/logic/LiquidationLogic.sol ++// src/contracts/protocol/libraries/logic/LiquidationLogic.sol + + /** + * @title LiquidationLogic library +@@ -7652,15 +7051,12 @@ library LiquidationLogic { + + struct LiquidationCallLocalVars { + uint256 userCollateralBalance; +- uint256 userVariableDebt; + uint256 userTotalDebt; + uint256 actualDebtToLiquidate; + uint256 actualCollateralToLiquidate; + uint256 liquidationBonus; + uint256 healthFactor; + uint256 liquidationProtocolFeeAmount; +- address collateralPriceSource; +- address debtPriceSource; + IAToken collateralAToken; + DataTypes.ReserveCache debtReserveCache; + } +@@ -7704,7 +7100,7 @@ library LiquidationLogic { + }) + ); + +- (vars.userVariableDebt, vars.userTotalDebt, vars.actualDebtToLiquidate) = _calculateDebt( ++ (vars.userTotalDebt, vars.actualDebtToLiquidate) = _calculateDebt( + vars.debtReserveCache, + params, + vars.healthFactor +@@ -7722,12 +7118,18 @@ library LiquidationLogic { + }) + ); + +- ( +- vars.collateralAToken, +- vars.collateralPriceSource, +- vars.debtPriceSource, +- vars.liquidationBonus +- ) = _getConfigurationData(eModeCategories, collateralReserve, params); ++ vars.collateralAToken = IAToken(collateralReserve.aTokenAddress); ++ if ( ++ params.userEModeCategory != 0 && ++ EModeConfiguration.isReserveEnabledOnBitmap( ++ eModeCategories[params.userEModeCategory].collateralBitmap, ++ collateralReserve.id ++ ) ++ ) { ++ vars.liquidationBonus = eModeCategories[params.userEModeCategory].liquidationBonus; ++ } else { ++ vars.liquidationBonus = collateralReserve.configuration.getLiquidationBonus(); ++ } + + vars.userCollateralBalance = vars.collateralAToken.balanceOf(params.user); + +@@ -7738,8 +7140,8 @@ library LiquidationLogic { + ) = _calculateAvailableCollateralToLiquidate( + collateralReserve, + vars.debtReserveCache, +- vars.collateralPriceSource, +- vars.debtPriceSource, ++ params.collateralAsset, ++ params.debtAsset, + vars.actualDebtToLiquidate, + vars.userCollateralBalance, + vars.liquidationBonus, +@@ -7908,29 +7310,9 @@ library LiquidationLogic { + DataTypes.ExecuteLiquidationCallParams memory params, + LiquidationCallLocalVars memory vars + ) internal { +- if (vars.userVariableDebt >= vars.actualDebtToLiquidate) { +- vars.debtReserveCache.nextScaledVariableDebt = IVariableDebtToken( +- vars.debtReserveCache.variableDebtTokenAddress +- ).burn( +- params.user, +- vars.actualDebtToLiquidate, +- vars.debtReserveCache.nextVariableBorrowIndex +- ); +- } else { +- // If the user doesn't have variable debt, no need to try to burn variable debt tokens +- if (vars.userVariableDebt != 0) { +- vars.debtReserveCache.nextScaledVariableDebt = IVariableDebtToken( +- vars.debtReserveCache.variableDebtTokenAddress +- ).burn(params.user, vars.userVariableDebt, vars.debtReserveCache.nextVariableBorrowIndex); +- } +- ( +- vars.debtReserveCache.nextTotalStableDebt, +- vars.debtReserveCache.nextAvgStableBorrowRate +- ) = IStableDebtToken(vars.debtReserveCache.stableDebtTokenAddress).burn( +- params.user, +- vars.actualDebtToLiquidate - vars.userVariableDebt +- ); +- } ++ vars.debtReserveCache.nextScaledVariableDebt = IVariableDebtToken( ++ vars.debtReserveCache.variableDebtTokenAddress ++ ).burn(params.user, vars.actualDebtToLiquidate, vars.debtReserveCache.nextVariableBorrowIndex); + } + + /** +@@ -7940,7 +7322,6 @@ library LiquidationLogic { + * @param debtReserveCache The reserve cache data object of the debt reserve + * @param params The additional parameters needed to execute the liquidation function + * @param healthFactor The health factor of the position +- * @return The variable debt of the user + * @return The total debt of the user + * @return The actual debt to liquidate as a function of the closeFactor + */ +@@ -7948,71 +7329,22 @@ library LiquidationLogic { + DataTypes.ReserveCache memory debtReserveCache, + DataTypes.ExecuteLiquidationCallParams memory params, + uint256 healthFactor +- ) internal view returns (uint256, uint256, uint256) { +- (uint256 userStableDebt, uint256 userVariableDebt) = Helpers.getUserCurrentDebt( +- params.user, +- debtReserveCache ++ ) internal view returns (uint256, uint256) { ++ uint256 userVariableDebt = IERC20(debtReserveCache.variableDebtTokenAddress).balanceOf( ++ params.user + ); + +- uint256 userTotalDebt = userStableDebt + userVariableDebt; +- + uint256 closeFactor = healthFactor > CLOSE_FACTOR_HF_THRESHOLD + ? DEFAULT_LIQUIDATION_CLOSE_FACTOR + : MAX_LIQUIDATION_CLOSE_FACTOR; + +- uint256 maxLiquidatableDebt = userTotalDebt.percentMul(closeFactor); ++ uint256 maxLiquidatableDebt = userVariableDebt.percentMul(closeFactor); + + uint256 actualDebtToLiquidate = params.debtToCover > maxLiquidatableDebt + ? maxLiquidatableDebt + : params.debtToCover; + +- return (userVariableDebt, userTotalDebt, actualDebtToLiquidate); +- } +- +- /** +- * @notice Returns the configuration data for the debt and the collateral reserves. +- * @param eModeCategories The configuration of all the efficiency mode categories +- * @param collateralReserve The data of the collateral reserve +- * @param params The additional parameters needed to execute the liquidation function +- * @return The collateral aToken +- * @return The address to use as price source for the collateral +- * @return The address to use as price source for the debt +- * @return The liquidation bonus to apply to the collateral +- */ +- function _getConfigurationData( +- mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories, +- DataTypes.ReserveData storage collateralReserve, +- DataTypes.ExecuteLiquidationCallParams memory params +- ) internal view returns (IAToken, address, address, uint256) { +- IAToken collateralAToken = IAToken(collateralReserve.aTokenAddress); +- uint256 liquidationBonus = collateralReserve.configuration.getLiquidationBonus(); +- +- address collateralPriceSource = params.collateralAsset; +- address debtPriceSource = params.debtAsset; +- +- if (params.userEModeCategory != 0) { +- address eModePriceSource = eModeCategories[params.userEModeCategory].priceSource; +- +- if ( +- EModeLogic.isInEModeCategory( +- params.userEModeCategory, +- collateralReserve.configuration.getEModeCategory() +- ) +- ) { +- liquidationBonus = eModeCategories[params.userEModeCategory].liquidationBonus; +- +- if (eModePriceSource != address(0)) { +- collateralPriceSource = eModePriceSource; +- } +- } +- +- // when in eMode, debt will always be in the same eMode category, can skip matching category check +- if (eModePriceSource != address(0)) { +- debtPriceSource = eModePriceSource; +- } +- } +- +- return (collateralAToken, collateralPriceSource, debtPriceSource, liquidationBonus); ++ return (userVariableDebt, actualDebtToLiquidate); + } + + struct AvailableCollateralToLiquidateLocalVars { +@@ -8110,7 +7442,7 @@ library LiquidationLogic { + } + } + +-// src/core/contracts/protocol/libraries/logic/FlashLoanLogic.sol ++// src/contracts/protocol/libraries/logic/FlashLoanLogic.sol + + /** + * @title FlashLoanLogic library +@@ -8140,7 +7472,6 @@ library FlashLoanLogic { + // Helper struct for internal variables used in the `executeFlashLoan` function + struct FlashLoanLocalVars { + IFlashLoanReceiver receiver; +- uint256 i; + address currentAsset; + uint256 currentAmount; + uint256[] totalPremiums; +@@ -8183,20 +7514,18 @@ library FlashLoanLogic { + ? (0, 0) + : (params.flashLoanPremiumTotal, params.flashLoanPremiumToProtocol); + +- for (vars.i = 0; vars.i < params.assets.length; vars.i++) { +- vars.currentAmount = params.amounts[vars.i]; +- vars.totalPremiums[vars.i] = DataTypes.InterestRateMode(params.interestRateModes[vars.i]) == ++ for (uint256 i = 0; i < params.assets.length; i++) { ++ vars.currentAmount = params.amounts[i]; ++ vars.totalPremiums[i] = DataTypes.InterestRateMode(params.interestRateModes[i]) == + DataTypes.InterestRateMode.NONE + ? vars.currentAmount.percentMul(vars.flashloanPremiumTotal) + : 0; + +- if (reservesData[params.assets[vars.i]].configuration.getIsVirtualAccActive()) { +- reservesData[params.assets[vars.i]].virtualUnderlyingBalance -= vars +- .currentAmount +- .toUint128(); ++ if (reservesData[params.assets[i]].configuration.getIsVirtualAccActive()) { ++ reservesData[params.assets[i]].virtualUnderlyingBalance -= vars.currentAmount.toUint128(); + } + +- IAToken(reservesData[params.assets[vars.i]].aTokenAddress).transferUnderlyingTo( ++ IAToken(reservesData[params.assets[i]].aTokenAddress).transferUnderlyingTo( + params.receiverAddress, + vars.currentAmount + ); +@@ -8213,13 +7542,12 @@ library FlashLoanLogic { + Errors.INVALID_FLASHLOAN_EXECUTOR_RETURN + ); + +- for (vars.i = 0; vars.i < params.assets.length; vars.i++) { +- vars.currentAsset = params.assets[vars.i]; +- vars.currentAmount = params.amounts[vars.i]; ++ for (uint256 i = 0; i < params.assets.length; i++) { ++ vars.currentAsset = params.assets[i]; ++ vars.currentAmount = params.amounts[i]; + + if ( +- DataTypes.InterestRateMode(params.interestRateModes[vars.i]) == +- DataTypes.InterestRateMode.NONE ++ DataTypes.InterestRateMode(params.interestRateModes[i]) == DataTypes.InterestRateMode.NONE + ) { + _handleFlashLoanRepayment( + reservesData[vars.currentAsset], +@@ -8227,7 +7555,7 @@ library FlashLoanLogic { + asset: vars.currentAsset, + receiverAddress: params.receiverAddress, + amount: vars.currentAmount, +- totalPremium: vars.totalPremiums[vars.i], ++ totalPremium: vars.totalPremiums[i], + flashLoanPremiumToProtocol: vars.flashloanPremiumToProtocol, + referralCode: params.referralCode + }) +@@ -8245,11 +7573,9 @@ library FlashLoanLogic { + user: msg.sender, + onBehalfOf: params.onBehalfOf, + amount: vars.currentAmount, +- interestRateMode: DataTypes.InterestRateMode(params.interestRateModes[vars.i]), ++ interestRateMode: DataTypes.InterestRateMode(params.interestRateModes[i]), + referralCode: params.referralCode, + releaseUnderlying: false, +- maxStableRateBorrowSizePercent: IPool(params.pool) +- .MAX_STABLE_RATE_BORROW_SIZE_PERCENT(), + reservesCount: IPool(params.pool).getReservesCount(), + oracle: IPoolAddressesProvider(params.addressesProvider).getPriceOracle(), + userEModeCategory: IPool(params.pool).getUserEMode(params.onBehalfOf).toUint8(), +@@ -8263,7 +7589,7 @@ library FlashLoanLogic { + msg.sender, + vars.currentAsset, + vars.currentAmount, +- DataTypes.InterestRateMode(params.interestRateModes[vars.i]), ++ DataTypes.InterestRateMode(params.interestRateModes[i]), + 0, + params.referralCode + ); +@@ -8369,14 +7695,14 @@ library FlashLoanLogic { + msg.sender, + params.asset, + params.amount, +- DataTypes.InterestRateMode(0), ++ DataTypes.InterestRateMode.NONE, + params.totalPremium, + params.referralCode + ); + } + } + +-// src/core/contracts/protocol/pool/Pool.sol ++// src/contracts/protocol/pool/Pool.sol + + /** + * @title Pool contract +@@ -8387,8 +7713,7 @@ library FlashLoanLogic { + * # Withdraw + * # Borrow + * # Repay +- * # Swap their loans between variable and stable rate +- * # Enable/disable their supplied assets as collateral rebalance stable rate borrow positions ++ * # Enable/disable their supplied assets as collateral + * # Liquidate positions + * # Execute Flash Loans + * @dev To be covered by a proxy contract, owned by the PoolAddressesProvider of the specific market +@@ -8589,7 +7914,6 @@ abstract contract Pool is VersionedInitializable, PoolStorage, IPool { + interestRateMode: DataTypes.InterestRateMode(interestRateMode), + referralCode: referralCode, + releaseUnderlying: true, +- maxStableRateBorrowSizePercent: _maxStableRateBorrowSizePercent, + reservesCount: _reservesCount, + oracle: ADDRESSES_PROVIDER.getPriceOracle(), + userEModeCategory: _usersEModeCategory[onBehalfOf], +@@ -8676,33 +8000,6 @@ abstract contract Pool is VersionedInitializable, PoolStorage, IPool { + ); + } + +- /// @inheritdoc IPool +- function swapBorrowRateMode(address asset, uint256 interestRateMode) public virtual override { +- BorrowLogic.executeSwapBorrowRateMode( +- _reserves[asset], +- _usersConfig[msg.sender], +- asset, +- msg.sender, +- DataTypes.InterestRateMode(interestRateMode) +- ); +- } +- +- /// @inheritdoc IPool +- function swapToVariable(address asset, address user) public virtual override { +- BorrowLogic.executeSwapBorrowRateMode( +- _reserves[asset], +- _usersConfig[user], +- asset, +- user, +- DataTypes.InterestRateMode.STABLE +- ); +- } +- +- /// @inheritdoc IPool +- function rebalanceStableBorrowRate(address asset, address user) public virtual override { +- BorrowLogic.executeRebalanceStableBorrowRate(_reserves[asset], asset, user); +- } +- + /// @inheritdoc IPool + function setUserUseReserveAsCollateral( + address asset, +@@ -8768,7 +8065,6 @@ abstract contract Pool is VersionedInitializable, PoolStorage, IPool { + referralCode: referralCode, + flashLoanPremiumToProtocol: _flashLoanPremiumToProtocol, + flashLoanPremiumTotal: _flashLoanPremiumTotal, +- maxStableRateBorrowSizePercent: _maxStableRateBorrowSizePercent, + reservesCount: _reservesCount, + addressesProvider: address(ADDRESSES_PROVIDER), + pool: address(this), +@@ -8831,11 +8127,9 @@ abstract contract Pool is VersionedInitializable, PoolStorage, IPool { + res.currentLiquidityRate = reserve.currentLiquidityRate; + res.variableBorrowIndex = reserve.variableBorrowIndex; + res.currentVariableBorrowRate = reserve.currentVariableBorrowRate; +- res.currentStableBorrowRate = reserve.currentStableBorrowRate; + res.lastUpdateTimestamp = reserve.lastUpdateTimestamp; + res.id = reserve.id; + res.aTokenAddress = reserve.aTokenAddress; +- res.stableDebtTokenAddress = reserve.stableDebtTokenAddress; + res.variableDebtTokenAddress = reserve.variableDebtTokenAddress; + res.interestRateStrategyAddress = reserve.interestRateStrategyAddress; + res.accruedToTreasury = reserve.accruedToTreasury; +@@ -8942,11 +8236,6 @@ abstract contract Pool is VersionedInitializable, PoolStorage, IPool { + return _reservesList[id]; + } + +- /// @inheritdoc IPool +- function MAX_STABLE_RATE_BORROW_SIZE_PERCENT() public view virtual override returns (uint256) { +- return _maxStableRateBorrowSizePercent; +- } +- + /// @inheritdoc IPool + function BRIDGE_PROTOCOL_FEE() public view virtual override returns (uint256) { + return _bridgeProtocolFee; +@@ -9000,7 +8289,6 @@ abstract contract Pool is VersionedInitializable, PoolStorage, IPool { + function initReserve( + address asset, + address aTokenAddress, +- address stableDebtAddress, + address variableDebtAddress, + address interestRateStrategyAddress + ) external virtual override onlyPoolConfigurator { +@@ -9011,7 +8299,6 @@ abstract contract Pool is VersionedInitializable, PoolStorage, IPool { + DataTypes.InitReserveParams({ + asset: asset, + aTokenAddress: aTokenAddress, +- stableDebtAddress: stableDebtAddress, + variableDebtAddress: variableDebtAddress, + interestRateStrategyAddress: interestRateStrategyAddress, + reservesCount: _reservesCount, +@@ -9084,18 +8371,76 @@ abstract contract Pool is VersionedInitializable, PoolStorage, IPool { + /// @inheritdoc IPool + function configureEModeCategory( + uint8 id, +- DataTypes.EModeCategory memory category ++ DataTypes.EModeCategoryBaseConfiguration memory category ++ ) external virtual override onlyPoolConfigurator { ++ // category 0 is reserved for volatile heterogeneous assets and it's always disabled ++ require(id != 0, Errors.EMODE_CATEGORY_RESERVED); ++ _eModeCategories[id].ltv = category.ltv; ++ _eModeCategories[id].liquidationThreshold = category.liquidationThreshold; ++ _eModeCategories[id].liquidationBonus = category.liquidationBonus; ++ _eModeCategories[id].label = category.label; ++ } ++ ++ /// @inheritdoc IPool ++ function configureEModeCategoryCollateralBitmap( ++ uint8 id, ++ uint128 collateralBitmap ++ ) external virtual override onlyPoolConfigurator { ++ // category 0 is reserved for volatile heterogeneous assets and it's always disabled ++ require(id != 0, Errors.EMODE_CATEGORY_RESERVED); ++ _eModeCategories[id].collateralBitmap = collateralBitmap; ++ } ++ ++ /// @inheritdoc IPool ++ function configureEModeCategoryBorrowableBitmap( ++ uint8 id, ++ uint128 borrowableBitmap + ) external virtual override onlyPoolConfigurator { + // category 0 is reserved for volatile heterogeneous assets and it's always disabled + require(id != 0, Errors.EMODE_CATEGORY_RESERVED); +- _eModeCategories[id] = category; ++ _eModeCategories[id].borrowableBitmap = borrowableBitmap; + } + + /// @inheritdoc IPool + function getEModeCategoryData( + uint8 id +- ) external view virtual override returns (DataTypes.EModeCategory memory) { +- return _eModeCategories[id]; ++ ) external view virtual override returns (DataTypes.EModeCategoryLegacy memory) { ++ DataTypes.EModeCategory memory category = _eModeCategories[id]; ++ return ++ DataTypes.EModeCategoryLegacy({ ++ ltv: category.ltv, ++ liquidationThreshold: category.liquidationThreshold, ++ liquidationBonus: category.liquidationBonus, ++ priceSource: address(0), ++ label: category.label ++ }); ++ } ++ ++ /// @inheritdoc IPool ++ function getEModeCategoryCollateralConfig( ++ uint8 id ++ ) external view returns (DataTypes.CollateralConfig memory) { ++ return ++ DataTypes.CollateralConfig({ ++ ltv: _eModeCategories[id].ltv, ++ liquidationThreshold: _eModeCategories[id].liquidationThreshold, ++ liquidationBonus: _eModeCategories[id].liquidationBonus ++ }); ++ } ++ ++ /// @inheritdoc IPool ++ function getEModeCategoryLabel(uint8 id) external view returns (string memory) { ++ return _eModeCategories[id].label; ++ } ++ ++ /// @inheritdoc IPool ++ function getEModeCategoryCollateralBitmap(uint8 id) external view returns (uint128) { ++ return _eModeCategories[id].collateralBitmap; ++ } ++ ++ /// @inheritdoc IPool ++ function getEModeCategoryBorrowableBitmap(uint8 id) external view returns (uint128) { ++ return _eModeCategories[id].borrowableBitmap; + } + + /// @inheritdoc IPool +@@ -9206,10 +8551,10 @@ abstract contract Pool is VersionedInitializable, PoolStorage, IPool { + } + } + +-// src/core/instances/PoolInstance.sol ++// src/contracts/instances/PoolInstance.sol + + contract PoolInstance is Pool { +- uint256 public constant POOL_REVISION = 4; ++ uint256 public constant POOL_REVISION = 5; + + constructor(IPoolAddressesProvider provider) Pool(provider) {} + +@@ -9222,7 +8567,6 @@ contract PoolInstance is Pool { + */ + function initialize(IPoolAddressesProvider provider) external virtual override initializer { + require(provider == ADDRESSES_PROVIDER, Errors.INVALID_ADDRESSES_PROVIDER); +- _maxStableRateBorrowSizePercent = 0.25e4; + } + + function getRevision() internal pure virtual override returns (uint256) { +@@ -9230,7 +8574,7 @@ contract PoolInstance is Pool { + } + } + +-// src/core/contracts/protocol/pool/L2Pool.sol ++// src/contracts/protocol/pool/L2Pool.sol + + /** + * @title L2Pool +@@ -9305,24 +8649,6 @@ abstract contract L2Pool is Pool, IL2Pool { + return repayWithATokens(asset, amount, interestRateMode); + } + +- /// @inheritdoc IL2Pool +- function swapBorrowRateMode(bytes32 args) external override { +- (address asset, uint256 interestRateMode) = CalldataLogic.decodeSwapBorrowRateModeParams( +- _reservesList, +- args +- ); +- swapBorrowRateMode(asset, interestRateMode); +- } +- +- /// @inheritdoc IL2Pool +- function rebalanceStableBorrowRate(bytes32 args) external override { +- (address asset, address user) = CalldataLogic.decodeRebalanceStableBorrowRateParams( +- _reservesList, +- args +- ); +- rebalanceStableBorrowRate(asset, user); +- } +- + /// @inheritdoc IL2Pool + function setUserUseReserveAsCollateral(bytes32 args) external override { + (address asset, bool useAsCollateral) = CalldataLogic.decodeSetUserUseReserveAsCollateralParams( +@@ -9345,7 +8671,7 @@ abstract contract L2Pool is Pool, IL2Pool { + } + } + +-// src/core/instances/L2PoolInstance.sol ++// src/contracts/instances/L2PoolInstance.sol + + contract L2PoolInstance is L2Pool, PoolInstance { + constructor(IPoolAddressesProvider provider) PoolInstance(provider) {} +``` diff --git a/changelog/3.2_3.1_gas-diff.md b/docs/3.2/3.1_3.2_gas-diff.md similarity index 100% rename from changelog/3.2_3.1_gas-diff.md rename to docs/3.2/3.1_3.2_gas-diff.md diff --git a/docs/3.2/Aave-3.2-features.md b/docs/3.2/Aave-3.2-features.md new file mode 100644 index 00000000..1e4e0492 --- /dev/null +++ b/docs/3.2/Aave-3.2-features.md @@ -0,0 +1,203 @@ +# Features + +
+ +## Deprecation of stable debt + +Currently, there is no active position with stable rate mode on any Aave instance. +As it is a deprecated feature that will not be used in the future, it is possible to remove all logic related with stable rate mode from the protocol, to increase gas efficiency and decrease code complexity. + +
+ +### Changes + +#### Core + +- Listing of new assets now does no longer instantiate a stable debt token +- It is no longer possible to upgrade stable debt tokens or do any configurator change of the stable rate via the PoolConfigurator +- All Pool functions related with stable rate mode are removed +- Usage of `getUserCurrentDebt()` (before aggregating variable + stable) is now replaced by directly querying only variable. +- Removed getters and setters of stable rate from ReserveConfiguration. The position on the bitmap is deprecated, as as stable rate is already disabled for all assets listed, with 0 value there. +- When borrowing, repaying or flash loaning (keeping debt open), ValidationLogic now enforces that the mode is variable, reverting on stable. +- Removed all logic related with stable rate mode on ValidationLogic. +- Removed deprecated ReserveStableRateBorrowing and StableDebtTokenUpgraded events on `PoolConfigurator` +- **BREAKING**: Modified DefaultReserveInterestRateStrategyV2 to only consider variable on the debt side. Breaking changes for anybody querying the strategy directly. + +#### Periphery + +- Paraswap adapters change to be consistent with pool borrow dynamics: reverting if trying to enter a stable rate position. +- Config engine (and payloads base) modified to not receive anymore input of stable rate mode, and adapted to the changes on PoolConfigurator. +- AaveProtocolDataProvider adapted to the removal of stable rate, but keeping backwards compatibility. +- UiIncentiveDataProviderV3 removing stable debt tokens data, but keeping interface compatible (returning 0 values) +- Modifications on UIPoolDataProvider to remove stable debt related logic, but keeping compatibility (returning 0 values). +- WrappedTokenGatewayV3 do not have borrowRate parameter on borrow and repay methods anymore + +
+ +### Migration guide + +For anyone directly integrating with the InterestRateStrategy the method `calculateInterestRates` will no longer return the stable rate and therefore usage must be adjusted. + +```diff +function calculateInterestRates( + DataTypes.CalculateInterestRatesParams memory params +- ) external view returns (uint256, uint256, uint256); ++ ) external view returns (uint256, uint256); +``` + +
+ +## Liquid eModes + +The new Liquid eMode feature of Aave v3.2 removes the previous constraint: **an asset listed on Aave can be eligible for different eModes, and then it only depends on the user to choose which eMode he wants to enter to.** + +For example, with liquid eModes, a possible configuration not doable before would be: + +- eMode 1, with wstETH, weETH and WETH. +- eMode 2, with wstETH and WETH. +- eMode 3, with weETH and WETH. +- eMode 4, with WETH and GHO. + +So then, user A holding the wstETH and weETH collaterals, could borrow WETH at high LTV. +User B holding only wstETH could borrow WETH at high (but different) LTV. +User C holding only weETH could similarly borrow WETH at a different LTV than the previous two eModes. +User D could have a position with WETH collateral and GHO borrowings. + +This doesn’t stop there, as more sophisticated configuration strategies could be adopted, like: + +- eMode for only WETH and stablecoins. +- eMode for onboarding less mature LSTs, without requiring them being together with all major LSTs. + +**For extra configuration flexibility, liquid eModes also allow now to flag an asset as only borrowable, only collateral, or both, in the context of an eMode.** +For example, in a hypothetic eMode with only wstETH and WETH, the normal configuration would be wstETH as only collateral and WETH as only borrowable, fully focusing on the wstETH leverage use-case. + +
+ +### Borrowable in eMode + +This feature allows configuring which assets can be borrowed in a certain eMode via a bitmask. + +- When an eMode is created no assets can be borrowed per default. Each asset has to be allowed independently. +- If an asset `borrowable` is disabled after someone has borrowed that asset, the position will remain intact, but borrow exposure cannot be increased. +- If a position has something borrowed that is not `borrowable` on eMode the position has to be repaid before being able to enter the eMode +- For an asset to be borrowable in eMode it must be borrowable outside eMode as well + +
+ +### Collateral in eModes + +This feature allows configuring an asset to be collateral in a specified eMode via a bitmap. + +- When an eMode is created no asset can be collateral per default. Each asset has to be added explicitly. +- If an asset is no eMode collateral it can still be collateral (just not with eMode LT/LTV/LB). +- For an asset to be collateral in eMode, it must be collateral outside eMode as well. + +
+ +### Removal of the eMode oracle + +The eMode oracle has never been used and there is no intention do enable one in the future. +Therefore to save some gas on storage packing, the eMode oracle has been removed. + +Note: The methods to alter configuration do not validate for an asset / eMode to exist. +This is to stay consistent with the current methods on `PoolConfigurator`, as there are multiple layers of security/risk procedures on updates to not create any issues. + +
+ +### Properties/rules + +#### General eMode rules + +- Positions can use **any** collateral while being in an eMode. The eMode LT/LTV will only apply for the ones listed as eModeCollateral for that specific eMode, while the others will use their non-eMode LT/LTV +- You can only borrow assets that are borrowable in your specific eMode`*`. +- When being liquidated (and any Health Factor calculation) the eMode LT/LB will only apply to your eMode collaterals. +- eMode = 0 is a special case, being reserved as "no eMode". No eMode rules are applied on eMode `0`. +- For an asset to be borrowable in eMode it must be borrowable outside eMode as well. +- For an asset to be collateral in eMode it must be collateral outside of eMode as well. + +`*` There is the theoretic possibility that a borrowable asset becomes unborrowable due to governance intervention. In this case, the position stays intact, but the exposure can no longer be increased. + +#### Enter/switch/leave an eMode + +For a user to be able to enter/switch an eMode: + +- The health factor of the user must be >= 1 after the switch. +- All borrowed assets must be borrowable in the new eMode. +- Leaving an eMode (switching to eMode 0) is possible as long as the health factor after leaving would not drop below 1. + +
+ +### Changelog + +#### Core + +- When entering an eMode the Health Factor now is always validated. Before, there was a skip on `0 -> n` as it was assumed that eMode LT would always be higher than non-eMode LT for all assets, which is not a constraint anymore. +- eMode creation no longer validates that all assets have LT < eMode LT as the enforcement is not necessary. +- `Pool.getEModeCategoryData` is deprecated and might be removed in a future version. +- `Pool.getEModeCategoryData().eModeOracle` will always return `address(0)` +- On `ValidationLogic.validateBorrow`, it is ensured that the asset is borrowable in the user's current eMode. +- On `ValidationLogic.validateSetUserEmode` it is ensured that the user is only borrowing assets that are borrowable in a given eMode. +- **BREAKING**: `AaveProtocolDataProvider.getReserveEModeCategory` was removed as as there no longer is a `1:1` relation between assets and eModes. +- **BREAKING**: The event `EModeAssetCategoryChanged ` will no longer be emitted, because its values would be misleading. Therefore `AssetCollateralInEModeChanged` and `AssetBorrowableInEModeChanged` have been introduced. +- **BREAKING**: `reserveConfig.getEModeCategory()` will return the current eMode, but will no longer be updated and is flagged deprecated. + +#### Periphery + +- `UiPoolDataProvider` has been altered to no longer return the eMode per asset, but exposes a new method to get all eModes. +- `ConfigEngine` eMode creation has been altered to no longer accept an eMode priceOracle. +- `ConfigEngine` listings have been altered to no longer accept an eModeCategory. +- `ConfigEngine.updateAssetsEMode` has been altered to accept a `borrowable/collateral` flag. + +
+ +### Migration guide + +For existing users, the upgrade is 100% backwards compatible and no migration or similar is required. +Entering and leaving an eMode still works via `setUserEMode(categoryId)` and `getUserEMode(address user)` like in previous versions of the protocol. + +#### Indexers + +As collateral/borrowable flags are newly introduced, two new events are being emitted instead of the current `EModeAssetCategoryChanged`: + +- `event AssetCollateralInEModeChanged(address indexed asset, uint8 categoryId, bool collateral);` +- `event AssetBorrowableInEModeChanged(address indexed asset, uint8 categoryId, bool borrowable);` + +**Note**: As part of the migration proposal, these new events will be emitted for all existing eModes & assets, so that by only listening to the new events the full state can be derived. + +#### Getters + +In aave 3.1 all eMode parameters were exposed via a single `getEModeCategoryData` getter. +When checking existing integrations, we noticed that in most cases this approach is suboptimal, given that users only rely on a subset of the data. +Therefore in addition to the **deprecated** `getEModeCategoryData` getter there are now independent getters for the respective values: + +- `getEModeCategoryCollateralConfig(categoryId)`, returning the eMode ltv,lt,lb +- `getEModeCategoryLabel(categoryId)`, returning the eMode label +- `getEModeCategoryCollateralBitmap(categoryId)`, returning the collateral bitmap +- `getEModeCategoryBorrowableBitmap(categoryId)`, returning the borrowable bitmap + +#### Identifying eModes for an asset + +In the previous version of the eModes feature it was possible to query a reserve configuration to receive its unique eMode. +This is no longer possible as there can be multiple eModes assigned to an asset. + +To identify eModes of a selected asset, there is multiple options: + +- onchain one can iterate trough eModes and select the "correct one" based on your application specific needs. + +```sol +for (uint8 i = 1; i < 255; i++) { + DataTypes.CollateralConfig memory cfg = pool.getEModeCategoryCollateralConfig(i); + // check if it is an active eMode + if (cfg.liquidationThreshold != 0) { + EModeConfiguration.isReserveEnabledOnBitmap(pool.getEModeCategoryCollateralBitmap(i), someReserveIndex); + EModeConfiguration.isReserveEnabledOnBitmap(pool.getEModeCategoryBorrowableBitmap(i), someReserveIndex); + } +} +``` + +- an offchain system could listen to `AssetCollateralInEModeChanged` & `AssetBorrowableInEModeChanged` events and feed the onchain contract with an desired categoryId + +#### Deprecations + +- `getEModeCategoryData` was deprecated and might be removed in a future version. Use `getEModeCategoryCollateralConfig`, `getEModeCategoryLabel`, `getEModeCategoryCollateralBitmap` & `getEModeCategoryBorrowableBitmap` instead. +- `getReserveDataExtended` was deprecated and might be removed in a future version. Use `getReserveData` & `getLiquidationGracePeriod` instead.