Aave V3 抵押借款實機操作完整指南:從基礎操作到進階策略

Aave 是以太坊生態系統中最重要且最成功的去中心化借貸協議之一。本文從工程師和實際操作者的視角出發,提供 Aave V3 的完整實機操作指南。涵蓋協議架構解析、抵押借款核心操作、風險管理策略、健康因子計算、以及如何在實際市場環境中執行各種借貸策略。同時提供完整的 JavaScript/TypeScript 程式碼範例。

Aave V3 抵押借款實機操作完整指南:從基礎操作到進階策略

概述

Aave 是以太坊生態系統中最重要且最成功的去中心化借貸協議之一。截至 2026 年第一季度,Aave 的總鎖定價值(TVL)已超過 100 億美元,累計借款量超過 2000 億美元。作為一名 DeFi 投資者或開發者,深入理解 Aave V3 的運作機制、掌握實際操作技能,是參與 DeFi 生態的必備能力。

本文從工程師和實際操作者的視角出發,提供 Aave V3 的完整實機操作指南。我們將涵蓋協議架構解析、抵押借款核心操作、風險管理策略、健康因子計算、以及如何在實際市場環境中執行各種借貸策略。同時,我們將提供完整的 JavaScript/TypeScript 程式碼範例,幫助開發者構建自己的借貸機器人或整合方案。

第一章:Aave V3 協議架構深度解析

1.1 協議核心組件

Aave V3 的架構由多個智能合約組成,每個合約都有其特定的角色和職責:

Aave V3 合約架構:

┌─────────────────────────────────────────────────────┐
│                                                     │
│  Pool Addresses Provider                           │
│  ├── 協議配置中心                                  │
│  ├── 版本管理                                      │
│  └── ACL 管理(訪問控制列表)                     │
│                                                     │
│  Pool Configurator                                 │
│  ├── 池子參數配置                                 │
│  ├── 抵押品啟用/停用                              │
│  └── 利率模型調整                                  │
│                                                     │
│  Pool(核心)                                      │
│  ├── supply()        - 存款                       │
│  ├── borrow()        - 借款                       │
│  ├── withdraw()      - 提款                       │
│  ├── repay()         - 還款                       │
│  ├── liquidationCall() - 清算                     │
│  └── flashLoan()     - 閃電貸                     │
│                                                     │
│  aTokens(利息代幣)                              │
│  ├── aToken 鑄造(存款時)                       │
│  ├── aToken 銷毀(提款時)                       │
│  └── 1:1 掛鉤儲備資產                           │
│                                                     │
│  Incentives Controller                             │
│  ├── 獎勵分發                                     │
│  └── 質押激勵                                     │
│                                                     │
└─────────────────────────────────────────────────────┘

1.2 關鍵合約地址(以太坊主網)

// Aave V3 主網合約地址
const AAVE_V3_ADDRESSES = {
  // 核心 Pool 合約
  POOL: '0x87870Bca3F3fD6335C3F4cE2E13E25FFa541Cb4d',
  
  // Pool 合約可配置器
  POOL_CONFIGURATOR: '0x64b761D848B7D2A2FC8C7C34B4d0B8b0B32f90eA',
  
  // 地址提供者
  ADDRESSES_PROVIDER: '0x2f39d218133AFaB8F2n819871B2548bBd5bFD93',
  
  // 抵押品代幣工廠
  ATOKEN_FACTORY: '0x3E50fC6707B769cF95B8dB4cB1B3f3F6C5f3B3F6',
  
  // 協議資料Provider
  DATA_PROVIDER: '0x7B4EB56F7eC2A23b1e3B2B5D9F0f2A3C4F5B4A3',
  
  // SWAP_ROUTER(Aave V3 抵押品交換)
  SWAP_ROUTER: '0xB969A1B3F4C18fF7d3F6f0D7a2B2C1D0E9F8A7B6',
  
  // 收藏夾
  COLLECTOR: '0x464C71f6c11F4b49F2c4E6b7f2B3D4C5E6F7A8B',
};

// 常用資產地址
const ASSETS = {
  WETH: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
  USDC: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
  DAI: '0x6B175474E89094C44Da98b954EescdeCB5BE3830',
  USDT: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
  WBTC: '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599',
  AAVE: '0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9',
};

1.3 Aave V3 的關鍵創新

相比 V2 版本,Aave V3 引入了多項重要改進:

Aave V3 核心創新:

┌─────────────────────────────────────────────────────┐
│                                                     │
│  1. High Efficiency Mode (隔離模式)                 │
│  ├── 允許抵押隔離的高波動性資產                    │
│  ├── 限制隔離抵押品只能借穩定幣                    │
│  └── 降低協議風險                                 │
│                                                     │
│  2. Isolation Mode                                 │
│  ├── 借款人的隔離抵押品有獨立的抵押上限           │
│  ├── 隔離資產不能作為其他資產的抵押               │
│  └── 適用於新的/高風險資產                        │
│                                                     │
│  3. Supply and Borrow Cap                          │
│  ├── 限制總存款量和借款量                          │
│  ├── 防止單一資產風險過度集中                     │
│  └── 由治理決定                                   │
│                                                     │
│  4. Portal                                         │
│  ├── 跨市場資產轉移                               │
│  ├── 提高資金效率                                 │
│  └── 為機構設計                                  │
│                                                     │
│  5. 改進的利率模型                                │
│  ├── 更高的存款利率跨入點                        │
│  ├── 更好的協議費用結構                          │
│  └── 穩定的借貸成本                              │
│                                                     │
│  6. 抵押品交換                                    │
│  ├── 不退出借款頭寸 更換抵押品                   │
│  ├── 降低 Gas 成本                               │
│  └── 提高資金效率                                 │
│                                                     │
└─────────────────────────────────────────────────────┘

