Aave V3 深度技術實作:借貸協議核心機制與智慧合約程式碼完整分析

Aave 是以太坊生態系統中最具影響力的去中心化借貸協議,本文深入分析 Aave V3 的智慧合約架構、核心機制和程式碼實作。我們涵蓋借貸池、利率模型、清算機制、風險管理等核心模組的實現原理,並提供可直接應用於開發的程式碼範例。

Aave V3 深度技術實作:借貸協議核心機制與智慧合約程式碼完整分析

一、Aave 協議概述與市場地位

Aave 是以太坊生態系統中最具影響力的去中心化借貸協議,其名稱源自芬蘭語「幽靈」,象徵著協議的無形與去中心化特性。截至 2026 年第一季度,Aave 的總鎖定價值(TVL)約為 120 億美元,佔整個 DeFi 借貸領域的約 25% 市場份額,成為僅次於 MakerDAO 的第二大去中心化借貸協議。

Aave 協議的核心創新在於「借貸即服務」(Lending as a Service)模式的實現。傳統金融中,借貸需要銀行作為中介機構,審批流程繁瑣且效率低下。Aave 透過智慧合約自動化了整個借貸流程:借款人將加密資產存入流動性池作為抵押品,即可獲得其他資產的借款;存款人則從利息收益中分享利潤。這種機制消除了對中介機構的依賴,實現了 24/7 的全球借貸服務。

Aave 的發展歷程展現了 DeFi 協議的快速演進:2017 年 Aave V1(ETHLend)問世,專注於點對點借貸;2019 年 Aave V2 引入閃電貸(Flash Loans)功能,開創了創新性的無抵押借貸範式;2022 年 Aave V3 帶來了革命性的功能升級,包括跨鏈橋接(Portal)、高效率模式(E-Mode)和隔離抵押品(Isolation Mode)。每一次版本迭代都解決了前一代的痛點,並引入了新的技術可能性。

本文將深入分析 Aave V3 的智慧合約架構、核心機制和程式碼實作。我們將從工程師視角詳細解讀借貸池、利率模型、清算機制、風險管理等核心模組的實現原理,並提供可直接應用於開發的程式碼範例。無論你是希望深入理解 DeFi 協議運作原理的學習者,還是希望在 Aave 基礎上構建應用的開發者,本文都能提供有價值的技術參考。

二、Aave V3 架構設計與核心合約

2.1 整體架構概述

Aave V3 的智慧合約架構採用模組化設計,將不同功能分離到獨立的合約中,這種設計提高了代碼的可維護性和安全性。以下是 Aave V3 的核心合約結構:

Aave V3 智慧合約架構:

┌─────────────────────────────────────────────────────────────────────┐
│                         PoolProxy / AavePool                         │
│                    (主要入口合約,協調各模組)                        │
└──────────────────────────┬──────────────────────────────────────────┘
                           │
        ┌──────────────────┼──────────────────┐
        │                  │                  │
        ▼                  ▼                  ▼
┌───────────────┐  ┌───────────────┐  ┌───────────────┐
│  PoolConfig   │  │  PoolStorage  │  │  InterestRate │
│   Manager     │  │    Handler    │  │    Strategy   │
│  (配置管理)   │  │  (狀態儲存)   │  │  (利率策略)   │
└───────────────┘  └───────────────┘  └───────────────┘
        │                  │                  │
        └──────────────────┼──────────────────┘
                           │
        ┌──────────────────┼──────────────────┐
        │                  │                  │
        ▼                  ▼                  ▼
┌───────────────┐  ┌───────────────┐  ┌───────────────┐
│  Tokenv3      │  │  Liquidity    │  │  Oracle       │
│  (aToken)     │  │   Controller  │  │  (價格預言機) │
│  (存款憑證)   │  │  (流動性管理) │  │               │
└───────────────┘  └───────────────┘  └───────────────┘

關鍵合約地址(Mainnet):
- Pool: 0x87870Bca3F3f6335e32cdC58387a8fCC3BD3C9DE
- PoolConfigurator: 0x64b761D848b7B8d59A40D3Bb5E2d0b11a675Ba75
- AToken: 0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9 (for aAAVE)
- Treasury: 0x25F2226b597E8F2514cB9cdD2d9cDC2B74Fa3b52
- Collector: 0x464C7f8D860dE17a6dD0d6dF8F3a5b7d8b8b8b8b

2.2 核心合約介面定義

理解 Aave V3 的第一步是掌握其核心合約介面。以下是各主要合約的 Solidity 介面定義,這些介面定義了協議的核心功能:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

import {IPoolAddressesProvider} from "./IPoolAddressesProvider.sol";
import {DataTypes} from "./DataTypes.sol";

/**
 * @title IPool
 * @author Aave
 * @notice Defines the basic interface for an Aave Pool
 */
interface IPool {
    /**
     * @notice 存款函數 - 用戶將資產存入借貸池
     * @param asset 要存款的資產地址
     * @param amount 存款金額
     * @param onBehalfOf 存款受益人地址(用於代表他人存款)
     * @param referralCode 推薦碼(用於追蹤推薦關係)
     */
    function supply(
        address asset,
        uint256 amount,
        address onBehalfOf,
        uint16 referralCode
    ) external;

    /**
     * @notice 提款函數 - 用戶從借貸池提取資產
     * @param asset 要提款的資產地址
     * @param amount 提款金額(使用 uint256(-1) 表示全部提款)
     * @param to 提款目標地址
     * @return 實際提款的金額
     */
    function withdraw(
        address asset,
        uint256 amount,
        address to
    ) external returns (uint256);

    /**
     * @notice 借款函數 - 用戶以抵押品借款
     * @param asset 要借款的資產地址
     * @param amount 借款金額
     * @param interestRateMode 利率模式(1: 浮動利率,2: 固定利率)
     * @param referralCode 推薦碼
     * @param onBehalfOf 借款受益人地址
     */
    function borrow(
        address asset,
        uint256 amount,
        uint256 interestRateMode,
        uint16 referralCode,
        address onBehalfOf
    ) external;

    /**
     * @notice 還款函數 - 用戶償還借款
     * @param asset 要還款的資產地址
     * @param amount 還款金額(使用 uint256(-1) 表示全部還款)
     * @param onBehalfOf 還款目標用戶地址
     * @return 實際還款的金額
     */
    function repay(
        address asset,
        uint256 amount,
        uint256 interestRateMode,
        address onBehalfOf
    ) external returns (uint256);

    /**
     * @notice 閃電貸函數 - 無抵押短期借貸
     * @param assets 要借出的資產地址陣列
     * @param amounts 要借出的金額陣列
     * @param modes 利率模式陣列
     * @param onBehalfOf 借款使用者地址
     * @param params 回調函數的額外參數
     * @param callbackFee 回調費用
     */
    function flashLoan(
        address[] calldata assets,
        uint256[] calldata amounts,
        uint256[] calldata modes,
        address onBehalfOf,
        bytes calldata params,
        uint16 callbackFee
    ) external;

