Aave V3 高级功能
1. E-Mode (效率模式)
1.1 概述
E-Mode 允许相关性资产(如稳定币之间)获得更高的资本效率:
普通模式 E-Mode (稳定币)
┌──────────────┐ ┌──────────────┐
│ LTV: 80% │ │ LTV: 97% │
│ 清算阈值: 82.5% │ ─升级──▶ │ 清算阈值: 98% │
│ 清算奖励: 5% │ │ 清算奖励: 1% │
└──────────────┘ └──────────────┘
1.2 E-Mode 类别
struct EModeCategory {
uint16 ltv; // LTV (97% = 9700)
uint16 liquidationThreshold; // 清算阈值 (98% = 9800)
uint16 liquidationBonus; // 清算奖励 (1% = 10100)
address priceSource; // 自定义价格源(可选)
string label; // 类别标签
}1.3 类别示例
| 类别 ID | 标签 | LTV | 清算阈值 | 清算奖励 | 资产 |
|---|---|---|---|---|---|
| 1 | Stablecoins | 97% | 98% | 1% | USDC, USDT, DAI |
| 2 | ETH Correlated | 93% | 95% | 1% | ETH, stETH, wstETH |
| 3 | BTC Correlated | 93% | 95% | 1% | WBTC, renBTC |
1.4 设置用户 E-Mode
// Pool.sol
function setUserEMode(uint8 categoryId) external virtual override {
EModeLogic.executeSetUserEMode(
_reserves,
_reservesList,
_eModeCategories,
_usersEModeCategory,
_usersConfig[msg.sender],
DataTypes.ExecuteSetUserEModeParams({
reservesCount: _reservesCount,
oracle: ADDRESSES_PROVIDER.getPriceOracle(),
categoryId: categoryId
})
);
}1.5 E-Mode 逻辑
// EModeLogic.sol
function executeSetUserEMode(
mapping(address => DataTypes.ReserveData) storage reservesData,
mapping(uint256 => address) storage reservesList,
mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories,
mapping(address => uint8) storage usersEModeCategory,
DataTypes.UserConfigurationMap storage userConfig,
DataTypes.ExecuteSetUserEModeParams memory params
) external {
// 验证类别存在
if (params.categoryId != 0) {
require(
eModeCategories[params.categoryId].liquidationThreshold != 0,
Errors.INCONSISTENT_EMODE_CATEGORY
);
}
uint8 prevCategoryId = usersEModeCategory[msg.sender];
if (prevCategoryId != params.categoryId) {
// 更新用户 E-Mode 类别
usersEModeCategory[msg.sender] = params.categoryId;
// 验证切换后健康因子仍然健康
if (params.categoryId != 0) {
require(
_validateEModeCategory(
reservesData,
reservesList,
eModeCategories,
userConfig,
params
),
Errors.INCONSISTENT_EMODE_CATEGORY
);
}
// 检查健康因子
(, , , , uint256 healthFactor, ) = GenericLogic.calculateUserAccountData(
reservesData,
reservesList,
eModeCategories,
DataTypes.CalculateUserAccountDataParams({
userConfig: userConfig,
reservesCount: params.reservesCount,
user: msg.sender,
oracle: params.oracle,
userEModeCategory: params.categoryId
})
);
require(
healthFactor >= HEALTH_FACTOR_LIQUIDATION_THRESHOLD,
Errors.HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD
);
}
emit UserEModeSet(msg.sender, params.categoryId);
}1.6 E-Mode 效率计算
场景:用户存入 10,000 USDC,借出 USDT
普通模式:
- 最大借贷 = 10,000 × 80% = 8,000 USDT
- 有效杠杆 = 10,000 / (10,000 - 8,000) = 5x
E-Mode (稳定币):
- 最大借贷 = 10,000 × 97% = 9,700 USDT
- 有效杠杆 = 10,000 / (10,000 - 9,700) = 33x
资本效率提升: 33x / 5x = 6.6 倍
2. Isolation Mode (隔离模式)
2.1 概述
隔离模式允许新资产在受控环境中上线,限制风险敞口:
隔离模式资产
┌────────────────────────────────────┐
│ 特点: │
│ • 只能作为唯一抵押品 │
│ • 只能借出稳定币 │
│ • 有债务上限 │
│ • 逐步提升信任度后可解除限制 │
└────────────────────────────────────┘
2.2 配置参数
struct ReserveData {
// ... 其他字段
uint128 isolationModeTotalDebt; // 当前隔离模式总债务
}
// ReserveConfiguration 中的隔离模式参数
// bit 212-251: debt ceiling (隔离模式债务上限)2.3 隔离模式检测
// UserConfiguration.sol
function getIsolationModeState(
DataTypes.UserConfigurationMap storage self,
mapping(address => DataTypes.ReserveData) storage reservesData,
mapping(uint256 => address) storage reservesList
) internal view returns (bool, address, uint256) {
// 遍历用户抵押品
if (self.isEmpty()) {
return (false, address(0), 0);
}
uint256 firstAssetId = self.getFirstAssetIdByMask(COLLATERAL_MASK);
if (reservesData[reservesList[firstAssetId]].configuration.getDebtCeiling() != 0) {
address isolationModeCollateral = reservesList[firstAssetId];
return (
true,
isolationModeCollateral,
reservesData[isolationModeCollateral].configuration.getDebtCeiling()
);
}
return (false, address(0), 0);
}2.4 隔离模式借贷限制
// ValidationLogic.sol (借贷验证)
function validateBorrow(...) internal view {
// ...
// 隔离模式检查
if (params.isolationModeActive) {
// 只允许借出标记为可在隔离模式借出的资产
require(
params.reserveCache.reserveConfiguration.getBorrowableInIsolation(),
Errors.ASSET_NOT_BORROWABLE_IN_ISOLATION
);
// 检查债务上限
require(
reservesData[params.isolationModeCollateralAddress].isolationModeTotalDebt +
(params.amount /
10 ** (params.reserveCache.reserveConfiguration.getDecimals() -
ReserveConfiguration.DEBT_CEILING_DECIMALS)) <=
params.isolationModeDebtCeiling,
Errors.DEBT_CEILING_EXCEEDED
);
}
}2.5 隔离模式示例
场景:新代币 XYZ 上线,设置为隔离模式
配置:
- XYZ 债务上限: 1,000,000 USD
- XYZ LTV: 50%
- 可借出资产: 仅 USDC, USDT, DAI
用户操作:
1. 存入 1000 XYZ (价值 $10,000)
2. 最大可借: 10,000 × 50% = 5,000 USDC
3. 无法同时使用其他抵押品
4. 无法借出非稳定币资产
3. Portal (跨链桥接)
3.1 概述
Portal 允许在不同链上铸造未支持的 aToken,实现跨链流动性:
源链 (Ethereum) 目标链 (Polygon)
┌─────────────┐ ┌─────────────┐
│ 用户资产 │ │ 用户资产 │
│ 100 USDC │ │ 0 USDC │
└─────────────┘ └─────────────┘
│ │
▼ ▼
┌─────────────┐ Portal ┌─────────────┐
│ aUSDC │ ═══════════════▶ │ aUSDC │
│ 销毁 │ (跨链消息) │ 铸造 │
└─────────────┘ └─────────────┘
3.2 Mint Unbacked
在目标链铸造未支持的 aToken:
// BridgeLogic.sol
function executeMintUnbacked(
mapping(address => DataTypes.ReserveData) storage reservesData,
mapping(uint256 => address) storage reservesList,
DataTypes.UserConfigurationMap storage userConfig,
address asset,
uint256 amount,
address onBehalfOf,
uint16 referralCode
) external {
DataTypes.ReserveData storage reserve = reservesData[asset];
DataTypes.ReserveCache memory reserveCache = reserve.cache();
reserve.updateState(reserveCache);
// 验证
ValidationLogic.validateUnbacked(reserveCache, amount, reserve);
// 增加 unbacked 计数
uint256 unbackedMintCap = reserveCache.reserveConfiguration.getUnbackedMintCap();
uint256 reserveDecimals = reserveCache.reserveConfiguration.getDecimals();
uint256 currentUnbacked = reserve.unbacked += amount.toUint128();
require(
currentUnbacked <= unbackedMintCap * (10 ** reserveDecimals),
Errors.UNBACKED_MINT_CAP_EXCEEDED
);
// 铸造 aToken
bool isFirstSupply = IAToken(reserveCache.aTokenAddress).mint(
msg.sender,
onBehalfOf,
amount,
reserveCache.nextLiquidityIndex
);
if (isFirstSupply) {
if (
ValidationLogic.validateAutomaticUseAsCollateral(
reservesData,
reservesList,
userConfig,
reserveCache.reserveConfiguration,
reserveCache.aTokenAddress
)
) {
userConfig.setUsingAsCollateral(reserve.id, true);
emit ReserveUsedAsCollateralEnabled(asset, onBehalfOf);
}
}
emit MintUnbacked(asset, msg.sender, onBehalfOf, amount, referralCode);
}3.3 Back Unbacked
在源链销毁资产,完成跨链:
function executeBackUnbacked(
DataTypes.ReserveData storage reserve,
address asset,
uint256 amount,
uint256 fee
) external returns (uint256) {
DataTypes.ReserveCache memory reserveCache = reserve.cache();
reserve.updateState(reserveCache);
// 计算实际支持金额
uint256 backingAmount = (amount < reserve.unbacked) ? amount : reserve.unbacked;
uint256 feeAmount = amount.percentMul(fee);
// 减少 unbacked 计数
reserve.unbacked -= backingAmount.toUint128();
// 累积费用到国库
reserve.accruedToTreasury += (backingAmount + feeAmount)
.rayDiv(reserveCache.nextLiquidityIndex)
.toUint128();
// 更新利率
reserve.updateInterestRates(reserveCache, asset, backingAmount + feeAmount, 0);
// 转移资产
IERC20(asset).safeTransferFrom(msg.sender, reserveCache.aTokenAddress, backingAmount + feeAmount);
emit BackUnbacked(asset, msg.sender, backingAmount, feeAmount);
return backingAmount;
}3.4 Portal 费用机制
费用 = bridgeAmount × bridgeProtocolFee
费用分配:
└── 100% → 协议国库
这笔费用补偿协议承担的跨链风险
4. Flash Loan (闪电贷)
4.1 概述
闪电贷允许在单笔交易内无抵押借贷任意金额:
单笔交易
┌──────────────────────────────────────────────┐
│ 1. 借出资产 │
│ 2. 执行自定义逻辑 │
│ 3. 归还资产 + 手续费 │
│ │
│ 如果无法归还 → 整笔交易回滚 │
└──────────────────────────────────────────────┘
4.2 闪电贷类型
| 类型 | 函数 | 特点 |
|---|---|---|
| 简单闪电贷 | flashLoanSimple | 单一资产 |
| 批量闪电贷 | flashLoan | 多资产,可选开仓 |
4.3 简单闪电贷
// FlashLoanLogic.sol
function executeFlashLoanSimple(
DataTypes.ReserveData storage reserve,
DataTypes.FlashLoanSimpleParams memory params
) external {
DataTypes.ReserveCache memory reserveCache = reserve.cache();
reserve.updateState(reserveCache);
// 验证
ValidationLogic.validateFlashloanSimple(reserveCache);
// 计算手续费
uint256 totalPremium = params.amount.percentMul(params.flashLoanPremiumTotal);
// 转移资产给借款人
IAToken(reserveCache.aTokenAddress).transferUnderlyingTo(
params.receiverAddress,
params.amount
);
// 执行用户逻辑
require(
IFlashLoanSimpleReceiver(params.receiverAddress).executeOperation(
params.asset,
params.amount,
totalPremium,
msg.sender,
params.params
),
Errors.INVALID_FLASHLOAN_EXECUTOR_RETURN
);
// 验证归还
uint256 amountPlusPremium = params.amount + totalPremium;
IERC20(params.asset).safeTransferFrom(
params.receiverAddress,
reserveCache.aTokenAddress,
amountPlusPremium
);
// 手续费分配
_handleFlashLoanRepayment(
reserve,
reserveCache,
params.flashLoanPremiumToProtocol,
totalPremium
);
emit FlashLoan(
params.receiverAddress,
msg.sender,
params.asset,
params.amount,
DataTypes.InterestRateMode.NONE,
totalPremium,
params.referralCode
);
}4.4 批量闪电贷
function executeFlashLoan(
mapping(address => DataTypes.ReserveData) storage reservesData,
mapping(uint256 => address) storage reservesList,
mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories,
mapping(address => DataTypes.UserConfigurationMap) storage usersConfig,
DataTypes.FlashLoanParams memory params
) external {
FlashLoanLocalVars memory vars;
ValidationLogic.validateFlashloan(reservesData, params.assets, params.amounts);
vars.receiver = IFlashLoanReceiver(params.receiverAddress);
// 转移所有资产给借款人
for (vars.i = 0; vars.i < params.assets.length; vars.i++) {
vars.currentAmount = params.amounts[vars.i];
vars.currentAsset = params.assets[vars.i];
vars.currentATokenAddress = reservesData[vars.currentAsset].aTokenAddress;
vars.currentPremium = params.interestRateModes[vars.i] ==
DataTypes.InterestRateMode.NONE
? vars.currentAmount.percentMul(vars.totalPremium)
: 0;
vars.flashloanPremiums[vars.i] = vars.currentPremium;
IAToken(vars.currentATokenAddress).transferUnderlyingTo(
params.receiverAddress,
vars.currentAmount
);
}
// 执行用户逻辑
require(
vars.receiver.executeOperation(
params.assets,
params.amounts,
vars.flashloanPremiums,
msg.sender,
params.params
),
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];
if (params.interestRateModes[vars.i] == DataTypes.InterestRateMode.NONE) {
// 完全归还
_handleFlashLoanRepayment(...)
} else {
// 开仓:保留借贷,创建债务头寸
BorrowLogic.executeBorrow(...)
}
}
}4.5 闪电贷接收者接口
interface IFlashLoanSimpleReceiver {
function executeOperation(
address asset,
uint256 amount,
uint256 premium,
address initiator,
bytes calldata params
) external returns (bool);
}
interface IFlashLoanReceiver {
function executeOperation(
address[] calldata assets,
uint256[] calldata amounts,
uint256[] calldata premiums,
address initiator,
bytes calldata params
) external returns (bool);
}4.6 闪电贷费用
总费用 = 借款金额 × flashLoanPremiumTotal
费用分配:
├── LP 收益 = 总费用 × (1 - protocolFee%)
└── 协议收入 = 总费用 × protocolFee%
典型参数:
- flashLoanPremiumTotal: 0.09% (9 bps)
- protocolFee: 30%
4.7 闪电贷用例
// 清算套利示例
contract FlashLiquidator is IFlashLoanSimpleReceiver {
IPool public pool;
ISwapRouter public router;
function liquidateWithFlashLoan(
address collateralAsset,
address debtAsset,
address user,
uint256 debtToCover
) external {
// 发起闪电贷借出债务资产
pool.flashLoanSimple(
address(this),
debtAsset,
debtToCover,
abi.encode(collateralAsset, user),
0
);
}
function executeOperation(
address asset,
uint256 amount,
uint256 premium,
address initiator,
bytes calldata params
) external override returns (bool) {
(address collateralAsset, address user) = abi.decode(params, (address, address));
// 批准池子使用资产
IERC20(asset).approve(address(pool), amount);
// 执行清算,获得抵押品
pool.liquidationCall(collateralAsset, asset, user, amount, false);
// 出售抵押品获得债务资产
uint256 collateralReceived = IERC20(collateralAsset).balanceOf(address(this));
IERC20(collateralAsset).approve(address(router), collateralReceived);
router.exactInputSingle(ISwapRouter.ExactInputSingleParams({
tokenIn: collateralAsset,
tokenOut: asset,
fee: 3000,
recipient: address(this),
deadline: block.timestamp,
amountIn: collateralReceived,
amountOutMinimum: amount + premium,
sqrtPriceLimitX96: 0
}));
// 批准归还
IERC20(asset).approve(address(pool), amount + premium);
return true;
}
}5. 预言机哨兵
5.1 概述
预言机哨兵用于 L2 网络,在序列器故障时保护协议:
正常状态 序列器故障
┌──────────────┐ ┌──────────────┐
│ 借贷: ✅ 允许 │ │ 借贷: ❌ 暂停 │
│ 清算: ✅ 允许 │ ───故障───▶ │ 清算: ❌ 暂停 │
└──────────────┘ └──────────────┘
5.2 实现
// PriceOracleSentinel.sol
contract PriceOracleSentinel is IPriceOracleSentinel {
ISequencerOracle public sequencerOracle;
uint256 public gracePeriod;
function isBorrowAllowed() external view override returns (bool) {
return _isUpAndGracePeriodPassed();
}
function isLiquidationAllowed() external view override returns (bool) {
return _isUpAndGracePeriodPassed();
}
function _isUpAndGracePeriodPassed() internal view returns (bool) {
(bool isSequencerUp, uint256 lastUpdateTimestamp) = sequencerOracle.latestRoundData();
// 序列器必须在线
if (!isSequencerUp) {
return false;
}
// 必须过了优雅期
if (block.timestamp - lastUpdateTimestamp < gracePeriod) {
return false;
}
return true;
}
}5.3 使用场景
Arbitrum/Optimism 等 L2 网络:
1. 序列器正常运行 → 所有操作正常
2. 序列器故障 → 借贷和清算暂停
3. 序列器恢复 → 等待优雅期(如 1 小时)
4. 优雅期结束 → 恢复正常操作
优雅期的目的:
- 让用户有时间补充抵押品
- 避免在价格不确定时被清算
6. 功能对比总结
| 功能 | 目的 | 风险/限制 |
|---|---|---|
| E-Mode | 提高相关资产资本效率 | 只能使用同类资产 |
| Isolation | 新资产安全上线 | 债务上限、单一抵押 |
| Portal | 跨链流动性 | 桥接风险、费用 |
| Flash Loan | 无抵押即时借贷 | 必须同交易归还 |
| Sentinel | L2 网络保护 | 故障时功能受限 |
7. 小结
Aave V3 的高级功能显著提升了协议的灵活性和安全性:
- E-Mode:稳定币间借贷效率提升 6 倍以上
- Isolation Mode:新资产可安全测试,逐步建立信任
- Portal:打破流动性碎片化,实现多链统一
- Flash Loan:支持复杂的 DeFi 策略和套利
- Oracle Sentinel:L2 网络额外保护层
下一章将详细讲解套利机会和 MEV 策略。