第二章:與 Aave V3 交互的開發環境配置

2.1 使用 ethers.js 與 Aave 交互

// 安裝依賴
// npm install ethers @aave/core-v3

import { ethers } from 'ethers';

// 連接錢包
const connectWallet = async () => {
  if (!window.ethereum) {
    throw new Error('請安裝 MetaMask');
  }
  
  const provider = new ethers.BrowserProvider(window.ethereum);
  const signer = await provider.getSigner();
  
  return { provider, signer };
};

// 初始化 Aave V3 Pool 合約
const getPoolContract = (signer) => {
  const poolAddress = '0x87870Bca3F3fD6335C3F4cE2E13E25FFa541Cb4d';
  const poolABI = [
    // 存款
    'function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external',
    // 借款
    'function borrow(address asset, uint256 amount, uint256 interestRateMode, uint16 referralCode, address onBehalfOf) external',
    // 提款
    'function withdraw(address asset, uint256 amount, address to) external returns (uint256)',
    // 還款
    'function repay(address asset, uint256 amount, uint256 rateMode, address onBehalfOf) external returns (uint256)',
    // 閃電貸
    'function flashLoan(address receiverAddress, address[] calldata assets, uint256[] calldata amounts, uint256[] calldata modes, address onBehalfOf, bytes calldata params, uint16 referralCode) external',
    // 清算
    'function liquidationCall(address collateralAsset, address debtAsset, address user, uint256 debtToCover, bool receiveAToken) external',
  ];
  
  return new ethers.Contract(poolAddress, poolABI, signer);
};

// 初始化 aToken 合約
const getATokenContract = (asset, signer) => {
  // 從 Pool 獲取 aToken 地址
  const pool = getPoolContract(signer);
  const aTokenAddress = await pool.getReserveData(asset);
  
  const aTokenABI = [
    'function balanceOf(address account) external view returns (uint256)',
    'function scaledBalanceOf(address user) external view returns (uint256)',
    'function getScaledUserBalanceAndSupply(address user) external view returns (uint256, uint256)',
  ];
  
  return new ethers.Contract(aTokenAddress.aTokenAddress, aTokenABI, signer);
};

2.2 使用 viem 與 Aave 交互(推薦)

// 安裝依賴
// npm install viem @tanstack/react-query

import { createPublicClient, createWalletClient, http, custom } from 'viem';
import { mainnet } from 'viem/chains';

// 創建客戶端
const publicClient = createPublicClient({
  chain: mainnet,
  transport: http('https://eth.llamarpc.com'),
});

const getWalletClient = () => {
  if (typeof window === 'undefined' || !window.ethereum) {
    throw new Error('請安裝 MetaMask');
  }
  return createWalletClient({
    account: window.ethereum.selectedAddress,
    chain: mainnet,
    transport: custom(window.ethereum),
  });
};

// Aave V3 ABI 定義
export const POOL_ABI = [
  {
    name: 'supply',
    type: 'function',
    inputs: [
      { name: 'asset', type: 'address' },
      { name: 'amount', type: 'uint256' },
      { name: 'onBehalfOf', type: 'address' },
      { name: 'referralCode', type: 'uint16' },
    ],
    outputs: [],
    stateMutability: 'nonpayable',
  },
  {
    name: 'borrow',
    type: 'function',
    inputs: [
      { name: 'asset', type: 'address' },
      { name: 'amount', type: 'uint256' },
      { name: 'interestRateMode', type: 'uint256' },
      { name: 'referralCode', type: 'uint16' },
      { name: 'onBehalfOf', type: 'address' },
    ],
    outputs: [],
    stateMutability: 'nonpayable',
  },
  {
    name: 'withdraw',
    type: 'function',
    inputs: [
      { name: 'asset', type: 'address' },
      { name: 'amount', type: 'uint256' },
      { name: 'to', type: 'address' },
    ],
    outputs: [{ name: '', type: 'uint256' }],
    stateMutability: 'nonpayable',
  },
  {
    name: 'repay',
    type: 'function',
    inputs: [
      { name: 'asset', type: 'address' },
      { name: 'amount', type: 'uint256' },
      { name: 'rateMode', type: 'uint256' },
      { name: 'onBehalfOf', type: 'address' },
    ],
    outputs: [{ name: '', type: 'uint256' }],
    stateMutability: 'nonpayable',
  },
] as const;

export const POOL_ADDRESS = '0x87870Bca3F3fD6335C3F4cE2E13E25FFa541Cb4d';

2.3 讀取用戶頭寸數據

import { ethers } from 'ethers';