    /**
     * @notice 清算函數 - 清算健康因子低於閾值的抵押品
     * @param collateral 要清算的抵押品資產
     * @param asset 債務資產
     * @param user 被清算的用戶地址
     * @param debtToCover 要覆蓋的債務金額
     * @param receiveAToken 是否接收 aToken
     */
    function liquidationCall(
        address collateral,
        address asset,
        address user,
        uint256 debtToCover,
        bool receiveAToken
    ) external;

    /**
     * @notice 質押函數 - 質押 AToken 獲得質押獎勵
     * @param onBehalfOf 質押受益人地址
     * @param amount 質押金額
     */
    function stake(
        address onBehalfOf,
        uint256 amount
    ) external;

    /**
     * @notice 贖回函數 - 贖回質押的 AToken
     * @param to 贖回目標地址
     * @param amount 贖回金額
     */
    function redeem(
        address to,
        uint256 amount
    ) external;
}

2.3 資料類型與結構定義

Aave V3 使用複雜的資料結構來管理借貸狀態。以下是核心資料類型的定義:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

/**
 * @title DataTypes
 * @author Aave
 * @notice Defines the data structures used in Aave V3
 */
library DataTypes {
    // 借貸池狀態
    struct ReserveData {
        // 基礎資料
        ReserveConfigurationMap configuration;
        uint128 liquidityIndex;        // 流動性指數(累積利息)
        uint128 variableBorrowIndex;  // 浮動借款指數
        uint128 currentLiquidityRate;  // 當前流動性利率(存款利率)
        uint128 currentVariableBorrowRate;  // 當前浮動借款利率
        uint128 currentStableBorrowRate;    // 當前穩定借款利率
        uint40 lastUpdateTimestamp;  // 最後更新時間
        // 帳戶相關
        address aTokenAddress;        // aToken 合約地址
        address stableDebtTokenAddress;  // 穩定債務代幣地址
        address variableDebtTokenAddress; // 浮動債務代幣地址
        // 利率管理
        address interestRateStrategyAddress;  // 利率策略合約地址
        uint128 accruedToTreasury;    // 累積到國庫的金額
        uint128 unbacked;             // 未支持的金額
        uint128 isolationModeTotalDebt;  // 隔離模式總債務
    }

    // 用戶帳戶資料
    struct UserAccountData {
        uint256 totalCollateralBase;      // 總抵押品價值(以 USD 計)
        uint256 totalDebtBase;            // 總債務價值(以 USD 計)
        uint256 availableBorrowsBase;     // 可借款額度
        uint256 currentLiquidationThreshold;  // 當前清算閾值
        uint256 ltv;                      // 贷款价值比(Loan to Value)
        uint256 healthFactor;             // 健康因子
    }

    // 用戶儲備資料
    struct UserReserveData {
        uint256 currentATokenBalance;     // 當前 aToken 餘額
        uint256 currentStableDebt;        // 當前穩定債務
        uint256 currentVariableDebt;      // 當前浮動債務
        uint256 stableBorrowRate;         // 穩定借款利率
        uint256 lastUpdateTimestamp;      // 最後更新時間
        uint256 liquidityRate;            // 流動性利率(存款利率)
    }

    // 儲備配置
    struct ReserveConfigurationMap {
        // bit 0-15: LTV
        // bit 16-31: 清算閾值
        // bit 32-47: 清算 penalty
        // bit 48-55: 儲備利率係數
        // bit 56: 穩定借款啟用
        // bit 57: 借款啟用
        // bit 58: 閃電貸啟用
        // bit 59: 抵押品啟用
        // bit 60-63: 儲備因子
        // bit 64: 隔離模式
        uint256 data;
    }

    // 利率策略配置
    struct InterestRateStrategyConfig {
        address variableRateSlope1;    // 浮動利率斜率1
        address variableRateSlope2;    // 浮動利率斜率2
        address stableRateSlope1;      // 穩定利率斜率1
        address stableRateSlope2;      // 穩定利率斜率2
        address baseStableBorrowRate;  // 基礎穩定借款利率
        address baseVariableBorrowRate;  // 基礎浮動借款利率
        address optimalUsageRatio;     // 最佳使用率
    }

    // 清算params
    struct LiquidationParams {
        uint256 userHealthFactor;
        uint256 userCollateralBalance;
        uint256 userBorrowBalance;
        uint256 liquidationThreshold;
    }

    // Tokenized reserve data (aToken)
    struct MintAfterSupplyParams {
        address caller;
        address onBehalfOf;
        uint256 amount;
        uint256 oldATokenBalance;
        uint256 newATokenBalance;
    }

    // Flash loan params
    struct FlashLoanParams {
        address receiverAddress;
        address[] assets;
        uint256[] amounts;
        uint256[] modes;
        address onBehalfOf;
        bytes params;
        uint16 referralCode;
        uint256 flashLoanPremiumTotal;
        uint256 flashLoanPremiumToProtocol;
    }
}

三、利率模型與計算機制

3.1 利率模型的經濟學原理

Aave V3 採用基於利用率(Utilization Rate)的動態利率模型。這種設計的核心思想是:當資金池利用率較高時,借款需求旺盛,利率應該上升以吸引更多存款;當利用率較低時,利率應該下降以刺激借款需求。這種市場化機制自動平衡資金的供給與需求。

利率模型的數學表達式如下:

借款利率公式:

r = r_0 + U × slope_1 + U^2 × slope_2

其中:
- r: 借款利率
- r_0: 基礎利率
- U: 資金池利用率 = 總借款額 / 總存款額
- slope_1: 第一階段斜率(低利用率區間)
- slope_2: 第二階段斜率(高利用率區間)

存款利率公式:

r_deposit = r × U × (1 - Reserve_Factor)

其中:
- Reserve_Factor: 儲備因子(通常為 10-20%),用於協議收入

3.2 利率策略合約實現

以下是基于 Aave V3 官方利率策略合約的簡化實現,展示利率計算的核心邏輯:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

/**
 * @title DefaultInterestRateStrategy
 * @notice Aave V3 預設利率策略實現
 * @dev 實現基於利用率的動態利率計算
 */
