This skill should be used when the user asks about "eMode", "efficiency mode", "correlated assets", "liquid eModes", "collateralBitmap", "borrowableBitmap", "EModeCategory", or needs to understand Aave V3 Efficiency Modes.
eModes allow higher capital efficiency when borrowing correlated assets. Users in an eMode get better LTV and liquidation parameters for assets within that category.
┌──────────────────────────────────────────────────────────────┐
│ EFFICIENCY MODES │
├──────────────────────────────────────────────────────────────┤
│ │
│ eMode 0 (Default): │
│ • No special treatment │
│ • Uses standard LTV/LT per asset │
│ │
│ eMode 1 (e.g., "Stablecoins"): │
│ • Higher LTV (e.g., 97%) │
│ • Higher LT (e.g., 97.5%) │
│ • Only for correlated assets (USDC, DAI, USDT) │
│ │
│ eMode 2 (e.g., "ETH Correlated"): │
│ • Higher LTV (e.g., 93%) │
│ • For ETH and LSTs (wstETH, rETH, cbETH) │
│ │
└──────────────────────────────────────────────────────────────┘
struct EModeCategory {
uint16 ltv; // LTV for eMode collaterals
uint16 liquidationThreshold; // LT for eMode collaterals
uint16 liquidationBonus; // LB for eMode liquidations
uint128 collateralBitmap; // Which assets can be collateral in this eMode
uint128 borrowableBitmap; // Which assets can be borrowed in this eMode
string label; // Human-readable label
}
V3.2 introduced "Liquid eModes" with major improvements:
eModeCategory in config┌──────────────────────────────────────────────────────────────┐
│ LIQUID eMODES │
├──────────────────────────────────────────────────────────────┤
│ │
│ Example Configuration: │
│ │
│ eMode 1: wstETH + weETH + WETH │
│ eMode 2: wstETH + WETH only │
│ eMode 3: weETH + WETH only │
│ eMode 4: WETH + GHO │
│ │
│ User A (holds wstETH & weETH) → enters eMode 1 │
│ User B (holds only wstETH) → enters eMode 2 │
│ User C (WETH collateral, GHO borrow) → enters eMode 4 │
│ │
└──────────────────────────────────────────────────────────────┘
// Set user's eMode category
function setUserEMode(uint8 categoryId) external {
EModeLogic.executeSetUserEMode(
_reserves,
_reservesList,
_eModeCategories,
_usersEModeCategory,
_usersConfig[msg.sender],
DataTypes.ExecuteSetUserEModeParams({
reservesCount: _reservesCount,
oracle: ADDRESSES_PROVIDER.getPriceOracle(),
categoryId: categoryId
})
);
}
// Get user's current eMode
function getUserEMode(address user) external view returns (uint256);
// To enter an eMode:
// 1. Health factor must remain >= 1 after switch
// 2. All borrowed assets must be borrowable in the new eMode
// To leave an eMode (switch to 0):
// 1. Health factor must remain >= 1 after leaving
// Example validation:
function validateSetUserEMode(
mapping(address => DataTypes.ReserveData) storage reservesData,
mapping(uint256 => address) storage reservesList,
mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories,
DataTypes.UserConfigurationMap memory userConfig,
DataTypes.ExecuteSetUserEModeParams memory params
) external view {
// Check all borrowed assets are borrowable in new eMode
for each borrowed asset {
if (!EModeConfiguration.isReserveEnabledOnBitmap(
eModeCategories[params.categoryId].borrowableBitmap,
reserveId
)) {
revert(Errors.INCONSISTENT_EMODE_CATEGORY);
}
}
// Validate health factor after switch
validateHealthFactor(params.categoryId, ...);
}
// Via PoolConfigurator
function setEModeCategory(
uint8 categoryId,
uint16 ltv,
uint16 liquidationThreshold,
uint16 liquidationBonus,
string calldata label
) external onlyRiskAdmin;
// Example: Create stablecoin eMode
poolConfigurator.setEModeCategory(
1, // categoryId
9700, // LTV: 97%
9750, // LT: 97.5%
10100, // LB: 1% bonus
"Stablecoins"
);
// Set which assets can be collateral in an eMode
function setAssetCollateralInEMode(
address asset,
uint8 categoryId,
bool collateral
) external onlyRiskAdmin;
// Sets the corresponding bit in collateralBitmap
// Based on asset's reserve.id
// Set which assets can be borrowed in an eMode
function setAssetBorrowableInEMode(
address asset,
uint8 categoryId,
bool borrowable
) external onlyRiskAdmin;
// Sets the corresponding bit in borrowableBitmap
// Based on asset's reserve.id
// Get eMode collateral config (LTV, LT, LB)
function getEModeCategoryCollateralConfig(uint8 id) external view
returns (DataTypes.CollateralConfig memory);
// Get eMode label
function getEModeCategoryLabel(uint8 id) external view returns (string memory);
// Get collateral bitmap
function getEModeCategoryCollateralBitmap(uint8 id) external view returns (uint128);
// Get borrowable bitmap
function getEModeCategoryBorrowableBitmap(uint8 id) external view returns (uint128);
// DEPRECATED: Legacy getter (still works for backwards compatibility)
function getEModeCategoryData(uint8 id) external view
returns (DataTypes.EModeCategoryLegacy memory);
library EModeConfiguration {
/// @notice Check if a reserve is enabled in a bitmap
function isReserveEnabledOnBitmap(
uint128 bitmap,
uint256 reserveIndex
) internal pure returns (bool) {
return (bitmap >> reserveIndex) & 1 != 0;
}
/// @notice Set a reserve bit in a bitmap
function setReserveEnabledOnBitmap(
uint128 bitmap,
uint256 reserveIndex,
bool enabled
) internal pure returns (uint128) {
if (enabled) {
return bitmap | uint128(1 << reserveIndex);
} else {
return bitmap & ~uint128(1 << reserveIndex);
}
}
}
// In GenericLogic.calculateUserAccountData()
for each collateral asset {
if (EModeConfiguration.isReserveEnabledOnBitmap(
eModeCategories[userEModeCategory].collateralBitmap,
reserveId
)) {
// Use eMode LTV/LT
ltv = eModeCategories[userEModeCategory].ltv;
liquidationThreshold = eModeCategories[userEModeCategory].liquidationThreshold;
} else {
// Use standard asset LTV/LT
ltv = reserve.configuration.getLtv();
liquidationThreshold = reserve.configuration.getLiquidationThreshold();
}
totalCollateralBase += assetValue;
totalCollateralLTV += assetValue * ltv;
totalCollateralLT += assetValue * liquidationThreshold;
}
// Health Factor = totalCollateralLT / totalDebt
┌──────────────────────────────────────────────────────────────┐
│ eMODE RULES │
├──────────────────────────────────────────────────────────────┤
│ │
│ Collateral: │
│ • Positions can use ANY collateral in any eMode │
│ • eMode LTV/LT only applies to assets in collateralBitmap │
│ • Other collaterals use their standard LTV/LT │
│ │
│ Borrowing: │
│ • Can only borrow assets in the eMode's borrowableBitmap │
│ • For an asset to be borrowable in eMode, it must also │
│ be borrowable outside eMode │
│ │
│ Switching eModes: │
│ • Must maintain HF >= 1 after switch │
│ • All borrowed assets must be borrowable in new eMode │
│ │
│ eMode 0: │
│ • Special "no eMode" category │
│ • No eMode rules apply │
│ • All assets use standard parameters │
│ │
└──────────────────────────────────────────────────────────────┘
| eMode | Assets | Use Case |
|---|---|---|
| Stablecoins | USDC, DAI, USDT | Stablecoin arbitrage, low-risk leverage |
| ETH Correlated | WETH, wstETH, rETH | LST leverage, yield farming |
| BTC Correlated | WBTC, cbBTC | BTC exposure optimization |
// eMode category creation/update
event EModeCategoryAdded(
uint8 indexed categoryId,
uint256 ltv,
uint256 liquidationThreshold,
uint256 liquidationBonus,
string label
);
// Asset eMode configuration (V3.2+)
event AssetCollateralInEModeChanged(
address indexed asset,
uint8 categoryId,
bool collateral
);
event AssetBorrowableInEModeChanged(
address indexed asset,
uint8 categoryId,
bool borrowable
);
// User eMode change
event UserEModeSet(address indexed user, uint8 categoryId);
src/contracts/protocol/libraries/logic/EModeLogic.sol - eMode logicsrc/contracts/protocol/libraries/configuration/EModeConfiguration.sol - Bitmap utilitiessrc/contracts/protocol/libraries/logic/GenericLogic.sol - Health factor with eModessrc/contracts/protocol/pool/Pool.sol - setUserEMode, getUserEModesrc/contracts/protocol/pool/PoolConfigurator.sol - eMode configuration