// 使用 Aave 數據提供者的完整 ABI
const DATA_PROVIDER_ABI = [
  'function getUserAccountData(address user) external view returns (uint256 totalCollateralBase, uint256 totalDebtBase, uint256 availableBorrowsBase, uint256 currentLiquidationThreshold, uint256 ltv, uint256 healthFactor)',
  'function getUserReserveData(address user, address asset) external view returns (uint256 currentATokenBalance, uint256 currentStableDebt, uint256 currentVariableDebt, uint256 principalStableDebt, uint256 stableBorrowRate, uint256 stableRateLastUpdated, uint256 usageAsCollateralEnabledOnUser)',
  'function getReserveData(address asset) external view returns (tuple(uint256 configuration, uint128 liquidityIndex, uint128 currentLiquidityIndex, uint128 variableBorrowIndex, uint128 currentVariableBorrowIndex, uint128 currentStableBorrowRate, uint40 lastUpdateTimestamp, uint16 id, address aTokenAddress, address stableDebtTokenAddress, address variableDebtTokenAddress, address interestRateStrategyAddress, uint128 accruedToTreasury, uint128 unbacked, uint128 isolationModeTotalDebt))',
];

// 初始化 Data Provider
const getDataProvider = (provider) => {
  return new ethers.Contract(
    '0x7B4EB56F7eC2A23b1e3B2B5D9F0f2A3C4F5B4A3',
    DATA_PROVIDER_ABI,
    provider
  );
};

// 獲取完整的用戶帳戶數據
const getUserAccountData = async (userAddress) => {
  const provider = new ethers.JsonRpcProvider('https://eth.llamarpc.com');
  const dataProvider = getDataProvider(provider);
  
  const [
    totalCollateralBase,
    totalDebtBase,
    availableBorrowsBase,
    currentLiquidationThreshold,
    ltv,
    healthFactor
  ] = await dataProvider.getUserAccountData(userAddress);
  
  return {
    totalCollateralUSD: Number(ethers.formatUnits(totalCollateralBase, 8)) / 100,
    totalDebtUSD: Number(ethers.formatUnits(totalDebtBase, 8)) / 100,
    availableBorrowsUSD: Number(ethers.formatUnits(availableBorrowsBase, 8)) / 100,
    currentLiquidationThreshold: Number(ethers.formatUnits(currentLiquidationThreshold, 4)),
    ltv: Number(ethers.formatUnits(ltv, 4)),
    healthFactor: Number(ethers.formatUnits(healthFactor, 18)),
  };
};

// 獲取特定資產的用戶頭寸
const getUserReserveData = async (userAddress, assetAddress) => {
  const provider = new ethers.JsonRpcProvider('https://eth.llamarpc.com');
  const dataProvider = getDataProvider(provider);
  
  const data = await dataProvider.getUserReserveData(userAddress, assetAddress);
  
  return {
    currentATokenBalance: data.currentATokenBalance,
    currentStableDebt: data.currentStableDebt,
    currentVariableDebt: data.currentVariableDebt,
    principalStableDebt: data.principalStableDebt,
    stableBorrowRate: data.stableBorrowRate,
    stableRateLastUpdated: new Date(Number(data.stableRateLastUpdated) * 1000),
    usageAsCollateralEnabled: data.usageAsCollateralEnabledOnUser,
  };
};

// 監控用戶頭寸變化
const watchUserPosition = async (userAddress, callback) => {
  const provider = new ethers.JsonRpcProvider('https://eth.llamarpc.com');
  const poolAddress = '0x87870Bca3F3fD6335C3F4cE2E13E25FFa541Cb4d';
  
  // 監控供應事件
  const supplyFilter = {
    address: poolAddress,
    topics: [
      ethers.id('Supply(address,address,address,uint256,uint16)'),
      null,
      null,
      ethers.zeroPadValue(userAddress, 32),
    ],
  };
  
  // 監控借款事件
  const borrowFilter = {
    address: poolAddress,
    topics: [
      ethers.id('Borrow(address,address,address,uint256,uint256,uint256,uint16)'),
      null,
      null,
      ethers.zeroPadValue(userAddress, 32),
    ],
  };
  
  provider.on(supplyFilter, (log) => {
    const event = parseSupplyEvent(log);
    callback('supply', event);
  });
  
  provider.on(borrowFilter, (log) => {
    const event = parseBorrowEvent(log);
    callback('borrow', event);
  });
  
  return () => {
    provider.off(supplyFilter);
    provider.off(borrowFilter);
  };
};

第三章:抵押借款核心操作

3.1 存款(Supply)

存款是 Aave 的核心功能之一。用戶存款資產後,會收到等量的 aToken,代表用戶在協議中的存款頭寸。

// 存款函數
const supply = async (asset, amount, onBehalfOf) => {
  const { signer } = await connectWallet();
  const pool = getPoolContract(signer);
  
  // 如果是 ETH,需要包裝為 WETH
  let assetAddress = asset;
  if (asset === 'ETH') {
    assetAddress = ASSETS.WETH;
    // 將 ETH 存入 WETH 合約
    const weth = new ethers.Contract(ASSETS.WETH, ['function deposit() payable'], signer);
    await weth.deposit({ value: amount });
  }
  
  // 批准 Pool 合約使用代幣
  const token = new ethers.Contract(assetAddress, ERC20_ABI, signer);
  const poolAddress = await pool.getAddress();
  await token.approve(poolAddress, amount);
  
  // 執行存款
  // referralCode 目前為 0
  const tx = await pool.supply(assetAddress, amount, onBehalfOf || await signer.getAddress(), 0);
  
  console.log('存款交易已提交:', tx.hash);
  const receipt = await tx.wait();
  
  return {
    success: receipt.status === 1,
    transactionHash: receipt.hash,
    gasUsed: receipt.gasUsed.toString(),
  };
};