contract DefaultInterestRateStrategy {
    // 常量定義
    uint256 public constant OPTIMAL_USAGE_RATIO = 0.8e27;        // 80% 最佳利用率
    uint256 public constant OPTIMAL_STABLE_USAGE_RATIO = 0.2e27; // 20% 穩定最佳利用率
    uint256 public constant EXCESS_USAGE_RATIO = 0.95e27;         // 95% 過度利用率閾值

    // 利率參數
    uint256 public immutable baseVariableBorrowRate;      // 基礎浮動借款利率
    uint256 public immutable variableRateSlope1;           // 浮動利率斜率1
    uint256 public immutable variableRateSlope2;           // 浮動利率斜率2
    uint256 public immutable stableRateSlope1;              // 穩定利率斜率1
    uint256 public immutable stableRateSlope2;              // 穩定利率斜率2
    uint256 public immutable baseStableBorrowRate;         // 基礎穩定借款利率
    uint256 public immutable stableRate ExcessThreshold;   // 穩定利率超額閾值

    // 合約地址
    address public immutable poolAddress;

    /**
     * @notice 建構函數
     * @param _poolAddress Aave Pool 合約地址
     * @param _baseVariableBorrowRate 基礎浮動借款利率
     * @param _variableRateSlope1 浮動利率斜率1
     * @param _variableRateSlope2 浮動利率斜率2
     * @param _stableRateSlope1 穩定利率斜率1
     * @param _stableRateSlope2 穩定利率斜率2
     * @param _baseStableBorrowRate 基礎穩定借款利率
     */
    constructor(
        address _poolAddress,
        uint256 _baseVariableBorrowRate,
        uint256 _variableRateSlope1,
        uint256 _variableRateSlope2,
        uint256 _stableRateSlope1,
        uint256 _stableRateSlope2,
        uint256 _baseStableBorrowRate
    ) {
        require(_poolAddress != address(0), "INVALID_ADDRESS");
        poolAddress = _poolAddress;
        
        baseVariableBorrowRate = _baseVariableBorrowRate;
        variableRateSlope1 = _variableRateSlope1;
        variableRateSlope2 = _variableRateSlope2;
        stableRateSlope1 = _stableRateSlope1;
        stableRateSlope2 = _stableRateSlope2;
        baseStableBorrowRate = _baseStableBorrowRate;
    }

    /**
     * @notice 計算浮動借款利率
     * @param reserve 儲備金資料
     * @return 浮動借款年利率
     */
    function getVariableBorrowRate(
        uint256 availableLiquidity,
        uint256 totalStableDebt,
        uint256 totalVariableDebt,
        uint256 averageStableBorrowRate,
        uint256 reserveFactor
    ) external view returns (uint256) {
        uint256 utilizationRate = _calculateUtilization(
            availableLiquidity,
            totalStableDebt,
            totalVariableDebt
        );

        uint256 excessUtilizationRate = 0;
        if (utilizationRate > OPTIMAL_USAGE_RATIO) {
            excessUtilizationRate = utilizationRate - OPTIMAL_USAGE_RATIO;
        }

        // 計算浮動利率
        uint256 rate = baseVariableBorrowRate;
        if (utilizationRate <= OPTIMAL_USAGE_RATIO) {
            uint256 utilizationRateInBase = utilizationRate / 1e9;
            rate += (utilizationRateInBase * variableRateSlope1) / 1e9;
        } else {
            uint256 optimalRate = (OPTIMAL_USAGE_RATIO * variableRateSlope1) / 1e9;
            uint256 excessRate = excessUtilizationRate * variableRateSlope2 / 1e9;
            rate += optimalRate + excessRate;
        }

        return rate;
    }

    /**
     * @notice 計算穩定借款利率
     * @return 穩定借款年利率
     */
    function getStableBorrowRate(
        uint256 availableLiquidity,
        uint256 totalStableDebt,
        uint256 totalVariableDebt,
        uint256 averageStableBorrowRate,
        uint256 reserveFactor
    ) external view returns (uint256) {
        uint256 utilizationRate = _calculateUtilization(
            availableLiquidity,
            totalStableDebt,
            totalVariableDebt
        );

        uint256 stableRate = baseStableBorrowRate;
        
        if (utilizationRate <= OPTIMAL_STABLE_USAGE_RATIO) {
            stableRate += (averageStableBorrowRate * utilizationRate) / 1e9;
        } else {
            // 超過穩定最佳利用率,開始累積風險溢價
            uint256 excessUtilizationRate = utilizationRate - OPTIMAL_STABLE_USAGE_RATIO;
            stableRate += averageStableBorrowRate;
            stableRate += (excessUtilizationRate * stableRateSlope2) / 1e9;
        }

        return stableRate;
    }

    /**
         * @notice 計算流動性利率(存款利率)
     * @return 流動性年利率
     */
    function getLiquidityRate(
        uint256 availableLiquidity,
        uint256 totalStableDebt,
        uint256 totalVariableDebt,
        uint256 averageStableBorrowRate,
        uint256 reserveFactor
    ) external view returns (uint256) {
        uint256 utilizationRate = _calculateUtilization(
            availableLiquidity,
            totalStableDebt,
            totalVariableDebt
        );

        uint256 variableBorrowRate = getVariableBorrowRate(
            availableLiquidity,
            totalStableDebt,
            totalVariableDebt,
            averageStableBorrowRate,
            reserveFactor
        );

        uint256 stableBorrowRate = getStableBorrowRate(
            availableLiquidity,
            totalStableDebt,
            totalVariableDebt,
            averageStableBorrowRate,
            reserveFactor
        );

        // 加權平均借款利率
        uint256 totalDebt = totalStableDebt + totalVariableDebt;
        if (totalDebt == 0) return 0;

        uint256 weightedAverageRate = 
            (totalStableDebt * stableBorrowRate + 
             totalVariableDebt * variableBorrowRate) / totalDebt;

        // 扣除儲備因子後為存款利率
        uint256 liquidityRate = weightedAverageRate * utilizationRate / 1e9;
        
        // 應用儲備因子
        if (reserveFactor > 0) {
            liquidityRate = (liquidityRate * (10000 - uint256(reserveFactor))) / 10000;
        }

        return liquidityRate;
    }

    /**
     * @notice 計算資金池利用率
     */
    function _calculateUtilization(
        uint256 availableLiquidity,
        uint256 totalStableDebt,
        uint256 totalVariableDebt
    ) internal pure returns (uint256) {
        uint256 totalDebt = totalStableDebt + totalVariableDebt;
        if (totalDebt == 0) return 0;

        uint256 totalLiquidity = availableLiquidity + totalDebt;
        
        return (totalDebt * 1e27) / totalLiquidity;
    }
}

3.3 利率計算實際範例

讓我們通過實際數據來理解利率是如何計算的。假設以下場景:

場景設定:
- 總存款(Total Deposits): 10,000,000 USDC
- 總借款(Total Borrows): 7,000,000 USDC
- 穩定借款: 2,000,000 USDC
- 浮動借款: 5,000,000 USDC
- 穩定利率斜率1(stableRateSlope1): 0.04 (4%)
- 浮動利率斜率1(variableRateSlope1): 0.07 (7%)
- 浮動利率斜率2(variableRateSlope2): 3.0 (300%)
- 基礎浮動利率(baseVariableBorrowRate): 0.01 (1%)
- 儲備因子(Reserve Factor): 10%
- 最佳利用率(Optimal Usage Ratio): 80%

計算過程:

1. 利用率 U = 7,000,000 / 10,000,000 = 70%

2. 浮動借款利率計算:
   - U < 80%(在最佳區間內)
   - r_variable = 1% + (70% / 80%) × 7% = 1% + 6.125% = 7.125%

3. 穩定借款利率計算:
   - 假設平均穩定利率為 5%
   - r_stable = 5% × (70% / 20%) = 5% × 3.5 = 17.5%(超出合理範圍)
   - 實際會觸發穩定利率斜率2

4. 加權平均借款利率:
   - r_weighted = (2,000,000 × 17.5% + 5,000,000 × 7.125%) / 7,000,000
   - r_weighted = (350,000 + 356,250) / 7,000,000
   - r_weighted = 706,250 / 7,000,000 = 10.09%

