Aave V3 核心概念与架构
1. 协议概述
1.1 什么是 Aave
Aave 是一个去中心化的非托管流动性协议,允许用户:
- 存款赚取利息:将资产存入流动性池,获得被动收益
- 抵押借贷:以存款作为抵押品借出其他资产
- 闪电贷:在单笔交易内无抵押借贷
1.2 V3 相对 V2 的核心升级
| 特性 | V2 | V3 | 改进 |
|---|---|---|---|
| 资本效率 | 基础 | E-Mode 提升 | 最高 97% LTV |
| 风险管理 | 统一参数 | 隔离模式 | 细粒度控制 |
| 跨链能力 | 无 | Portal 桥接 | 原生跨链 |
| Gas 消耗 | ~180k | ~150k | 降低 16%+ |
| L2 优化 | 无 | L2Pool | calldata 压缩 |
2. 整体架构设计
2.1 分层架构
┌────────────────────────────────────────────────────────────┐
│ 第一层: 用户交互层 │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ supply │ │ borrow │ │liquidate│ │flashLoan│ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
└────────────────────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────────┐
│ 第二层: 核心协调层 │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Pool.sol │ │
│ │ - 统一入口点 │ │
│ │ - 状态协调 │ │
│ │ - 权限检查 │ │
│ └──────────────────────────────────────────────────┘ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │PoolConfigurator │ │PoolAddressesProvider│ │
│ │ 配置管理器 │ │ 地址注册中心 │ │
│ └─────────────────┘ └─────────────────┘ │
└────────────────────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────────┐
│ 第三层: 业务逻辑层 │
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
│ │SupplyLogic│ │BorrowLogic│ │Liquidation│ │FlashLoan │ │
│ │ Logic │ │ Logic │ │ Logic │ │ Logic │ │
│ └───────────┘ └───────────┘ └───────────┘ └───────────┘ │
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
│ │ EModeLogic│ │BridgeLogic│ │Validation │ │GenericLogic│ │
│ │ │ │ (Portal) │ │ Logic │ │ │ │
│ └───────────┘ └───────────┘ └───────────┘ └───────────┘ │
└────────────────────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────────┐
│ 第四层: 代币化层 │
│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │
│ │ AToken │ │StableDebtToken│ │VariableDebt │ │
│ │ 存款凭证 │ │ 固定利率债务 │ │Token 浮动债务 │ │
│ └───────────────┘ └───────────────┘ └───────────────┘ │
└────────────────────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────────┐
│ 第五层: 基础设施层 │
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
│ │PriceOracle│ │InterestRate│ │DataTypes │ │WadRayMath │ │
│ │ 价格预言机 │ │ Strategy │ │ 数据结构 │ │ 数学库 │ │
│ └───────────┘ └───────────┘ └───────────┘ └───────────┘ │
└────────────────────────────────────────────────────────────┘
2.2 核心合约关系
// Pool.sol 是核心入口
contract Pool is VersionedInitializable, PoolStorage, IPool {
// 存款
function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode);
// 借贷
function borrow(address asset, uint256 amount, uint256 interestRateMode, uint16 referralCode, address onBehalfOf);
// 还款
function repay(address asset, uint256 amount, uint256 interestRateMode, address onBehalfOf);
// 清算
function liquidationCall(address collateralAsset, address debtAsset, address user, uint256 debtToCover, bool receiveAToken);
// 闪电贷
function flashLoan(address receiverAddress, address[] calldata assets, uint256[] calldata amounts, uint256[] calldata interestRateModes, address onBehalfOf, bytes calldata params, uint16 referralCode);
}3. 核心设计模式
3.1 代理模式 (Proxy Pattern)
Aave V3 使用透明代理模式实现合约可升级性:
┌─────────────────┐ ┌─────────────────┐
│ 用户调用 │───────▶│ Proxy 合约 │
└─────────────────┘ │ (存储状态) │
└────────┬────────┘
│ delegatecall
▼
┌─────────────────┐
│ Implementation │
│ (逻辑代码) │
└─────────────────┘
实现代码:
// contracts/protocol/libraries/aave-upgradeability/
contract InitializableImmutableAdminUpgradeabilityProxy is BaseAdminUpgradeabilityProxy {
address private immutable _admin;
constructor(address admin) {
_admin = admin;
// EIP-1967 标准存储槽
assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1));
}
function _willFallback() internal override {
require(msg.sender != _admin, 'Cannot call fallback function from the proxy admin');
super._willFallback();
}
}优势:
- 合约逻辑可升级,无需迁移用户资金
- 存储布局保持一致
- 管理员与用户调用路径分离
3.2 库委托调用模式 (Library Delegatecall)
将业务逻辑拆分到独立的库合约中:
// Pool.sol 中调用库
function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode)
public virtual override {
// 委托给 SupplyLogic 库执行
SupplyLogic.executeSupply(
_reserves,
_reservesList,
_usersConfig[onBehalfOf],
DataTypes.ExecuteSupplyParams({
asset: asset,
amount: amount,
onBehalfOf: onBehalfOf,
referralCode: referralCode
})
);
}优势:
- 绕过合约大小限制 (24KB)
- 代码模块化,易于维护
- 降低部署成本
3.3 位图配置存储 (Bitmap Configuration)
使用单个 uint256 存储多个配置参数:
struct ReserveConfigurationMap {
// 位布局说明:
// bit 0-15: LTV (贷款价值比)
// bit 16-31: Liquidation threshold (清算阈值)
// bit 32-47: Liquidation bonus (清算奖励)
// bit 48-55: Decimals (精度)
// bit 56: reserve is active (是否激活)
// bit 57: reserve is frozen (是否冻结)
// bit 58: borrowing is enabled (是否可借贷)
// bit 59: stable rate borrowing enabled (是否支持固定利率)
// bit 60: asset is paused (是否暂停)
// bit 61: borrowing in isolation mode enabled
// bit 62: siloed borrowing enabled
// bit 63: flashloaning enabled
// bit 64-79: reserve factor (协议费率)
// bit 80-115: borrow cap (借贷上限)
// bit 116-151: supply cap (存款上限)
// bit 152-167: liquidation protocol fee
// bit 168-175: eMode category
// bit 176-211: unbacked mint cap
// bit 212-251: debt ceiling (隔离模式债务上限)
uint256 data;
}位操作示例:
library ReserveConfiguration {
uint256 internal constant LTV_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000;
uint256 internal constant LIQUIDATION_THRESHOLD_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF;
function getLtv(DataTypes.ReserveConfigurationMap storage self) internal view returns (uint256) {
return self.data & ~LTV_MASK; // 取低 16 位
}
function setLtv(DataTypes.ReserveConfigurationMap storage self, uint256 ltv) internal {
require(ltv <= MAX_VALID_LTV, 'Invalid LTV');
self.data = (self.data & LTV_MASK) | ltv;
}
}Gas 优化效果:
- 单次 SSTORE 更新多个参数
- 读取配置只需一次 SLOAD
- 原子操作保证配置一致性
4. 数据结构详解
4.1 ReserveData - 储备数据
struct ReserveData {
// 配置参数 (位图)
ReserveConfigurationMap configuration;
// 流动性指数 (27位精度)
uint128 liquidityIndex;
// 当前存款利率
uint128 currentLiquidityRate;
// 可变借贷指数
uint128 variableBorrowIndex;
// 当前可变借贷利率
uint128 currentVariableBorrowRate;
// 当前固定借贷利率
uint128 currentStableBorrowRate;
// 最后更新时间戳
uint40 lastUpdateTimestamp;
// 储备 ID
uint16 id;
// aToken 地址
address aTokenAddress;
// 固定债务代币地址
address stableDebtTokenAddress;
// 可变债务代币地址
address variableDebtTokenAddress;
// 利率策略地址
address interestRateStrategyAddress;
// 累积到国库的费用
uint128 accruedToTreasury;
// Portal 未支持的铸造量
uint128 unbacked;
// 隔离模式总债务
uint128 isolationModeTotalDebt;
}存储优化:
Slot 0: configuration (256 bits)
Slot 1: liquidityIndex (128) + currentLiquidityRate (128)
Slot 2: variableBorrowIndex (128) + currentVariableBorrowRate (128)
Slot 3: currentStableBorrowRate (128) + lastUpdateTimestamp (40) + id (16) + ... (72 bits)
Slot 4: aTokenAddress (160)
Slot 5: stableDebtTokenAddress (160)
Slot 6: variableDebtTokenAddress (160)
Slot 7: interestRateStrategyAddress (160)
Slot 8: accruedToTreasury (128) + unbacked (128)
Slot 9: isolationModeTotalDebt (128) + ...
4.2 UserConfigurationMap - 用户配置
struct UserConfigurationMap {
// 每个储备占用 2 位:
// - bit 0: 是否用作抵押品
// - bit 1: 是否有借贷
// 最多支持 128 个储备
uint256 data;
}位操作:
library UserConfiguration {
uint256 internal constant BORROWING_MASK =
0x5555555555555555555555555555555555555555555555555555555555555555;
function isBorrowing(DataTypes.UserConfigurationMap storage self, uint256 reserveIndex)
internal view returns (bool)
{
unchecked {
return (self.data >> (reserveIndex << 1)) & 1 != 0;
}
}
function isUsingAsCollateral(DataTypes.UserConfigurationMap storage self, uint256 reserveIndex)
internal view returns (bool)
{
unchecked {
return (self.data >> ((reserveIndex << 1) + 1)) & 1 != 0;
}
}
}4.3 ReserveCache - 储备缓存
struct ReserveCache {
// 当前和下一个缩放可变债务
uint256 currScaledVariableDebt;
uint256 nextScaledVariableDebt;
// 固定债务相关
uint256 currPrincipalStableDebt;
uint256 currAvgStableBorrowRate;
uint256 currTotalStableDebt;
uint256 nextAvgStableBorrowRate;
uint256 nextTotalStableDebt;
// 流动性指数
uint256 currLiquidityIndex;
uint256 nextLiquidityIndex;
// 可变借贷指数
uint256 currVariableBorrowIndex;
uint256 nextVariableBorrowIndex;
// 利率
uint256 currLiquidityRate;
uint256 currVariableBorrowRate;
// 配置
uint256 reserveFactor;
ReserveConfigurationMap reserveConfiguration;
// 代币地址
address aTokenAddress;
address stableDebtTokenAddress;
address variableDebtTokenAddress;
// 时间戳
uint40 reserveLastUpdateTimestamp;
uint40 stableDebtLastUpdateTimestamp;
}使用场景:
function executeSupply(...) external {
DataTypes.ReserveData storage reserve = reservesData[params.asset];
// 一次性加载到内存,避免重复 SLOAD
DataTypes.ReserveCache memory reserveCache = reserve.cache();
// 后续操作使用缓存
reserve.updateState(reserveCache);
ValidationLogic.validateSupply(reserveCache, reserve, params.amount);
reserve.updateInterestRates(reserveCache, params.asset, params.amount, 0);
}5. 状态管理流程
5.1 操作生命周期
用户调用
│
▼
┌─────────────────────────────────────┐
│ 1. 参数验证 (ValidationLogic) │
│ - 检查储备状态 │
│ - 验证金额 │
│ - 检查用户权限 │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 2. 状态缓存 (reserve.cache()) │
│ - 加载储备数据到内存 │
│ - 读取当前指数 │
│ - 读取债务数据 │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 3. 状态更新 (reserve.updateState) │
│ - 计算累积利息 │
│ - 更新流动性指数 │
│ - 更新借贷指数 │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 4. 利率更新 (updateInterestRates) │
│ - 计算新的利用率 │
│ - 应用利率模型 │
│ - 更新利率 │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 5. 代币操作 │
│ - mint/burn aToken │
│ - mint/burn 债务代币 │
│ - 转移基础资产 │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 6. 事件发射 │
│ - 记录链上日志 │
│ - 便于链下索引 │
└─────────────────────────────────────┘
5.2 状态更新核心代码
function updateState(
DataTypes.ReserveData storage reserve,
DataTypes.ReserveCache memory reserveCache
) internal {
// 如果最后更新时间等于当前时间,无需更新
if (reserve.lastUpdateTimestamp == uint40(block.timestamp)) {
return;
}
// 更新流动性累积指数
_updateIndexes(reserve, reserveCache);
// 累积协议费用到国库
_accrueToTreasury(reserve, reserveCache);
// 更新时间戳
reserve.lastUpdateTimestamp = uint40(block.timestamp);
}
function _updateIndexes(
DataTypes.ReserveData storage reserve,
DataTypes.ReserveCache memory reserveCache
) internal {
// 计算自上次更新以来的复利
uint256 cumulatedLiquidityInterest = MathUtils.calculateLinearInterest(
reserveCache.currLiquidityRate,
reserveCache.reserveLastUpdateTimestamp
);
// 更新流动性指数: newIndex = oldIndex * (1 + rate * time)
reserveCache.nextLiquidityIndex = cumulatedLiquidityInterest.rayMul(reserveCache.currLiquidityIndex);
reserve.liquidityIndex = reserveCache.nextLiquidityIndex.toUint128();
// 只有存在可变债务时才更新借贷指数
if (reserveCache.currScaledVariableDebt != 0) {
uint256 cumulatedVariableBorrowInterest = MathUtils.calculateCompoundedInterest(
reserveCache.currVariableBorrowRate,
reserveCache.reserveLastUpdateTimestamp
);
reserveCache.nextVariableBorrowIndex = cumulatedVariableBorrowInterest.rayMul(reserveCache.currVariableBorrowIndex);
reserve.variableBorrowIndex = reserveCache.nextVariableBorrowIndex.toUint128();
}
}6. 权限控制系统
6.1 ACL 角色层次
┌─────────────────┐
│ DEFAULT_ADMIN │
│ (最高权限) │
└────────┬────────┘
│
┌────────────────┼────────────────┐
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ POOL_ADMIN │ │EMERGENCY_ADMIN│ │ RISK_ADMIN │
│ 池管理员 │ │ 紧急管理员 │ │ 风险管理员 │
└───────────────┘ └───────────────┘ └───────────────┘
│ │
▼ ▼
┌───────────────┐ ┌───────────────┐
│ASSET_LISTING │ │ FLASH_BORROWER│
│ ADMIN │ │ 闪电贷用户 │
└───────────────┘ └───────────────┘
6.2 权限定义
contract ACLManager {
bytes32 public constant POOL_ADMIN_ROLE = keccak256('POOL_ADMIN');
bytes32 public constant EMERGENCY_ADMIN_ROLE = keccak256('EMERGENCY_ADMIN');
bytes32 public constant RISK_ADMIN_ROLE = keccak256('RISK_ADMIN');
bytes32 public constant FLASH_BORROWER_ROLE = keccak256('FLASH_BORROWER');
bytes32 public constant BRIDGE_ROLE = keccak256('BRIDGE');
bytes32 public constant ASSET_LISTING_ADMIN_ROLE = keccak256('ASSET_LISTING_ADMIN');
}6.3 权限检查
// PoolConfigurator 中的权限检查
modifier onlyPoolAdmin() {
_onlyPoolAdmin();
_;
}
function _onlyPoolAdmin() internal view {
IACLManager aclManager = IACLManager(_addressesProvider.getACLManager());
require(aclManager.isPoolAdmin(msg.sender), 'Caller is not Pool Admin');
}
// 紧急暂停
function setPoolPause(bool paused) external override onlyEmergencyAdmin {
_pool.setPoolPause(paused);
}7. Gas 优化技术
7.1 存储优化策略
| 技术 | 描述 | Gas 节省 |
|---|---|---|
| 紧密打包 | 相关字段放同一槽 | ~20,000 gas/操作 |
| 位图存储 | 多个布尔值压缩 | ~15,000 gas/操作 |
| 内存缓存 | 减少重复读取 | ~5,000 gas/操作 |
| unchecked | 跳过溢出检查 | ~100 gas/操作 |
7.2 L2Pool 优化
// L2Pool.sol - 专为 L2 优化的实现
function supply(bytes32 args) external override {
// 从压缩参数解码
(address asset, uint256 amount, uint16 referralCode) =
CalldataLogic.decodeSupplyParams(_reservesList, args);
supply(asset, amount, msg.sender, referralCode);
}
// CalldataLogic.sol
function decodeSupplyParams(
mapping(uint256 => address) storage reservesList,
bytes32 args
) internal view returns (address, uint256, uint16) {
uint16 assetId;
uint256 amount;
uint16 referralCode;
assembly {
assetId := and(args, 0xFFFF)
amount := and(shr(16, args), 0xFFFFFFFFFFFFFFFFFFFFFFFF)
referralCode := and(shr(144, args), 0xFFFF)
}
return (reservesList[assetId], amount, referralCode);
}L2 优化效果:
- calldata 从 ~200 bytes 压缩到 32 bytes
- L2 网络交易成本降低 50-70%
8. 小结
Aave V3 的架构设计体现了 DeFi 协议的最佳实践:
- 模块化设计:通过库模式实现代码复用和升级灵活性
- 存储优化:位图和紧密打包显著降低 Gas 消耗
- 安全性:多层权限控制和验证逻辑
- 可扩展性:代理模式支持无缝升级
- 多链友好:L2Pool 和 Portal 支持多链部署
下一章将详细讲解存款、借贷、还款、清算等核心借贷机制的实现。