// 批量存款
const batchSupply = async (deposits) => {
  const results = [];
  
  for (const { asset, amount } of deposits) {
    try {
      const result = await supply(asset, amount);
      results.push({ asset, amount, ...result });
    } catch (error) {
      results.push({ asset, amount, error: error.message });
    }
  }
  
  return results;
};

// 存款事件監聽
const onSupply = (callback) => {
  const provider = new ethers.JsonRpcProvider('https://eth.llamarpc.com');
  const poolAddress = '0x87870Bca3F3fD6335C3F4cE2E13E25FFa541Cb4d';
  
  const filter = {
    address: poolAddress,
    topics: [ethers.id('Supply(address,address,address,uint256,uint16)')],
  };
  
  provider.on(filter, (log) => {
    const parsed = pool.interface.parseLog(log);
    callback({
      reserve: parsed.args[0],
      user: parsed.args[2],
      onBehalfOf: parsed.args[3],
      amount: parsed.args[4],
      referralCode: parsed.args[5],
      timestamp: log.blockNumber,
    });
  });
};

3.2 借款(Borrow)

Aave V3 支持兩種利率模式:穩定利率(Stable Rate)和浮動利率(Variable Rate)。

// 利率模式常量
const INTEREST_RATE_MODE = {
  NONE: 0,
  STABLE: 1,
  VARIABLE: 2,
};

// 借款函數
const borrow = async (asset, amount, interestRateMode, onBehalfOf) => {
  const { signer } = await connectWallet();
  const pool = getPoolContract(signer);
  
  // 檢查用戶的健康因子(借款前)
  const userAddress = await signer.getAddress();
  const accountData = await getUserAccountData(userAddress);
  
  console.log('借款前健康因子:', accountData.healthFactor);
  console.log('可用借款額度:', accountData.availableBorrowsUSD);
  
  // 執行借款
  const tx = await pool.borrow(
    asset,
    amount,
    interestRateMode,
    0, // referralCode
    onBehalfOf || userAddress
  );
  
  console.log('借款交易已提交:', tx.hash);
  const receipt = await tx.wait();
  
  // 檢查借款後的健康因子
  const newAccountData = await getUserAccountData(userAddress);
  console.log('借款後健康因子:', newAccountData.healthFactor);
  
  return {
    success: receipt.status === 1,
    transactionHash: receipt.hash,
    healthFactorAfter: newAccountData.healthFactor,
  };
};

// 借款並自動鑄造 aToken(示例)
const borrowAndSupply = async (borrowAsset, borrowAmount, supplyAsset, supplyAmount) => {
  const { signer } = await connectWallet();
  const pool = getPoolContract(signer);
  const userAddress = await signer.getAddress();
  
  // 1. 先存款以增加抵押品
  await supply(supplyAsset, supplyAmount, userAddress);
  
  // 2. 借款
  await borrow(borrowAsset, borrowAmount, INTEREST_RATE_MODE.VARIABLE, userAddress);
  
  console.log('借款完成');
};

// 計算借款最大額度
const calculateMaxBorrow = async (userAddress, asset, ltvMultiplier = 0.95) => {
  const accountData = await getUserAccountData(userAddress);
  
  // 最大借款額 = 抵押品價值 × LTV × 安全係數
  const maxBorrowUSD = accountData.totalCollateralUSD * (accountData.ltv / 10000) * ltvMultiplier;
  
  // 減去現有借款
  const remainingBorrowPower = maxBorrowUSD - accountData.totalDebtUSD;
  
  return {
    maxBorrowUSD: remainingBorrowPower,
    currentHealthFactor: accountData.healthFactor,
    utilization: accountData.totalDebtUSD / (accountData.totalDebtUSD + remainingBorrowPower),
  };
};

3.3 還款(Repay)

還款時需要注意清算門檻和健康因子變化。

// 還款函數
const repay = async (asset, amount, rateMode, onBehalfOf) => {
  const { signer } = await connectWallet();
  const pool = getPoolContract(signer);
  
  const userAddress = await signer.getAddress();
  const targetUser = onBehalfOf || userAddress;
  
  // 獲取目標用戶的實際債務(可能因利息累積而大於原借款)
  const userReserveData = await getUserReserveData(targetUser, asset);
  
  let repayAmount = amount;
  let actualDebt;
  
  if (rateMode === INTEREST_RATE_MODE.STABLE) {
    actualDebt = userReserveData.currentStableDebt;
  } else {
    actualDebt = userReserveData.currentVariableDebt;
  }
  
  // 如果還款金額 >= 實際債務,設為最大債務
  if (amount >= actualDebt) {
    repayAmount = actualDebt;
  }
  
  // 批准代幣
  const token = new ethers.Contract(asset, ERC20_ABI, signer);
  await token.approve(await pool.getAddress(), repayAmount);
  
  // 執行還款
  // 注意:還款時 amount 設為 type(uint256).max 表示還清全部
  const maxAmount = ethers.MaxUint256;
  const tx = await pool.repay(
    asset,
    repayAmount === amount ? amount : maxAmount,
    rateMode,
    targetUser
  );
  
  console.log('還款交易已提交:', tx.hash);
  const receipt = await tx.wait();
  
  return {
    success: receipt.status === 1,
    amountRepaid: repayAmount,
    transactionHash: receipt.hash,
  };
};