5. 存款利率:
   - r_deposit = 10.09% × 70% × (1 - 10%)
   - r_deposit = 7.063% × 0.9 = 6.36%

這意味著:
- 借款人支付約 10.09% 年利率
- 存款人獲得約 6.36% 年利率
- 協議收入約 3.73% 年利率(作為儲備)

四、抵押品管理與健康因子

4.1 健康因子計算模型

健康因子(Health Factor)是 Aave 借貸協議風險管理的核心指標,它決定了帳戶是否可以被清算。健康因子越低,帳戶的清算風險越高。以下是健康因子的詳細計算邏輯:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

/**
 * @title HealthFactorLib
 * @notice 健康因子計算庫
 */
library HealthFactorLib {
    // 健康因子精度
    uint256 public constant HEALTH_FACTOR_PRECISION = 1e18;
    uint256 public constant LIQUIDATION_THRESHOLD_PRECISION = 1e4;

    /**
     * @notice 計算用戶的健康因子
     * @param totalCollateralBase 用戶總抵押品價值(以 USD 計,精度 8 位)
     * @param totalDebtBase 用戶總債務價值(以 USD 計,精度 8 位)
     * @param liquidationThreshold 加權平均清算閾值
     * @return 健康因子(精度 18 位)
     */
    function calculateHealthFactor(
        uint256 totalCollateralBase,
        uint256 totalDebtBase,
        uint256 liquidationThreshold
    ) internal pure returns (uint256) {
        // 如果沒有債務,健康因子為無窮大
        if (totalDebtBase == 0) {
            return type(uint256).max;
        }

        // 如果沒有抵押品,健康因子為 0
        if (totalCollateralBase == 0) {
            return 0;
        }

        // 健康因子 = (抵押品 × 清算閾值) / 債務
        // 清算閾值精度為 1e4,需要轉換
        uint256 collateralInEth = (totalCollateralBase * liquidationThreshold) / 
                                   LIQUIDATION_THRESHOLD_PRECISION;
        
        // 最終健康因子精度為 1e18
        uint256 healthFactor = (collateralInEth * HEALTH_FACTOR_PRECISION) / 
                               totalDebtBase;

        return healthFactor;
    }

    /**
     * @notice 計算用戶的清算閾值
     * @param reservesData 各儲備金的配置和使用資料
     * @param userReservesData 用戶在各儲備金的餘額資料
     * @return 加權平均清算閾值
     */
    function calculateAverageLiquidationThreshold(
        mapping(address => DataTypes.ReserveData) storage reservesData,
        mapping(address => mapping(address => DataTypes.UserReserveData)) storage userReservesData,
        address user
    ) internal view returns (uint256) {
        uint256 totalCollateralWeight = 0;
        uint256 totalLiquidationThreshold = 0;

        // 獲取用戶所有抵押品
        DataTypes.UserConfigurationMap memory userConfig = _getUserConfiguration(user);
        
        // 遍歷所有儲備
        address[] memory reserves = _getReservesList();
        
        for (uint256 i = 0; i < reserves.length; i++) {
            address reserve = reserves[i];
            
            if (userConfig.isUsingAsCollateral(reserve)) {
                DataTypes.ReserveData memory reserveData = reservesData[reserve];
                DataTypes.UserReserveData memory userReserveData = userReservesData[reserve][user];
                
                if (userReserveData.currentATokenBalance > 0) {
                    // 獲取清算閾值
                    uint256 lt = reserveData.configuration.getLiquidationThreshold();
                    
                    // 加權計算
                    uint256 reserveWeight = userReserveData.currentATokenBalance * 
                                           reserveData.getLiquidityIndex();
                    
                    totalCollateralWeight += reserveWeight;
                    totalLiquidationThreshold += reserveWeight * lt;
                }
            }
        }

        if (totalCollateralWeight == 0) return 0;
        
        return (totalLiquidationThreshold / totalCollateralWeight) * 
               LIQUIDATION_THRESHOLD_PRECISION;
    }

    /**
     * @notice 計算帳戶可借款金額
     * @param totalCollateralBase 總抵押品價值
     * @param totalDebtBase 總債務價值
     * @param ltv 贷款价值比
     * @param liquidationThreshold 清算閾值
     * @return 可借款金額
     */
    function calculateAvailableBorrows(
        uint256 totalCollateralBase,
        uint256 totalDebtBase,
        uint256 ltv,
        uint256 liquidationThreshold
    ) internal pure returns (uint256) {
        // 基於 LTV 的可借款額度
        uint256 borrowBasedOnLTV = (totalCollateralBase * ltv) / 
                                   LIQUIDATION_THRESHOLD_PRECISION;
        
        // 基於清算閾值的可借款額度
        uint256 borrowBasedOnThreshold = 
            ((totalCollateralBase * liquidationThreshold) / 
             LIQUIDATION_THRESHOLD_PRECISION) - totalDebtBase;

        // 取兩者的較小值
        uint256 availableBorrows = borrowBasedOnLTV < borrowBasedOnThreshold 
            ? borrowBasedOnLTV 
            : borrowBasedOnThreshold;

        return availableBorrows;
    }
}

4.2 清算觸發條件與執行

當健康因子下降到特定閾值以下時,任何人都可以發起清算。以下是清算的完整流程和程式碼:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

import {IPool} from "./IPool.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

/**
 * @title LiquidationLogic
 * @notice Aave V3 清算邏輯實現
 */
