Aave V3 核心概念与架构

1. 协议概述

1.1 什么是 Aave

Aave 是一个去中心化的非托管流动性协议,允许用户:

  • 存款赚取利息:将资产存入流动性池,获得被动收益
  • 抵押借贷:以存款作为抵押品借出其他资产
  • 闪电贷:在单笔交易内无抵押借贷

1.2 V3 相对 V2 的核心升级

特性V2V3改进
资本效率基础E-Mode 提升最高 97% LTV
风险管理统一参数隔离模式细粒度控制
跨链能力Portal 桥接原生跨链
Gas 消耗~180k~150k降低 16%+
L2 优化L2Poolcalldata 压缩

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 协议的最佳实践:

  1. 模块化设计:通过库模式实现代码复用和升级灵活性
  2. 存储优化:位图和紧密打包显著降低 Gas 消耗
  3. 安全性:多层权限控制和验证逻辑
  4. 可扩展性:代理模式支持无缝升级
  5. 多链友好:L2Pool 和 Portal 支持多链部署

下一章将详细讲解存款、借贷、还款、清算等核心借贷机制的实现。