// 自動還款(清算保護)
const autoRepayToProtectHealthFactor = async (asset, minHealthFactor = 1.5) => {
  const { signer } = await connectWallet();
  const userAddress = await signer.getAddress();
  
  // 持續監控直到健康因子高於目標
  let accountData = await getUserAccountData(userAddress);
  
  while (accountData.healthFactor < minHealthFactor) {
    // 計算需要還款多少才能達到目標健康因子
    const targetHealthFactor = minHealthFactor;
    
    // 簡化計算:假設抵押品不變
    // HF = (抵押品 × 清償比率) / 債務
    // 目標 HF = (抵押品 × 清償比率) / (債務 - 還款額)
    // 還款額 = 債務 - (抵押品 × 清償比率) / 目標 HF
    
    const collateralValue = accountData.totalCollateralUSD;
    const liquidationThreshold = accountData.currentLiquidationThreshold / 10000;
    const currentDebt = accountData.totalDebtUSD;
    
    const requiredDebt = collateralValue * liquidationThreshold / targetHealthFactor;
    const repayAmount = currentDebt - requiredDebt;
    
    if (repayAmount <= 0) {
      console.log('已達到目標健康因子');
      break;
    }
    
    console.log(`健康因子 ${accountData.healthFactor.toFixed(2)},嘗試還款 $${repayAmount.toFixed(2)}`);
    
    try {
      await repay(asset, repayAmount, INTEREST_RATE_MODE.VARIABLE, userAddress);
    } catch (error) {
      console.error('還款失敗:', error.message);
      break;
    }
    
    accountData = await getUserAccountData(userAddress);
  }
  
  return accountData.healthFactor;
};

3.4 提款(Withdraw)

// 提款函數
const withdraw = async (asset, amount, to) => {
  const { signer } = await connectWallet();
  const pool = getPoolContract(signer);
  
  const userAddress = await signer.getAddress();
  const recipient = to || userAddress;
  
  // 檢查 aToken 餘額
  const aTokenData = await getUserReserveData(userAddress, asset);
  const aTokenBalance = aTokenData.currentATokenBalance;
  
  let withdrawAmount = amount;
  if (amount >= aTokenBalance) {
    withdrawAmount = aTokenBalance;
  }
  
  if (withdrawAmount === 0n) {
    throw new Error('沒有可提取的資產');
  }
  
  // 檢查提款後的健康因子
  const accountDataBefore = await getUserAccountData(userAddress);
  
  const tx = await pool.withdraw(asset, withdrawAmount, recipient);
  
  console.log('提款交易已提交:', tx.hash);
  const receipt = await tx.wait();
  
  const accountDataAfter = await getUserAccountData(userAddress);
  
  return {
    success: receipt.status === 1,
    amountWithdrawn: withdrawAmount,
    transactionHash: receipt.hash,
    healthFactorBefore: accountDataBefore.healthFactor,
    healthFactorAfter: accountDataAfter.healthFactor,
  };
};

// 最大提款(考慮健康因子)
const withdrawMax = async (asset) => {
  const { signer } = await connectWallet();
  const userAddress = await signer.getAddress();
  
  const accountData = await getUserAccountData(userAddress);
  
  // 計算在保持健康因子 > 1 的情況下最多能提多少
  // HF = (抵押品 × 閾值) / 債務
  // 可提 = 抵押品 - 債務 / 閾值
  
  const liquidationThreshold = accountData.currentLiquidationThreshold / 10000;
  
  if (liquidationThreshold === 0 || accountData.totalDebtUSD === 0) {
    // 沒有債務,可以全部提款
    const aTokenData = await getUserReserveData(userAddress, asset);
    return aTokenData.currentATokenBalance;
  }
  
  const maxCollateralValue = accountData.totalDebtUSD / liquidationThreshold;
  const withdrawableCollateral = accountData.totalCollateralUSD - maxCollateralValue;
  
  // 這裡需要根據資產轉換為具體代幣數量
  // 省略轉換邏輯...
  
  return withdrawableCollateral;
};

第四章:清算機制與實際操作

4.1 清算原理

當借款人的健康因子低於 1 時,該頭寸可以被清算。清算人可以以折扣價購買借款人的抵押品。

// 清算觸發條件
const LIQUIDATION_TRIGGER = 1.0; // 健康因子 < 1