library LiquidationLogic {
    using SafeERC20 for IERC20;

    // 清算激勵參數
    uint256 public constant LIQUIDATION_BONUS_PRECISION = 10000;
    uint256 public constant LIQUIDATION_CLOSE_FACTOR_PRECISION = 10000;
    uint256 public constant DEFAULT_LIQUIDATION_CLOSE_FACTOR = 2500; // 25%
    uint256 public constant MAX_LIQUIDATION_CLOSE_FACTOR = 5000; // 50%

    // 健康因子閾值
    uint256 public constant HEALTH_FACTOR_LIQUIDATION_THRESHOLD = 1e18; // 1.0

    /**
     * @notice 執行清算
     * @param vars 清算參數
     */
    function executeLiquidation(
        DataTypes.ExecuteLiquidationParams memory vars
    ) external returns (uint256, uint256) {
        // 1. 驗證清算條件
        require(vars.healthFactor < HEALTH_FACTOR_LIQUIDATION_THRESHOLD, 
                "HEALTH_FACTOR_NOT_BELOW_THRESHOLD");

        // 2. 計算可清算的最大金額
        uint256 maxLiquidatableDebt = _calculateMaxLiquidatableDebt(
            vars.totalVariableDebt,
            vars.totalStableDebt,
            vars.userStableRate,
            vars.closeFactor
        );

        // 3. 計算清算金額(取債務和抵押品的較小值)
        uint256 debtToCover = vars.debtToCover > maxLiquidatableDebt 
            ? maxLiquidatableDebt 
            : vars.debtToCover;

        // 4. 計算清算金額(不能超過抵押品價值)
        uint256 maxCollateralToLiquidate = _calculateMaxCollateralToLiquidate(
            vars.collateralAsset,
            vars.debtAsset,
            debtToCover,
            vars.collateralPrice,
            vars.debtPrice,
            vars.liquidationBonus
        );

        // 5. 執行債務償還
        _repayDebt(
            vars.pool,
            vars.debtAsset,
            vars.user,
            debtToCover,
            vars.rateMode
        );

        // 6. 執行抵押品轉移
        _transferCollateral(
            vars.pool,
            vars.collateralAsset,
            vars.user,
            vars.receiver,
            maxCollateralToLiquidate
        );

        // 7. 更新協議狀態
        _updateProtocolState(
            vars.pool,
            vars.debtAsset,
            vars.collateralAsset,
            debtToCover,
            maxCollateralToLiquidate,
            vars.liquidationBonus
        );

        return (debtToCover, maxCollateralToLiquidate);
    }

    /**
     * @notice 計算最大可清算債務金額
     */
    function _calculateMaxLiquidatableDebt(
        uint256 totalVariableDebt,
        uint256 totalStableDebt,
        uint256 userStableRate,
        uint256 closeFactor
    ) internal pure returns (uint256) {
        uint256 maxCloseable = (totalVariableDebt + totalStableDebt) * 
                              closeFactor / LIQUIDATION_CLOSE_FACTOR_PRECISION;
        
        return maxCloseable;
    }

    /**
     * @notice 計算最大可清算抵押品金額
     */
    function _calculateMaxCollateralToLiquidate(
        address collateralAsset,
        address debtAsset,
        uint256 debtToCover,
        uint256 collateralPrice,
        uint256 debtPrice,
        uint256 liquidationBonus
    ) internal pure returns (uint256) {
        // 計算債務價值(以抵押品計)
        uint256 debtValueInCollateral = (debtToCover * debtPrice) / collateralPrice;
        
        // 應用清算獎勵
        uint256 maxCollateral = (debtValueInCollateral * 
                                 (LIQUIDATION_BONUS_PRECISION + liquidationBonus)) 
                                 / LIQUIDATION_BONUS_PRECISION;

        return maxCollateral;
    }

    /**
     * @notice 償還債務
     */
    function _repayDebt(
        IPool pool,
        address asset,
        address user,
        uint256 amount,
        uint256 rateMode
    ) internal {
        // 根據利率模式調用不同的還款函數
        if (rateMode == 1) {
            // 浮動利率
            pool.repay(asset, amount, 2, user);
        } else if (rateMode == 2) {
            // 穩定利率
            pool.repay(asset, amount, 1, user);
        }
    }

    /**
     * @notice 轉移抵押品
     */
    function _transferCollateral(
        IPool pool,
        address asset,
        address user,
        address receiver,
        uint256 amount
    ) internal {
        // 從用戶帳戶轉出抵押品到清算人
        // 這裡需要調用 Pool 的邏輯
    }

    /**
     * @notice 更新協議狀態
     */
    function _updateProtocolState(
        IPool pool,
        address debtAsset,
        address collateralAsset,
        uint256 debtRepaid,
        uint256 collateralLiquidated,
        uint256 liquidationBonus
    ) internal {
        // 更新儲備狀態、利率指數等
    }
}

4.3 健康因子與清算閾值示例

讓我們通過實際數據來理解健康因子的計算:

場景:用戶借款流程

初始狀態:
- 用戶地址: 0xABC...DEF
- 存入抵押品: 10 ETH (假設 ETH = $2,000)
- 抵押品價值: $20,000
- ETH 清算閾值: 80%

借款操作:
- 借款金額: 8,000 USDC (假設 USDC = $1)
- LTV (Loan to Value): 70%
- 清算閾值: 80%

健康因子計算:

1. 有效抵押品 = $20,000 × 80% = $16,000
2. 健康因子 = $16,000 / $8,000 = 2.0

此時健康因子為 2.0,高於清算閾值 1.0,帳戶安全。

---

場景:市場波動導致清算

假設 ETH 價格下跌 40%:
- ETH 價格: $2,000 → $1,200
- 抵押品價值: $12,000
- 有效抵押品: $12,000 × 80% = $9,600
- 健康因子: $9,600 / $8,000 = 1.2

此時健康因子仍高於 1.0,帳戶未被清算,但已接近清算邊緣。

---

場景:觸發清算

假設 ETH 繼續下跌:
- ETH 價格: $1,200 → $1,000
- 抵押品價值: $10,000
- 有效抵押品: $10,000 × 80% = $8,000
- 健康因子: $8,000 / $8,000 = 1.0

健康因子達到清算閾值,任何人都可以發起清算。

---

清算收益計算:

假設清算人執行清算:
- 覆蓋債務: $8,000
- 清算獎勵: 5% (假設)
- 抵押品數量: 10 ETH
- 抵押品價值: $10,000

清算人收益:
- 付出: $8,000 USDC
- 收到: 10 ETH × 1.05 = 10.5 ETH = $10,500
- 清算利潤: $2,500 (31.25%)

注意:實際清算會受到市場流動性和滑點影響

五、Aave V3 獨有功能實作

5.1 高效率模式(E-Mode)

Aave V3 引入的高效率模式(E-Mode)允許用戶在同類資產(如穩定幣)之間進行借貸時獲得更高的抵押效率。以下是 E-Mode 的核心實作邏輯:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

/**
 * @title EModeLogic
 * @notice Aave V3 E-Mode 高效率模式邏輯
 */