// 清算計算
const calculateLiquidation = async (user, collateralAsset, debtAsset) => {
  const provider = new ethers.JsonRpcProvider('https://eth.llamarpc.com');
  const dataProvider = getDataProvider(provider);
  
  // 獲取用戶帳戶數據
  const accountData = await dataProvider.getUserAccountData(user);
  
  if (accountData.healthFactor >= ethers.parseUnits('1', 18)) {
    console.log('健康因子 >= 1,無法清算');
    return null;
  }
  
  // 獲取借款人的債務數據
  const debtReserveData = await dataProvider.getUserReserveData(user, debtAsset);
  const collateralReserveData = await dataProvider.getUserReserveData(user, collateralAsset);
  
  // 計算最大可清算金額(通常為債務的 50%)
  const maxLiquidatableDebt = accountData.healthFactor < 1.0
    ? accountData.totalDebtBase * 5000n / 10000n // 50%
    : accountData.availableBorrowsBase;
  
  // 獲取資產價格
  const priceOracle = new ethers.Contract(
    '0x54586bE62E3c3580375aE3723C14525306031DaB',
    ['function getAssetPrice(address asset) external view returns (uint256)'],
    provider
  );
  
  const collateralPrice = await priceOracle.getAssetPrice(collateralAsset);
  const debtPrice = await priceOracle.getAssetPrice(debtAsset);
  
  // 計算可獲得的抵押品數量
  // 抵押品數量 = (債務 × 價格) / 抵押品價格 × 清算獎勵
  const liquidationBonus = 1.1; // 通常是 1.05 - 1.1
  
  const collateralAmount = (maxLiquidatableDebt * debtPrice) / 
    (collateralPrice * liquidationBonus);
  
  return {
    user,
    maxLiquidatableDebt,
    collateralAmount,
    healthFactor: accountData.healthFactor,
    debtAsset,
    collateralAsset,
  };
};

// 執行清算
const liquidationCall = async (
  collateralAsset,
  debtAsset,
  user,
  debtToCover,
  receiveAToken = false
) => {
  const { signer } = await connectWallet();
  const pool = getPoolContract(signer);
  
  // 計算清算信息
  const liquidationInfo = await calculateLiquidation(user, collateralAsset, debtAsset);
  
  if (!liquidationInfo) {
    throw new Error('該頭寸不可清算');
  }
  
  // 確保清算人持有足夠的債務代幣
  const debtToken = new ethers.Contract(debtAsset, ERC20_ABI, signer);
  const balance = await debtToken.balanceOf(await signer.getAddress());
  
  if (balance < liquidationInfo.maxLiquidatableDebt) {
    throw new Error('清算人持有債務代幣不足');
  }
  
  // 批准 Pool 使用代幣
  await debtToken.approve(await pool.getAddress(), liquidationInfo.maxLiquidatableDebt);
  
  // 執行清算
  const tx = await pool.liquidationCall(
    collateralAsset,
    debtAsset,
    user,
    liquidationInfo.maxLiquidatableDebt,
    receiveAToken
  );
  
  console.log('清算交易已提交:', tx.hash);
  const receipt = await tx.wait();
  
  return {
    success: receipt.status === 1,
    transactionHash: receipt.hash,
    debtCovered: liquidationInfo.maxLiquidatableDebt,
    collateralReceived: liquidationInfo.collateralAmount,
  };
};

4.2 清算機器人示例

// 清算機器人
class LiquidationBot {
  constructor(privateKey, rpcUrl) {
    this.wallet = new ethers.Wallet(privateKey, new ethers.JsonRpcProvider(rpcUrl));
    this.pool = getPoolContract(this.wallet);
    this.dataProvider = getDataProvider(this.wallet);
  }
  
  async scanForLiquidatablePositions() {
    // 監控新區塊中的健康因子低於閾值的頭寸
    const provider = new ethers.JsonRpcProvider('https://eth.llamarpc.com');
    const poolAddress = await this.pool.getAddress();
    
    const filter = {
      address: poolAddress,
      topics: [
        ethers.id('ReserveUsedAsCollateralEnabled(address,address,bool)'),
      ],
    };
    
    return new Promise((resolve) => {
      provider.on(filter, async (log) => {
        const parsed = this.pool.interface.parseLog(log);
        const user = parsed.args[1];
        
        // 檢查該用戶的頭寸
        const accountData = await this.dataProvider.getUserAccountData(user);
        
        if (accountData.healthFactor < ethers.parseUnits('1', 18)) {
          resolve({
            user,
            healthFactor: Number(ethers.formatUnits(accountData.healthFactor, 18)),
            totalDebt: Number(ethers.formatUnits(accountData.totalDebtBase, 8)),
          });
        }
      });
    });
  }
  
  async executeLiquidation(user, debtAsset, collateralAsset) {
    // 計算清算金額
    const liquidationInfo = await calculateLiquidation(user, collateralAsset, debtAsset);
    
    if (!liquidationInfo) {
      console.log('無可清算頭寸');
      return;
    }
    
    // 檢查利潤
    const profit = await this.calculatePotentialProfit(liquidationInfo);
    
    if (profit <= 0) {
      console.log('清算無利可圖');
      return;
    }
    
    console.log(`清算利潤: $${profit.toFixed(2)}`);
    
    try {
      await liquidationCall(
        collateralAsset,
        debtAsset,
        user,
        liquidationInfo.maxLiquidatableDebt
      );
      console.log('清算成功');
    } catch (error) {
      console.error('清算失敗:', error.message);
    }
  }
  
  async calculatePotentialProfit(liquidationInfo) {
    // 實現利潤計算邏輯
    // ...
  }
}

第五章:健康因子與風險管理

5.1 健康因子計算詳解

健康因子(Health Factor)是衡量借款頭寸安全程度的核心指標:

健康因子計算公式:

        抵押品價值 × 清償比率