library EModeLogic {
    // E-Mode 類別ID
    uint8 public constant EMODE_CATEGORY_NONE = 0;
    uint8 public constant EMODE_CATEGORY_STABLECOINS = 1;
    uint8 public constant EMODE_CATEGORY_ETH = 2;

    /**
     * @notice 啟用 E-Mode
     * @param pool Pool 合約
     * @param categoryId E-Mode 類別 ID
     */
    function enableEMode(
        IPool pool,
        uint8 categoryId
    ) external {
        require(categoryId > 0, "INVALID_CATEGORY");
        
        DataTypes.EModeCategory memory category = pool.getEModeCategoryData(categoryId);
        
        // 驗證用戶當前資產與目標類別兼容
        require(_isCompatibleWithCategory(pool, categoryId), "INCOMPATIBLE_ASSETS");
        
        // 設置用戶的 E-Mode 類別
        pool.setUserEMode(categoryId);
    }

    /**
     * @notice 禁用 E-Mode
     */
    function disableEMode(IPool pool) external {
        pool.setUserEMode(0);
    }

    /**
     * @notice 檢查資產是否與 E-Mode 類別兼容
     */
    function _isCompatibleWithCategory(
        IPool pool,
        uint8 categoryId
    ) internal view returns (bool) {
        DataTypes.UserConfigurationMap memory userConfig = pool.getUserConfiguration(msg.sender);
        
        // 獲取所有儲備
        address[] memory reserves = pool.getReservesList();
        
        for (uint256 i = 0; i < reserves.length; i++) {
            address reserve = reserves[i];
            DataTypes.ReserveData memory reserveData = pool.getReserveData(reserve);
            
            // 檢查用戶是否使用該資產作為抵押品
            if (userConfig.isUsingAsCollateral(reserve)) {
                // 檢查是否與目標類別兼容
                require(
                    _isAssetCompatibleWithCategory(reserveData, categoryId),
                    "ASSET_NOT_COMPATIBLE"
                );
            }
        }
        
        return true;
    }

    /**
     * @notice 檢查單一資產是否與類別兼容
     */
    function _isAssetCompatibleWithCategory(
        DataTypes.ReserveData memory reserveData,
        uint8 categoryId
    ) internal pure returns (bool) {
        if (categoryId == 0) return true;
        
        // 獲取資產的 E-Mode 類別
        uint8 assetCategory = reserveData.configuration.getEModeCategory();
        
        return assetCategory == categoryId;
    }

    /**
     * @notice 計算 E-Mode 下的借款限額
     * @param user  用戶地址
     * @param totalCollateral  總抵押品價值
     * @param totalDebt  總債務價值
     * @param ltv  LTV
     * @param liquidationThreshold  清算閾值
     * @param userEModeCategory  用戶 E-Mode 類別
     */
    function calculateEModeBorrowingPower(
        uint256 totalCollateral,
        uint256 totalDebt,
        uint256 ltv,
        uint256 liquidationThreshold,
        uint8 userEModeCategory
    ) internal pure returns (uint256) {
        if (userEModeCategory == 0) {
            // 非 E-Mode 模式,使用標準計算
            return (totalCollateral * ltv) / 10000 - totalDebt;
        }
        
        // E-Mode 模式下,使用更高的 LTV
        uint256 eModeLtv = _getEModeLtv(userEModeCategory);
        uint256 eModeLt = _getEModeLiquidationThreshold(userEModeCategory);
        
        // E-Mode 允許更高效的借款
        return (totalCollateral * eModeLtv) / 10000 - totalDebt;
    }

    function _getEModeLtv(uint8 categoryId) internal pure returns (uint256) {
        // E-Mode 類別對應的 LTV
        if (categoryId == EMODE_CATEGORY_STABLECOINS) {
            return 9000; // 90% LTV for stablecoins in E-Mode
        } else if (categoryId == EMODE_CATEGORY_ETH) {
            return 9000; // 90% LTV for ETH in E-Mode
        }
        return 8000; // 預設 80%
    }

    function _getEModeLiquidationThreshold(uint8 categoryId) internal pure returns (uint256) {
        if (categoryId == EMODE_CATEGORY_STABLECOINS) {
            return 9500; // 95% for stablecoins
        } else if (categoryId == EMODE_CATEGORY_ETH) {
            return 9500;
        }
        return 8500;
    }
}

5.2 隔離模式(Isolation Mode)

隔離模式允許新資產以隔離模式上線,限制該資產作為抵押品時只能借出特定資產,降低系統性風險:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

/**
 * @title IsolationModeLogic
 * @notice Aave V3 隔離模式邏輯
 */
library IsolationModeLogic {
    /**
     * @notice 以隔離模式借款
     * @param vars 借款參數
     */
    function executeIsolationModeBorrow(
        DataTypes.IsolationModeBorrowParams memory vars
    ) external {
        // 1. 驗證借款資產是否為隔離資產
        require(
            vars.reserveData.configuration.getIsolationMode(),
            "NOT_ISOLATION_MODE_ASSET"
        );

        // 2. 獲取隔離資產的借款上限
        uint256 isolationModeDebtCeiling = vars.reserveData.configuration.getDebtCeiling();
        
        // 3. 計算當前隔離模式總債務
        uint256 currentIsolationModeTotalDebt = vars.reserveData.isolationModeTotalDebt;
        
        // 4. 驗證不超過上限
        uint256 newIsolationModeTotalDebt = currentIsolationModeTotalDebt + vars.amount;
        require(
            newIsolationModeTotalDebt <= isolationModeDebtCeiling,
            "DEBT_CEILING_EXCEEDED"
        );

        // 5. 隔離模式下只能借款借款資產本身
        // (隔離模式限制:只能用隔離資產借穩定幣)
        require(
            _isBorrowingAllowedInIsolation(vars.reserveData, vars.asset),
            "ISOLATION_MODE_BORROWING_VIOLATION"
        );

        // 6. 執行借款
        vars.pool.borrow(vars.asset, vars.amount, vars.interestRateMode, vars.referralCode, vars.onBehalfOf);
    }

    /**
     * @notice 驗證隔離模式借款是否允許
     */
    function _isBorrowingAllowedInIsolation(
        DataTypes.ReserveData memory reserveData,
        address borrowAsset
    ) internal pure returns (bool) {
        // 在隔離模式下,只能借款白名單中的資產
        // 通常是穩定幣
        address[] memory isolationModeBorrowable = reserveData.isolationModeBorrowable;
        
        for (uint256 i = 0; i < isolationModeBorrowable.length; i++) {
            if (isolationModeBorrowable[i] == borrowAsset) {
                return true;
            }
        }
        
        return isolationModeBorrowable.length == 0;
    }
}

六、閃電貸實作與應用場景

6.1 閃電貸機制詳解

閃原子貸(Flash Loans)是 Aave 協議最具創新性的功能之一,允許用戶在單一交易內無需抵押品借貸大量資金。這個看似不可能的功能依賴於智慧合約的原子性——如果借款人在交易結束前未能償還借款,整個交易會被回滾,相當於借款從未發生。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

/**
 * @title FlashLoanReceiverBase
 * @notice 閃電貸接收者基礎合約
 */
abstract contract FlashLoanReceiverBase is IFlashLoanReceiver {
    IPoolAddressesProvider public immutable override ADDRESSES_PROVIDER;
    ILendingPool public immutable override LENDING_POOL;

    constructor(address addressesProvider) {
        ADDRESSES_PROVIDER = IPoolAddressesProvider(addressesProvider);
        LENDING_PENDING = ILendingPool(IPoolAddressesProvider(addressesProvider).getLendingPool());
    }
}

/**
 * @title IFlashLoanReceiver
 * @notice 閃電貸回調介面
 */
interface IFlashLoanReceiver {
    function ADDRESSES_PROVIDER() external view returns (IPoolAddressesProvider);
    function LENDING_POOL() external view returns (ILendingPool);

    /**
     * @notice 閃電貸回調函數
     * @param assets 借款的資產地址陣列
     * @param amounts 借款的金額陣列
     * @param premiums 借款手續費(溢價)陣列
     * @param initiator 發起閃電貸的地址
     * @param params 回調的額外參數
     * @return 需要返回的值(通常是 true)
     */
    function executeOperation(
        address[] calldata assets,
        uint256[] calldata amounts,
        uint256[] calldata premiums,
        address initiator,
        bytes calldata params
    ) external returns (bool);
}

6.2 閃電貸套利實作範例

以下是一個完整的閃電貸套利合約範例,展示了如何在單一交易中完成套利:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

import {FlashLoanReceiverBase} from "./FlashLoanReceiverBase.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IPool} from "./IPool.sol";

/**
 * @title ArbitrageFlashLoan
 * @notice 閃電貸套利合約範例
 * @dev 此合約僅用於教育目的,實際套利需要考慮更多風險因素
 */