HF = ─────────────────────────
             債務總價值

其中:
- 抵押品價值:用戶所有抵押品的當前價值
- 清償比率(LTQ):各抵押品的加權平均清償比率
- 債務總價值:用戶所有借款的當前價值

健康因子 > 1:頭寸安全
健康因子 = 1:清算邊界
健康因子 < 1:可被清算
// 健康因子實時監控
class HealthFactorMonitor {
  constructor(userAddress, assets) {
    this.userAddress = userAddress;
    this.assets = assets;
    this.lastAlert = 0;
    this.alertInterval = 60000; // 1 分鐘
  }
  
  async checkHealthFactor() {
    const accountData = await getUserAccountData(this.userAddress);
    const healthFactor = accountData.healthFactor;
    
    console.log(`健康因子: ${healthFactor.toFixed(4)}`);
    console.log(`抵押品: $${accountData.totalCollateralUSD.toFixed(2)}`);
    console.log(`債務: $${accountData.totalDebtUSD.toFixed(2)}`);
    console.log(`可用借款: $${accountData.availableBorrowsUSD.toFixed(2)}`);
    
    // 警告級別
    if (healthFactor < 1.2) {
      await this.sendAlert('CRITICAL', healthFactor);
    } else if (healthFactor < 1.5) {
      await this.sendAlert('WARNING', healthFactor);
    } else if (healthFactor < 2.0) {
      await this.sendAlert('CAUTION', healthFactor);
    }
    
    return healthFactor;
  }
  
  async sendAlert(level, healthFactor) {
    const now = Date.now();
    if (now - this.lastAlert < this.alertInterval) {
      return; // 避免過度頻繁的警告
    }
    
    console.warn(`[${level}] 健康因子警告: ${healthFactor.toFixed(4)}`);
    this.lastAlert = now;
  }
  
  startMonitoring(intervalMs = 30000) {
    this.intervalId = setInterval(() => this.checkHealthFactor(), intervalMs);
    return () => clearInterval(this.intervalId);
  }
}

// 計算安全借款額度
const calculateSafeBorrowAmount = (accountData, targetHealthFactor) => {
  const liquidationThreshold = accountData.currentLiquidationThreshold;
  
  // 安全借款 = 抵押品 × 閾值 / 目標 HF - 現有債務
  const safeBorrow = 
    (accountData.totalCollateralUSD * liquidationThreshold / 10000 / targetHealthFactor) 
    - accountData.totalDebtUSD;
  
  return Math.max(0, safeBorrow);
};

5.2 風險管理策略

// Aave V3 風險管理策略

// 策略一:保守抵押品管理
const conservativeStrategy = async (userAddress) => {
  const accountData = await getUserAccountData(userAddress);
  
  // 確保健康因子 > 2.0
  const TARGET_HEALTH_FACTOR = 2.0;
  
  if (accountData.healthFactor < TARGET_HEALTH_FACTOR) {
    console.log('健康因子過低,需要補充抵押品或減少債務');
    
    // 計算需要補充多少抵押品
    const requiredCollateral = 
      (accountData.totalDebtUSD * TARGET_HEALTH_FACTOR * 10000) 
      / accountData.currentLiquidationThreshold;
    
    const collateralNeeded = requiredCollateral - accountData.totalCollateralUSD;
    
    return {
      action: 'ADD_COLLATERAL',
      amount: collateralNeeded,
      reason: `需要將健康因子從 ${accountData.healthFactor.toFixed(2)} 提升到 ${TARGET_HEALTH_FACTOR}`,
    };
  }
  
  return { action: 'HOLD', healthFactor: accountData.healthFactor };
};

// 策略二:自動化頭寸再平衡
const rebalancePosition = async (userAddress, targetHF = 2.0) => {
  const accountData = await getUserAccountData(userAddress);
  
  if (accountData.healthFactor > targetHF * 1.2) {
    // 健康因子過高,可以借入更多或減少抵押品
    const maxBorrow = calculateSafeBorrowAmount(accountData, targetHF);
    
    if (maxBorrow > 100) { // 假設 100 USD 門檻
      return {
        action: 'BORROW_MORE',
        suggestedAmount: maxBorrow,
        reason: `健康因子 ${accountData.healthFactor.toFixed(2)} > 目標 ${targetHF} × 1.2`,
      };
    } else {
      return {
        action: 'WITHDRAW_COLLATERAL',
        suggestedAmount: accountData.totalCollateralUSD - 
          (accountData.totalDebtUSD * targetHF * 10000) / accountData.currentLiquidationThreshold,
        reason: '可以安全提取抵押品',
      };
    }
  } else if (accountData.healthFactor < targetHF) {
    // 健康因子低於目標
    const collateralNeeded = 
      (accountData.totalDebtUSD * targetHF * 10000) / accountData.currentLiquidationThreshold
      - accountData.totalCollateralUSD;
    
    return {
      action: 'ADD_COLLATERAL',
      suggestedAmount: collateralNeeded,
      reason: `健康因子 ${accountData.healthFactor.toFixed(2)} < 目標 ${targetHF}`,
    };
  }
  
  return { action: 'HOLD', healthFactor: accountData.healthFactor };
};