contract ArbitrageFlashLoan is FlashLoanReceiverBase {
    using SafeERC20 for IERC20;

    // 利率閾值:扣除手續費後的最低收益要求
    uint256 public constant MIN_PROFIT_THRESHOLD = 0.001 ether;
    
    // 合約所有者
    address public owner;

    // 路由器地址(用於 DEX 交易)
    address public uniswapRouter;
    address public sushiswapRouter;
    address public balancerVault;

    // 代幣地址
    address public weth;
    address public usdc;
    address public usdt;
    address public dai;

    // 事件
    event ArbitrageExecuted(
        address indexed token,
        uint256 profit,
        uint256 loanAmount
    );

    modifier onlyOwner() {
        require(msg.sender == owner, "ONLY_OWNER");
        _;
    }

    constructor(
        address _addressesProvider,
        address _uniswapRouter,
        address _sushiswapRouter,
        address _balancerVault,
        address _weth,
        address _usdc,
        address _usdt,
        address _dai
    ) FlashLoanReceiverBase(_addressesProvider) {
        owner = msg.sender;
        uniswapRouter = _uniswapRouter;
        sushiswapRouter = _sushiswapRouter;
        balancerVault = _balancerVault;
        weth = _weth;
        usdc = _usdc;
        usdt = _usdt;
        dai = _dai;
    }

    /**
     * @notice 執行套利閃電貸
     * @param borrowToken 要借貸的代幣地址
     * @param borrowAmount 借貸金額
     * @param exchangePath 交易路徑
     */
    function executeArbitrage(
        address borrowToken,
        uint256 borrowAmount,
        bytes calldata exchangePath
    ) external onlyOwner {
        address[] memory assets = new address[](1);
        assets[0] = borrowToken;

        uint256[] memory amounts = new uint256[](1);
        amounts[0] = borrowAmount;

        uint256[] memory modes = new uint256[](1);
        modes[0] = 0; // 0 = 必須在同筆交易償還

        // 調用閃電貸
        LENDING_POOL.flashLoan(
            address(this),
            assets,
            amounts,
            modes,
            address(this),
            exchangePath,
            0
        );
    }

    /**
     * @notice 閃電貸回調函數
     */
    function executeOperation(
        address[] calldata assets,
        uint256[] calldata amounts,
        uint256[] calldata premiums,
        address /* initiator */,
        bytes calldata params
    ) external override returns (bool) {
        require(msg.sender == address(LENDING_POOL), "CALLER_MUST_BE_LENDING_POOL");

        // 解碼交易路徑
        (address[] memory swapPath, uint256 minProfit) = abi.decode(
            params, 
            (address[], uint256)
        );

        // 1. 借貸的代幣
        address borrowToken = assets[0];
        uint256 borrowAmount = amounts[0];
        uint256 premium = premiums[0];

        // 2. 在第一個 DEX 賣出借貸代幣
        uint256 receivedAmount = _swapOnDEX(
            swapPath[0], 
            swapPath[1], 
            borrowAmount,
            uniswapRouter
        );

        // 3. 沿路徑繼續交易
        for (uint256 i = 1; i < swapPath.length - 1; i++) {
            receivedAmount = _swapOnDEX(
                swapPath[i],
                swapPath[i + 1],
                receivedAmount,
                i % 2 == 0 ? uniswapRouter : sushiswapRouter
            );
        }

        // 4. 換回借貸代幣
        uint256 finalAmount = _swapOnDEX(
            swapPath[swapPath.length - 1],
            borrowToken,
            receivedAmount,
            sushiswapRouter
        );

        // 5. 計算利潤
        uint256 totalRepayment = borrowAmount + premium;
        require(finalAmount >= totalRepayment + minProfit, "INSUFFICIENT_PROFIT");

        // 6. 償還閃電貸
        uint256 profit = finalAmount - totalRepayment;
        
        // 批准還款
        IERC20(borrowToken).safeApprove(address(LENDING_POOL), totalRepayment);

        // 轉出利潤給所有者
        if (profit > 0) {
            IERC20(borrowToken).safeTransfer(owner, profit);
            emit ArbitrageExecuted(borrowToken, profit, borrowAmount);
        }

        return true;
    }

    /**
     * @notice 在 DEX 上進行 Swap
     */
    function _swapOnDEX(
        address fromToken,
        address toToken,
        uint256 amountIn,
        address router
    ) internal returns (uint256) {
        IERC20(fromToken).safeApprove(router, amountIn);

        // 構建 swap 路徑
        address[] memory path = new address[](2);
        path[0] = fromToken;
        path[1] = toToken;

        // 調用 DEX router(這裡以 Uniswap V2 為例)
        uint256[] memory amounts = IUniswapV2Router02(router).swapExactTokensForTokens(
            amountIn,
            0,  // 最小輸出(實際應設置滑點保護)
            path,
            address(this),
            block.timestamp + 300
        );

        return amounts[1];
    }

    /**
     * @notice 提取錯誤發送的代幣
     */
    function rescueTokens(
        address token,
        address to,
        uint256 amount
    ) external onlyOwner {
        require(to != address(0), "INVALID_ADDRESS");
        IERC20(token).safeTransfer(to, amount);
    }
}

6.3 閃電貸風險與限制

使用閃電貸時需要注意以下風險和限制:

閃電貸風險分析:

1. 智慧合約風險
   - 依賴多個外部合約,任何一個漏洞都可能导致资金损失
   - DEX 路由合約可能存在漏洞
   - 套利合約本身可能存在安全問題

2. 市場風險
   - 價格波動:套利機會可能在交易確認前消失
   - 滑點:大量交易導致價格變動,侵蝕利潤
   - 流動性不足:無法執行完整交易

3. 技術風險
   - Gas 限制:複雜操作可能超過區塊 Gas 限制
   - 交易失敗:網路擁堵導致交易失敗
   - MEV:礦工可能搶先套利機會

4. 經濟風險
   - 手續費:高 Gas 費用可能侵蝕利潤
   - 競爭激烈:套利空間通常很小且轉瞬即逝

實際套利收益計算示例:

假設:
- 借貸金額: 1,000,000 USDC
- 閃電貸手續費: 0.09% = 900 USDC
- Uniswap 滑點: 0.3%
- Sushiswap 滑點: 0.3%
- 預期套利空間: 0.5%

計算:
- 預期收入: 1,000,000 × 1.005 = 1,005,000 USDC
- Uniswap 費用: 1,000,000 × 0.003 = 3,000 USDC
- Sushiswap 費用: 1,005,000 × 0.003 = 3,015 USDC
- 預期利潤: 1,005,000 - 1,000,000 - 900 - 3,000 - 3,015 = -1,915 USDC

結論:在正常市場條件下,單純的代幣對套利很難獲利
實際套利需要更複雜的策略,如:
- 跨協議套利
- 清算套利
- 質押品重組

七、整合開發實踐

7.1 與 Aave 協議交互的完整範例

以下是一個完整的 TypeScript/JavaScript 範例,展示如何與 Aave V3 協議進行交互:

import { ethers, providers, Wallet, BigNumber } from 'ethers';
import { IPool__factory, IERC20__factory } from './typechain';