// 策略三:利率切換
const switchInterestRateMode = async (userAddress, asset) => {
  const userReserveData = await getUserReserveData(userAddress, asset);
  
  const currentRateMode = userReserveData.stableBorrowRate > 0 
    ? INTEREST_RATE_MODE.STABLE 
    : INTEREST_RATE_MODE.VARIABLE;
  
  // 獲取當前利率
  const poolData = await getReserveData(asset);
  const currentStableRate = Number(ethers.formatUnits(poolData.currentStableBorrowRate, 27)) * 100;
  const currentVariableRate = Number(ethers.formatUnits(poolData.currentVariableBorrowIndex, 27)) 
    * (await getCurrentVariableRate(poolData));
  
  // 預測利率趨勢(需要更複雜的模型)
  const ratePrediction = await predictInterestRate(asset);
  
  const targetRateMode = ratePrediction.variableIncreasing 
    ? INTEREST_RATE_MODE.STABLE 
    : INTEREST_RATE_MODE.VARIABLE;
  
  if (currentRateMode !== targetRateMode) {
    console.log(`建議從 ${currentRateMode === 1 ? '穩定' : '浮動'}利率切換到 ${targetRateMode === 1 ? '穩定' : '浮動'}利率`);
    
    // 執行切換:先還款再借款
    const debt = currentRateMode === INTEREST_RATE_MODE.STABLE
      ? userReserveData.currentStableDebt
      : userReserveData.currentVariableDebt;
    
    await repay(asset, debt, currentRateMode, userAddress);
    await borrow(asset, debt, targetRateMode, userAddress);
    
    console.log('利率模式切換完成');
  }
};

第六章:閃電貸操作

Aave V3 支持閃電貸功能,可以在單筆交易中借款、操縱、還款,無需前期抵押。

// 閃電貸回調介面
const FLASH_LOAN_RECEIVER_ABI = [
  'function executeOperation(address[] calldata assets, uint256[] calldata amounts, uint256[] calldata premiums, address initiator, bytes calldata params) external returns (bool)',
];

// 閃電貸範例: arbitrage
const executeFlashLoanArbitrage = async (borrowAsset, borrowAmount, targetAsset) => {
  const { signer } = await connectWallet();
  const pool = getPoolContract(signer);
  
  // 部署閃電貸接收合約
  const flashLoanReceiver = await deployFlashLoanArbitrageContract(signer);
  
  const assets = [borrowAsset];
  const amounts = [borrowAmount];
  const modes = [0]; // 0 = 借完還款,不保留債務
  
  // 編碼操作參數
  const params = ethers.utils.defaultAbiCoder.encode(
    ['address', 'address'],
    [borrowAsset, targetAsset]
  );
  
  const tx = await pool.flashLoan(
    flashLoanReceiver.address,
    assets,
    amounts,
    modes,
    await signer.getAddress(),
    params,
    0 // referralCode
  );
  
  console.log('閃電貸交易已提交:', tx.hash);
  const receipt = await tx.wait();
  
  return {
    success: receipt.status === 1,
    transactionHash: receipt.hash,
  };
};

// 閃電貸接收合約(需部署)
const FLASH_LOAN_RECEIVER_SOURCE = `
pragma solidity ^0.8.28;

import {IPoolAddressesProvider, IPool, IERC20} from "@aave/v3-core/contracts/interfaces/";
import {FlashLoanSimpleReceiverBase} from "@aave/v3-core/contracts/flashloan/base/FlashLoanSimpleReceiverBase.sol";

contract FlashLoanArbitrageReceiver is FlashLoanSimpleReceiverBase {
    address public owner;
    
    constructor(IPoolAddressesProvider addressProvider) 
        FlashLoanSimpleReceiverBase(addressProvider)
    {
        owner = msg.sender;
    }
    
    function executeOperation(
        address[] calldata assets,
        uint256[] calldata amounts,
        uint256[] calldata premiums,
        address initiator,
        bytes calldata params
    ) external override returns (bool) {
        // 這裡實現套利邏輯
        
        // 1. 在交易所用借來的資產購買目標資產
        
        // 2. 在另一個交易所出售目標資產換回原資產
        
        // 3. 確保利潤足以支付費用
        uint256 amountToRepay = amounts[0] + premiums[0];
        uint256 profit = IERC20(assets[0]).balanceOf(address(this)) - amountToRepay;
        
        require(profit > 0, "No profit from arbitrage");
        
        // 4. 歸還閃電貸
        IERC20(assets[0]).approve(address(POOL), amountToRepay);
        
        // 5. 轉移利潤給調用者
        if (profit > 0) {
            IERC20(assets[0]).transfer(initiator, profit);
        }
        
        return true;
    }
}
`;

結論:最佳實踐與風險提示

核心要點總結

  1. 健康因子是生命線:始終將健康因子維持在安全範圍(建議 > 1.5)
  2. 了解清算機制:理解清算門檻和清算獎勵,避免被清算
  3. 選擇適當的利率模式:穩定利率適合長期借款,浮動利率可能更低
  4. 分散抵押品:不要將所有資產集中在一種抵押品
  5. 持續監控:市場波動會影響抵押品價值和健康因子

風險提示

建議讀者在實際操作前先在測試網(如 Sepolia)充分演練,並從小額開始逐步積累經驗。

重要參考資源

延伸閱讀與來源

這篇文章對您有幫助嗎?

評論

發表評論

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

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