// Aave V3 Pool 地址 (Mainnet)
const AAVE_POOL_ADDRESS = '0x87870Bca3F3f6335e32cdC58387a8fCC3BD3C9DE';

// 常用代幣地址
const TOKENS = {
  USDC: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
  WETH: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
  AAVE: '0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9'
};

class AaveV3Service {
  private provider: providers.JsonRpcProvider;
  private wallet: Wallet;
  private pool: IPool;
  private signer: ethers.Signer;

  constructor(rpcUrl: string, privateKey: string) {
    this.provider = new providers.JsonRpcProvider(rpcUrl);
    this.wallet = new Wallet(privateKey, this.provider);
    this.pool = IPool__factory.connect(AAVE_POOL_ADDRESS, this.wallet);
    this.signer = this.wallet;
  }

  /**
   * 獲取用戶帳戶數據
   */
  async getUserAccountData(userAddress: string) {
    const data = await this.pool.getUserAccountData(userAddress);
    
    return {
      totalCollateralBase: data.totalCollateralBase,
      totalDebtBase: data.totalDebtBase,
      availableBorrowsBase: data.availableBorrowsBase,
      currentLiquidationThreshold: data.currentLiquidationThreshold,
      ltv: data.ltv,
      healthFactor: data.healthFactor
    };
  }

  /**
   * 存款
   */
  async supply(asset: string, amount: BigNumber, onBehalfOf?: string) {
    const token = IERC20__factory.connect(asset, this.signer);
    
    // 批准代幣轉帳
    const approveTx = await token.approve(AAVE_POOL_ADDRESS, amount);
    await approveTx.wait();
    
    // 執行存款
    const tx = await this.pool.supply(
      asset,
      amount,
      onBehalfOf || this.wallet.address,
      0 // referral code
    );
    
    return await tx.wait();
  }

  /**
   * 借款
   */
  async borrow(
    asset: string, 
    amount: BigNumber, 
    interestRateMode: number = 1 // 1 = 浮動, 2 = 穩定
  ) {
    const tx = await this.pool.borrow(
      asset,
      amount,
      interestRateMode,
      0, // referral code
      this.wallet.address
    );
    
    return await tx.wait();
  }

  /**
   * 還款
   */
  async repay(
    asset: string, 
    amount: BigNumber, 
    interestRateMode: number = 1
  ) {
    const token = IERC20__factory.connect(asset, this.signer);
    
    // 批准代幣轉帳
    await token.approve(AAVE_POOL_ADDRESS, amount);
    
    const tx = await this.pool.repay(
      asset,
      amount,
      interestRateMode,
      this.wallet.address
    );
    
    return await tx.wait();
  }

  /**
   * 提款
   */
  async withdraw(asset: string, amount: BigNumber, to?: string) {
    const tx = await this.pool.withdraw(
      asset,
      amount,
      to || this.wallet.address
    );
    
    return await tx.wait();
  }

  /**
   * 獲取儲備數據
   */
  async getReserveData(asset: string) {
    return await this.pool.getReserveData(asset);
  }

  /**
   * 計算健康因子
   */
  async calculateHealthFactor() {
    const accountData = await this.getUserAccountData(this.wallet.address);
    
    // 健康因子 = (抵押品 × 清算閾值) / 債務
    if (accountData.totalDebtBase === 0) {
      return ethers.constants.MaxUint256;
    }
    
    const weightedCollateral = 
      accountData.totalCollateralBase * 
      accountData.currentLiquidationThreshold / 10000;
    
    return weightedCollateral / accountData.totalDebtBase;
  }

  /**
   * 獲取 aToken 地址
   */
  async getATokenAddress(asset: string) {
    const reserveData = await this.getReserveData(asset);
    return reserveData.aTokenAddress;
  }

  /**
   * 檢查是否可以使用 E-Mode
   */
  async checkEModeCompatibility(categoryId: number) {
    const userEmode = await this.pool.getUserEModeData(this.wallet.address);
    
    if (userEmode === 0 && categoryId > 0) {
      // 可以啟用 E-Mode
      return {
        canEnable: true,
        currentMode: 'Normal'
      };
    } else if (userEmode === categoryId) {
      return {
        canEnable: false,
        currentMode: 'EMode'
      };
    }
    
    return {
      canEnable: false,
      currentMode: userEmode > 0 ? 'EMode' : 'Normal',
      reason: 'Switching between E-Mode categories requires disabling first'
    };
  }
}

// 使用範例
async function main() {
  const service = new AaveV3Service(
    process.env.RPC_URL!,
    process.env.PRIVATE_KEY!
  );

  // 1. 獲取帳戶數據
  const accountData = await service.getUserAccountData(
    '0xYourAddress...'
  );
  console.log('可用借款額度:', 
    ethers.utils.formatUnits(accountData.availableBorrowsBase, 8)
  );
  console.log('健康因子:', 
    ethers.utils.formatEther(accountData.healthFactor)
  );

  // 2. 存入 ETH 作為抵押品
  const ethAmount = ethers.utils.parseEther('1');
  await service.supply(TOKENS.WETH, ethAmount);
  console.log('存款成功');

  // 3. 借款 USDC
  const usdcAmount = ethers.utils.parseUnits('1000', 6);
  await service.borrow(TOKENS.USDC, usdcAmount, 1);
  console.log('借款成功');
}

main().catch(console.error);

八、結論與最佳實踐

8.1 開發最佳實踐

在使用 Aave 協議進行開發時,以下是一些重要的最佳實踐建議:

Aave 開發最佳實踐:

1. 安全考量
   - 始終驗證用戶的健康因子在安全範圍內
   - 實現你自己的清算機器人來保護抵押品
   - 使用多重簽名來管理協議交互
   - 定期檢查並更新利率策略

2. 錯誤處理
   - 處理所有可能的 Revert 情況
   - 實現重試機制處理暫時性失敗
   - 監控 Gas 價格優化交易成本

3. 監控與報警
   - 實時監控健康因子變化
   - 設置清算閾值預警
   - 追蹤利率變動趨勢

4. 風險管理
   - 不要借貸超過你能承受清算的金額
   - 分散抵押品以降低單一資產風險
   - 保持足夠的流動性緩沖

8.2 未來發展方向

Aave 協議仍在持續演進,未來的發展方向包括:

Aave 未來發展趨勢:

1. 跨鏈擴展
   - 更廣泛的跨鏈橋接支持
   - 統一的跨鏈借貸市場

2. 風險管理改進
   - 更精細的風險參數
   - AI 驅動的風險評估

3. 收益優化
   - 自動收益複合策略
   - 結構化收益產品

4. 機構採用
   - 機構級別的合規框架
   - 托管解決方案集成

本文深入分析了 Aave V3 借貸協議的核心機制與程式碼實作。透過理解利率模型、抵押品管理、清算機制和進階功能,開發者可以更安全有效地在 Aave 基礎上構建應用,同時用戶也能更好地理解和管理自己的借貸風險。

延伸閱讀與來源

這篇文章對您有幫助嗎?

評論

發表評論

注意:由於這是靜態網站,您的評論將儲存在本地瀏覽器中,不會公開顯示。

目前尚無評論,成為第一個發表評論的人吧!