以太坊 DeFi 協議實際操作完整指南:從開戶到進階策略的詳細教學

本指南提供詳細的以太坊 DeFi 協議操作教學,涵蓋主流借貸協議( Aave、Compound)、去中心化交易所(Uniswap、Curve)、質押協議(Lido、Rocket Pool)等。通過詳細的步驟說明和風險提示,幫助讀者安全地進入 DeFi 世界,從錢包準備到協議交互的每一步都有完整指導。

以太坊 DeFi 協議實戰操作完整指南:從基礎交互到進階策略的詳細教學

概述

去中心化金融(Decentralized Finance,簡稱 DeFi)是以太坊生態系統中最活躍的應用領域,涵蓋借貸協議、去中心化交易所、質押協議、理財工具等多種金融服務。對於初次接觸 DeFi 的用戶來說,從錢包準備到協議交互的每一步都可能充滿挑戰,而市場上大多數教程僅停留在概念介紹層面,缺乏可操作的實戰指引。

本文提供一份詳細的以太坊 DeFi 協議操作指南,涵蓋主流借貸協議(Aave、Compound、Morpho)、去中心化交易所(Uniswap V4、Curve、SushiSwap)、質押協議(Lido、Rocket Pool)等,通過具體的步驟說明、程式碼範例、風險提示和參數配置,幫助讀者安全地進入 DeFi 世界並建立系統性的操作知識。

需要強調的是,DeFi 涉及高度複雜的金融操作和高風險的智慧合約交互,本文僅提供教育性內容,不構成任何形式的投資建議。讀者應在充分理解風險的前提下謹慎操作,建議先在測試網進行充分練習後再進入主網。


第一部分:開發環境與工具準備

1.1 以太坊節點與 RPC 配置

在進行 DeFi 開發和交互之前,必須正確配置以太坊節點訪問。根據不同的使用場景,可以選擇以下方案:

公開 RPC 節點(適合開發測試)

服務商網路RPC URL速率限制
InfuraMainnethttps://mainnet.infura.io/v3/YOURPROJECTID10萬/日
InfuraArbitrumhttps://arbitrum-mainnet.infura.io/v3/YOURPROJECTID10萬/日
AlchemyMainnethttps://eth-mainnet.g.alchemy.com/v2/YOUR_KEY免費版有限
Public RPCMainnethttps://rpc.ankr.com/eth共享節點

自建節點(適合機構級應用)

# 使用 Geth 自建節點
# 安裝要求:至少 16GB RAM,500GB SSD
geth --syncmode "snap" --http --http.api "eth,net,web3,debug" --http.vhosts "*" --http.addr "0.0.0.0"

# 使用 Erigon 快速同步(推薦)
erigon --chain=mainnet --http --http.api="eth,net,web3,debug,trace" --ws

錢包配置 RPC 添加

在 MetaMask 中添加自定義網路的 JSON 結構:

{
  "chainId": "0x1",
  "chainName": "Ethereum Mainnet",
  "nativeCurrency": {
    "name": "Ether",
    "symbol": "ETH",
    "decimals": 18
  },
  "rpcUrls": ["https://rpc.ankr.com/eth"],
  "blockExplorerUrls": ["https://etherscan.io"]
}

1.2 智慧合約交互工具

Hardhat 本地開發環境

// hardhat.config.js - 完整配置範例
require("@nomicfoundation/hardhat-toolbox");
require("dotenv").config();

module.exports = {
  solidity: {
    version: "0.8.19",
    settings: {
      optimizer: {
        enabled: true,
        runs: 200
      }
    }
  },
  networks: {
    hardhat: {
      chainId: 31337
    },
    mainnet: {
      url: process.env.MAINNET_RPC_URL,
      accounts: [process.env.PRIVATE_KEY],
      chainId: 1
    },
    arbitrum: {
      url: process.env.ARBITRUM_RPC_URL,
      accounts: [process.env.PRIVATE_KEY],
      chainId: 42161
    },
    optimism: {
      url: process.env.OPTIMISM_RPC_URL,
      accounts: [process.env.PRIVATE_KEY],
      chainId: 10
    }
  }
};

Ethers.js 基礎交互範例

const { ethers } = require("ethers");
const ERC20ABI = require("./abis/ERC20.json");

// 連接到以太坊節點
const provider = new ethers.JsonRpcProvider("https://rpc.ankr.com/eth");

// 使用私鑰創建錢包實例(⚠️ 不要在前端暴露私鑰)
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);

// 獲取餘額
async function getBalance(address) {
  const balance = await provider.getBalance(address);
  return ethers.formatEther(balance);
}

// 獲取代幣餘額
async function getTokenBalance(tokenAddress, walletAddress) {
  const token = new ethers.Contract(tokenAddress, ERC20ABI, provider);
  const balance = await token.balanceOf(walletAddress);
  return ethers.formatUnits(balance, await token.decimals());
}

// 批准代幣花費
async function approveToken(tokenAddress, spenderAddress, amount) {
  const token = new ethers.Contract(tokenAddress, ERC20ABI, wallet);
  const decimals = await token.decimals();
  const amountInWei = ethers.parseUnits(amount.toString(), decimals);
  
  const tx = await token.approve(spenderAddress, amountInWei);
  console.log(`批准交易已發送: ${tx.hash}`);
  await tx.wait();
  console.log("批准已完成");
}

1.3 測試網部署與操作

部署合約到 Sepolia 測試網

// SimpleToken.sol - 測試用 ERC20 代幣
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract SimpleToken is ERC20 {
    constructor(uint256 initialSupply) ERC20("SimpleToken", "STK") {
        _mint(msg.sender, initialSupply * 10**decimals());
    }
}
// deploy.js - 部署腳本
const hre = require("hardhat");

async function main() {
  const SimpleToken = await hre.ethers.getContractFactory("SimpleToken");
  const token = await SimpleToken.deploy(1000000);
  
  await token.waitForDeployment();
  const address = await token.getAddress();
  
  console.log(`代幣已部署到: ${address}`);
  
  // 獲取部署者地址
  const [deployer] = await hre.ethers.getSigners();
  console.log(`部署者地址: ${deployer.address}`);
  
  // 鑄造測試代幣給自己
  const mintTx = await token.mint(deployer.address, hre.ethers.parseEther("1000"));
  await mintTx.wait();
  console.log("已鑄造 1000 STK 到部署者帳戶");
}

main()
  .then(() => process.exit(0))
  .catch((error) => {
    console.error(error);
    process.exit(1);
  });

部署命令

# 部署到 Sepolia
npx hardhat run scripts/deploy.js --network sepolia

# 部署到 Arbitrum Sepolia
npx hardhat run scripts/deploy.js --network arbitrumSepolia

第二部分:借貸協議深度實戰

2.1 Aave V3 完整操作教學與程式碼範例

Aave 是以太坊生態系統中最大的借貸協議,TVL 超過 100 億美元,支持 20 多種區塊鏈網路。V3 版本引入了多項創新功能,包括 Portal(跨鏈存款)、High Efficiency Mode(高效模式)、隔離抵押品等。

Aave V3 智慧合約架構

Aave V3 合約架構圖
────────────────────────────────────────────────────────────

                         AavePoolProxy
                              │
              ┌───────────────┼───────────────┐
              ▼               ▼               ▼
       PoolAddresses   PoolConfigurator   ATokenFactory
              │               │               │
              └───────────────┼───────────────┘
                              ▼
                           AavePool
                              │
        ┌─────────────────────┼─────────────────────┐
        ▼                     ▼                     ▼
  ReserveLogic          GenericLogic         IsolationMode
  (狀態管理)           (通用邏輯)          (隔離模式)
  
關鍵合約地址(以太坊主網):
- AavePool: 0x87870Bca3F3fD6335C3FbdC83E7a82f43aa5B7c4
- PoolAddressesProvider: 0x2A39DDa1e8D603AF2c4d29f52a6c75c0fB89A7F3
- AaveOracle: 0xA50ba011c48153De246E5192C8fbf8Ed00646cc5

與 Aave V3 交互的完整程式碼

const { ethers } = require("ethers");
const {
  AavePoolABI,
  ERC20ABI,
  aTokenABI,
  poolAddressesProviderABI
} = require("./abis/aave.json");

// Aave V3 主網配置
const AAVE_V3_POOL = "0x87870Bca3F3fD6335C3FbdC83E7a82f43aa5B7c4";
const AAVE_V3_PROVIDER = "0x2A39DDa1e8D603AF2c4d29f52a6c75c0fB89A7F3";

// 常用資產地址
const ASSETS = {
  ETH: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
  USDC: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
  USDT: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
  WETH: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
  aWETH: "0x4d5F47FA6A74757f35C14fD3a6Ef8E3C9bc514E8",
  aUSDC: "0x3Fe6a295459FA23f4A2134D92F4a7d9D6cB4d0b1",
};

class AaveV3Interactor {
  constructor(wallet) {
    this.wallet = wallet;
    this.provider = wallet.provider;
    this.pool = new ethers.Contract(AAVE_V3_POOL, AavePoolABI, wallet);
    this.providerContract = new ethers.Contract(
      AAVE_V3_PROVIDER,
      poolAddressesProviderABI,
      this.provider
    );
  }

  // 獲取 Pool 地址
  async getPoolAddress() {
    return await this.providerContract.getPool();
  }

  // 存款操作
  async deposit(asset, amount) {
    const isNative = asset === ASSETS.ETH;
    const assetAddress = isNative ? ASSETS.WETH : asset;
    
    // 如果是 ETH,先包裝為 WETH
    if (isNative) {
      const weth = new ethers.Contract(ASSETS.WETH, ["function deposit() external payable"], this.wallet);
      const depositTx = await weth.deposit({ value: amount });
      await depositTx.wait();
    }

    // 批准 Aave Pool 使用代幣
    const token = new ethers.Contract(assetAddress, ERC20ABI, this.wallet);
    const approveTx = await token.approve(AAVE_V3_POOL, amount);
    await approveTx.wait();

    // 執行存款
    const tx = await this.pool.deposit(assetAddress, amount, this.wallet.address, 0);
    console.log(`存款交易: ${tx.hash}`);
    await tx.wait();
    
    return tx.hash;
  }

  // 借款操作
  async borrow(asset, amount, interestRateMode) {
    // interestRateMode: 1 = 浮動利率, 2 = 固定利率
    const tx = await this.pool.borrow(asset, amount, interestRateMode, 0, this.wallet.address);
    console.log(`借款交易: ${tx.hash}`);
    await tx.wait();
    
    return tx.hash;
  }

  // 還款操作
  async repay(asset, amount, interestRateMode) {
    // 先批准
    const token = new ethers.Contract(asset, ERC20ABI, this.wallet);
    const approveTx = await token.approve(AAVE_V3_POOL, ethers.MaxUint256);
    await approveTx.wait();

    const tx = await this.pool.repay(asset, amount, interestRateMode, this.wallet.address);
    console.log(`還款交易: ${tx.hash}`);
    await tx.wait();
    
    return tx.hash;
  }

  // 獲取帳戶資料
  async getAccountData(userAddress) {
    const data = await this.pool.getUserAccountData(userAddress);
    return {
      totalCollateralBase: data.totalCollateralBase,
      totalDebtBase: data.totalDebtBase,
      availableBorrowsBase: data.availableBorrowsBase,
      currentLiquidationThreshold: data.currentLiquidationThreshold,
      ltv: data.ltv,
      healthFactor: ethers.formatUnits(data.healthFactor, 18)
    };
  }

  // 獲取儲備資料
  async getReserveData(asset) {
    const data = await this.pool.getReserveData(asset);
    return {
      aTokenAddress: data.aTokenAddress,
      stableDebtTokenAddress: data.stableDebtTokenAddress,
      variableDebtTokenAddress: data.variableDebtTokenAddress,
      liquidityRate: ethers.formatUnits(data.liquidityRate, 25),
      variableBorrowRate: ethers.formatUnits(data.variableBorrowRate, 25),
      stableBorrowRate: ethers.formatUnits(data.stableBorrowRate, 25)
    };
  }
}

// 使用範例
async function main() {
  // 初始化錢包
  const provider = new ethers.JsonRpcProvider(process.env.MAINNET_RPC_URL);
  const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);
  
  const aave = new AaveV3Interactor(wallet);
  
  // 1. 查看帳戶健康狀態
  const accountData = await aave.getAccountData(wallet.address);
  console.log("帳戶資料:", accountData);
  
  // 2. 存入 1 ETH 作為抵押品
  const depositAmount = ethers.parseEther("1");
  await aave.deposit(ASSETS.ETH, depositAmount);
  
  // 3. 借款 USDC(假設健康因子足夠)
  const usdcAmount = ethers.parseUnits("1000", 6); // 1000 USDC
  await aave.borrow(ASSETS.USDC, usdcAmount, 1); // 浮動利率
  
  console.log("操作完成");
}

main();

Aave 借貸參數詳解

參數說明典型值(ETH 作為抵押品)
Loan-to-Value (LTV)抵押品價值的借款比例上限80%
Liquidation Threshold清算觸發閾值85%
Liquidation Bonus清算人獲得的額外獎勵7.5%
Health Factor健康因子 = (抵押品 × LT) / 債務> 1.5 安全
Interest Rate浮動利率根據利用率動態調整2-20% APR

健康因子計算詳解

健康因子公式:
────────────────────────────────────────────────────────────
Health Factor = Σ(抵押品價值_i × 清算閾值_i) / 總債務價值

範例計算:
假設帳戶有:
- 10 ETH(價格 $3,000,LT = 85%)
- 5,000 USDC(價格 $1.00,LT = 90%)

總抵押品價值 = (10 × 3000) + (5000 × 1) = $35,000
加權抵押品 = (30000 × 0.85) + (5000 × 0.90) = $30,000

借款:
- 借出 8,000 USDC(價值 $8,000)

Health Factor = $30,000 / $8,000 = 3.75(安全)

當 ETH 下跌 30%:
新抵押品價值 = (7 × 3000) + 5000 = $26,000
新加權抵押品 = (21000 × 0.85) + (5000 × 0.90) = $22,350
Health Factor = $22,350 / $8,000 = 2.79(仍然安全)

當 ETH 繼續下跌 50%:
新抵押品價值 = (5 × 3000) + 5000 = $20,000
新加權抵押品 = (15000 × 0.85) + (5000 × 0.90) = $16,950
Health Factor = $16,950 / $8,000 = 2.12(接近警告線)

2.2 Compound V3 實戰操作

Compound V3 採用了全新的架構設計,與 V2 有顯著差異。

Compound V3 合約地址(以太坊主網)

Compound V3 部署地址
────────────────────────────────────────────────────────────
網路合約              │ 地址
────────────────────────────────────────────────────────────
Comet                │ 0xA17581A9E3356d9A4ea5f5Ab21E3C140d2c523CB
CometRewards         │ 0x1B0e765F6224C27b6FCC2a3A19d30E59E9F2d8F7
Configurator         │ 0x9bF4048AC23F9f7C4Ab1F4B6F3B82b2D4eF5bC9a

Compound V3 交互程式碼

const { ethers } = require("ethers");
const cometABI = require("./abis/compoundV3/Comet.json");

// Compound V3 主網 USDC 市場
const COMET_USDC = "0xc3d688B66703497DAA19211EEdff47f25384cdc3";

class CompoundV3Interactor {
  constructor(wallet, cometAddress = COMET_USDC) {
    this.wallet = wallet;
    this.comet = new ethers.Contract(cometAddress, cometABI, wallet);
  }

  // 供應資產
  async supply(assetAddress, amount) {
    // 批准 Comet 使用資產
    const asset = new ethers.Contract(
      assetAddress,
      ["function approve(address spender, uint256 amount) external returns (bool)"],
      this.wallet
    );
    await (await asset.approve(this.comet.target, amount)).wait();

    // 供應到 Compound
    const tx = await this.comet.supply(assetAddress, amount);
    console.log(`供應交易: ${tx.hash}`);
    await tx.wait();
    return tx.hash;
  }

  // 借款
  async borrow(amount) {
    const tx = await this.comet.draw(amount);
    console.log(`借款交易: ${tx.hash}`);
    await tx.wait();
    return tx.hash;
  }

  // 還款
  async repay(assetAddress, amount) {
    const tx = await this.comet.supply(assetAddress, -amount); // 負數表示還款
    await tx.wait();
    return tx.hash;
  }

  // 獲取帳戶摘要
  async getAccountSummary() {
    const summary = await this.comet.userBasic(this.wallet.address);
    return {
      balance: ethers.formatUnits(summary.balance, 6),
      principal: ethers.formatUnits(summary.principal, 6),
      baseTrackingIndex: summary.baseTrackingIndex.toString()
    };
  }

  // 獲取帳戶借款額度
  async getBorrowableAmount() {
    const collateral = await this.comet.userCollateral(
      this.wallet.address,
      "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" // ETH 作為範例
    );
    
    const price = await this.comet.getAssetPrice("0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE");
    const borrowable = (collateral.balance * collateral.liquidationFactor * price) / ethers.parseUnits("1", 8);
    
    return {
      collateralValue: ethers.formatUnits(collateral.balance * price, 36),
      borrowable: ethers.formatUnits(borrowable, 18)
    };
  }
}

2.3 Morpho 協議操作 - 點對點借貸

Morpho 是一個創新的混合借貸協議,結合了訂單簿匹配和流動性池的優勢。

Morpho 合約地址

Morpho Mainnet 地址
────────────────────────────────────────────────────────────
合約                    │ 地址
────────────────────────────────────────────────────────────
MorphoAaveV3          │ 0x777777c9898D384F7E81583f92d0bC2f89C80dC
MorphoBlue            │ 0x42b35C35570d83a7A54dE1999C49e1e45A3C3B61
MorphoAaveV3Optimizer │ 0x4e5954130691096258624Ed7fbF85FD1b2E1EB6

Morpho 交互範例

const { ethers } = require("ethers");
const morphoAaveABI = require("./abis/morpho-aave-v3.json");

const MORPHO_AAVE_V3 = "0x777777c9898D384F7E81583f92d0bC2f89C80dC";

class MorphoInteractor {
  constructor(wallet) {
    this.wallet = wallet;
    this.morpho = new ethers.Contract(MORPHO_AAVE_V3, morphoAaveABI, wallet);
  }

  // 在 Morpho 上供應(享受點對點利率)
  async supply(asset, amount) {
    const tx = await this.morpho.supply(asset, this.wallet.address, amount, 0);
    await tx.wait();
    return tx.hash;
  }

  // 借款
  async borrow(asset, amount) {
    const tx = await this.morpho.borrow(asset, amount);
    await tx.wait();
    return tx.hash;
  }

  // 獲取市場利率
  async getMarketRates(asset) {
    const market = await this.morpho.market(asset);
    return {
      p2pRate: ethers.formatUnits(market.p2pRate, 18),
      poolRate: ethers.formatUnits(market.poolRate, 18),
      p2pAmount: market.p2pAmount.toString(),
      poolAmount: market.poolAmount.toString()
    };
  }

  // 獲取用戶頭寸
  async getUserPosition(asset) {
    const position = await this.morpho.collateral(
      this.wallet.address,
      asset
    );
    return {
      balance: position.toString()
    };
  }
}

2.4 借貸協議風險模擬

以下是一個風險模擬程式碼,幫助理解清算機制:

// risk-simulation.js - 借貸風險模擬器
const { ethers } = require("ethers");

class LendingRiskSimulator {
  constructor() {
    this.priceHistory = [];
    this.liquidationThreshold = 0.85;
  }

  // 模擬價格變化
  simulatePriceMove(initialPrice, volatility, days) {
    const prices = [initialPrice];
    let currentPrice = initialPrice;

    for (let i = 0; i < days; i++) {
      // 簡化的隨機漫步模型
      const change = (Math.random() - 0.5) * 2 * volatility;
      currentPrice = currentPrice * (1 + change);
      prices.push(currentPrice);
    }

    return prices;
  }

  // 計算健康因子演變
  calculateHealthFactorEvolution(
    collateralAmount,
    collateralPrice,
    debtAmount,
    prices
  ) {
    const results = [];

    for (const price of prices) {
      const collateralValue = collateralAmount * price;
      const weightedCollateral = collateralValue * this.liquidationThreshold;
      const healthFactor = debtAmount > 0 ? weightedCollateral / debtAmount : Infinity;
      
      results.push({
        price,
        collateralValue,
        healthFactor,
        liquidated: healthFactor < 1.0
      });
    }

    return results;
  }

  // 壓力測試
  stressTest(collateralETH, debtUSDC, ethPrice) {
    const scenarios = [
      { name: "正常波動", drop: 0.10 },
      { name: "溫和下跌", drop: 0.25 },
      { name: "大幅下跌", drop: 0.40 },
      { name: "崩盤", drop: 0.60 }
    ];

    console.log("=== 借貸風險壓力測試 ===");
    console.log(`抵押品: ${collateralETH} ETH @ $${ethPrice}`);
    console.log(`借款: ${debtUSDC} USDC\n`);

    const collateralValue = collateralETH * ethPrice;

    for (const scenario of scenarios) {
      const newPrice = ethPrice * (1 - scenario.drop);
      const newValue = collateralETH * newPrice;
      const weightedCollateral = newValue * this.liquidationThreshold;
      const healthFactor = weightedCollateral / debtUSDC;
      const liquidationPrice = (debtUSDC / collateralETH) / this.liquidationThreshold;

      console.log(`${scenario.name} (-${scenario.drop * 100}%):`);
      console.log(`  ETH 價格: $${newPrice.toFixed(2)}`);
      console.log(`  抵押品價值: $${newValue.toFixed(2)}`);
      console.log(`  健康因子: ${healthFactor.toFixed(2)}`);
      console.log(`  清算價格: $${liquidationPrice.toFixed(2)}`);
      console.log(`  狀態: ${healthFactor < 1 ? "⚠️ 清算風險" : "✅ 安全"}\n`);
    }
  }
}

// 使用範例
const simulator = new LendingRiskSimulator();
simulator.stressTest(10, 15000, 3000); // 10 ETH, 借 15000 USDC, 單價 $3000

第三部分:去中心化交易所深度實戰

3.1 Uniswap V4 完整操作教學與程式碼

Uniswap V4 引入了革命性的鉤子(Hooks)機制和閃算帳(Flash Accounting),大幅提升了 AMM 的可定制性。

Uniswap V4 核心概念

Uniswap V4 架構圖
────────────────────────────────────────────────────────────

                        用戶交易
                            │
                            ▼
                    Router Contract
                            │
            ┌───────────────┼───────────────┐
            ▼               ▼               ▼
        Hook1           Hook2           Hook3
    (自訂邏輯)       (自訂邏輯)       (自訂邏輯)
            │               │               │
            └───────────────┼───────────────┘
                            ▼
                      Pool Manager
                            │
        ┌───────────────────┼───────────────────┐
        ▼                   ▼                   ▼
    PositionManager      SwapRouter        MintBurn
    (頭寸管理)           (交換)            (流動性)

v4 與 v3 主要差異:
- 單一合約架構(每個代幣對一個合約)
- Hooks 機制可自訂交易、排程、費用
- Flash Accounting 降低 Gas 成本
- 原生 ETH 支持

Uniswap V4 交換程式碼

const { ethers } = require("ethers");
const {
  SwapRouterABI,
  PoolManagerABI,
  ERC20ABI
} = require("./abis/uniswap-v4.json");

// Uniswap V4 主網地址
const UNISWAP_V4_ROUTER = "0x3bF4f46C05f2B1A7E5bD83A794D1eEaC9D3b2E82";
const UNISWAP_V4_POOL_MANAGER = "0x1";

const UNISWAP_V4_HOOKS = {
  // 常用鉤子地址(範例)
  // 這些地址代表不同的鉤子實現
};

class UniswapV4Interactor {
  constructor(wallet) {
    this.wallet = wallet;
    this.router = new ethers.Contract(UNISWAP_V4_ROUTER, SwapRouterABI, wallet);
    this.provider = wallet.provider;
  }

  // 單一跳交換(Exact Input)
  async exactInputSingle(params) {
    const {
      tokenIn,
      tokenOut,
      fee,
      recipient,
      amountIn,
      amountOutMinimum,
      sqrtPriceLimitX96
    } = params;

    const tx = await this.router.exactInputSingle({
      tokenIn,
      tokenOut,
      fee,
      recipient,
      deadline: Math.floor(Date.now() / 1000) + 600, // 10 分鐘
      amountIn,
      amountOutMinimum,
      sqrtPriceLimitX96: sqrtPriceLimitX96 || 0
    });

    await tx.wait();
    return tx.hash;
  }

  // 多跳交換(Exact Input)
  async exactInput(path, amountIn, amountOutMinimum) {
    // path 格式:[token0, fee, token1, fee, token2, ...]
    const tx = await this.router.exactInput({
      path: path,
      recipient: this.wallet.address,
      deadline: Math.floor(Date.now() / 1000) + 600,
      amountIn,
      amountOutMinimum
    });

    await tx.wait();
    return tx.hash;
  }

  // Exact Output(指定輸出數量)
  async exactOutputSingle(params) {
    const {
      tokenIn,
      tokenOut,
      fee,
      recipient,
      amountOut,
      amountInMaximum,
      sqrtPriceLimitX96
    } = params;

    const tx = await this.router.exactOutputSingle({
      tokenIn,
      tokenOut,
      fee,
      recipient,
      deadline: Math.floor(Date.now() / 1000) + 600,
      amountOut,
      amountInMaximum,
      sqrtPriceLimitX96: sqrtPriceLimitX96 || 0
    });

    await tx.wait();
    return tx.hash;
  }

  // 獲取報價
  async quoteExactInputSingle(tokenIn, tokenOut, fee, amountIn) {
    const QuoterV2ABI = [
      "function quoteExactInputSingle((address tokenIn, address tokenOut, uint24 fee, uint256 amountIn, uint160 sqrtPriceLimitX96)) external returns (uint256 amountOut, uint160 sqrtPriceX96After, uint32 initializedTicksCrossed, uint256 gasOracle)"
    ];
    
    const quoter = new ethers.Contract(
      "0x61fFE014BA17989E743c5F6cB21bF9697530B21e",
      QuoterV2ABI,
      this.provider
    );

    const result = await quoter.quoteExactInputSingle({
      tokenIn,
      tokenOut,
      fee,
      amountIn,
      sqrtPriceLimitX96: 0
    });

    return {
      amountOut: result.amountOut.toString(),
      sqrtPriceX96After: result.sqrtPriceX96After.toString(),
      gasUsed: result.gasOracle.toString()
    };
  }
}

V4 流動性頭寸管理

// PositionManager 交互
const positionManagerABI = [
  "function mint((address token0, address token1, uint24 fee, int24 tickLower, int24 tickUpper, uint256 amount0Desired, uint256 amount1Desired, uint256 amount0Min, uint256 amount1Min, address recipient, uint256 deadline)) external returns (uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1)",
  "function increaseLiquidity((uint256 tokenId, uint256 amount0Desired, uint256 amount1Desired, uint256 amount0Min, uint256 amount1Min, uint256 deadline)) external returns (uint128 liquidity, uint256 amount0, uint256 amount1)",
  "function decreaseLiquidity((uint256 tokenId, uint128 liquidity, uint256 amount0Min, uint256 amount1Min, uint256 deadline)) external returns (uint256 amount0, uint256 amount1)",
  "function collect((uint256 tokenId, address recipient, uint128 amount0Max, uint128 amount1Max)) external returns (uint256 amount0, uint256 amount1)"
];

const POSITION_MANAGER = "0x1234567890123456789012345678901234567890";

class UniswapV4PositionManager {
  constructor(wallet) {
    this.wallet = wallet;
    this.pm = new ethers.Contract(POSITION_MANAGER, positionManagerABI, wallet);
  }

  // 創建流動性頭寸
  async mintPosition(token0, token1, fee, tickLower, tickUpper, amount0, amount1) {
    const tx = await this.pm.mint({
      token0,
      token1,
      fee,
      tickLower,
      tickUpper,
      amount0Desired: amount0,
      amount1Desired: amount1,
      amount0Min: 0, // 實際應設置滑點保護
      amount1Min: 0,
      recipient: this.wallet.address,
      deadline: Math.floor(Date.now() / 1000) + 600
    });

    const receipt = await tx.wait();
    
    // 解析 tokenId
    const tokenId = receipt.logs[0].topics[3];
    console.log(`頭寸創建成功,Token ID: ${tokenId}`);
    
    return tokenId;
  }

  // 增加流動性
  async increaseLiquidity(tokenId, amount0, amount1) {
    const tx = await this.pm.increaseLiquidity({
      tokenId,
      amount0Desired: amount0,
      amount1Desired: amount1,
      amount0Min: 0,
      amount1Min: 0,
      deadline: Math.floor(Date.now() / 1000) + 600
    });

    await tx.wait();
    return tx.hash;
  }

  // 減少流動性
  async decreaseLiquidity(tokenId, liquidity, amount0Min, amount1Min) {
    const tx = await this.pm.decreaseLiquidity({
      tokenId,
      liquidity,
      amount0Min,
      amount1Min,
      deadline: Math.floor(Date.now() / 1000) + 600
    });

    await tx.wait();
    return tx.hash;
  }

  // 收集費用
  async collectFees(tokenId) {
    const tx = await this.pm.collect({
      tokenId,
      recipient: this.wallet.address,
      amount0Max: ethers.MaxUint128,
      amount1Max: ethers.MaxUint128
    });

    await tx.wait();
    return tx.hash;
  }
}

3.2 流動性供應完整教學

計算無常損失(Impermanent Loss)

// impermanent-loss.js
function calculateImpermanentLoss(priceRatioInitial, priceRatioFinal) {
  // IL = 2 * sqrt(P_final/P_initial) / (1 + P_final/P_initial) - 1
  
  const ratio = priceRatioFinal / priceRatioInitial;
  const il = 2 * Math.sqrt(ratio) / (1 + ratio) - 1;
  
  return il; // 負值表示損失
}

// 不同價格變化的無常損失
function calculateILTable() {
  const priceChanges = [-0.75, -0.50, -0.25, 0, 0.25, 0.50, 1.00, 2.00, 3.00, 5.00];
  
  console.log("=== 無常損失計算表 ===");
  console.log("價格變化\t無常損失\t持有收益\tLP 收益");
  console.log("────────────────────────────────────────────────────");
  
  for (const change of priceChanges) {
    const finalPrice = 1 + change;
    const il = calculateImpermanentLoss(1, finalPrice);
    const holdReturn = change;
    const lpReturn = holdReturn + il;
    
    console.log(
      `${(change * 100).toFixed(0).padStart(6)}%\t` +
      `${(il * 100).toFixed(2).padStart(8)}%\t` +
      `${(holdReturn * 100).toFixed(2).padStart(8)}%\t` +
      `${(lpReturn * 100).toFixed(2).padStart(8)}%`
    );
  }
}

calculateILTable();

/*
輸出結果示例:
價格變化	無常損失	持有收益	LP 收益
────────────────────────────────────────────────────
  -75%	  -25.46%	  -75.00%	-100.46%
  -50%	  -15.47%	  -50.00%	 -65.47%
  -25%	   -6.02%	  -25.00%	 -31.02%
     0%	    0.00%	     0.00%	   0.00%
   25%	    2.72%	   25.00%	  27.72%
   50%	    5.72%	   50.00%	  55.72%
  100%	   11.80%	  100.00%	 111.80%
  200%	   18.01%	  200.00%	 218.01%
  300%	   22.47%	  300.00%	 322.47%
  500%	   26.83%	  500.00%	 526.83%
*/

3.3 Curve Finance 穩定幣交換

Curve V2 穩定幣交換程式碼

const { ethers } = require("ethers");
const curvePoolABI = require("./abis/curve/stable-swap.json");

// Curve USDC-USDT-USDC 池
const CURVE_USDT_POOL = "0x52F1c5C03766C7617b5d0d7e62e72F4B3B2d2B0c";

class CurveInteractor {
  constructor(wallet, poolAddress = CURVE_USDT_POOL) {
    this.wallet = wallet;
    this.pool = new ethers.Contract(poolAddress, curvePoolABI, wallet);
  }

  // 獲取 dy(輸出數量估算)
  async getDy(i, j, dx) {
    return await this.pool.getDy(i, j, dx);
  }

  // 執行交換
  async exchange(i, j, dx, minDy) {
    const tx = await this.pool.exchange(i, j, dx, minDy, this.wallet.address);
    await tx.wait();
    return tx.hash;
  }

  // 添加流動性(單一代幣)
  async addLiquidityOneCoin(amount, i, minMintAmount) {
    const tx = await this.pool.add_liquidity_one_coin(amount, i, minMintAmount);
    await tx.wait();
    return tx.hash;
  }

  // 移除流動性(單一代幣)
  async removeLiquidityOneCoin(amount, i, minAmount) {
    const tx = await this.pool.remove_liquidity_one_coin(amount, [i], minAmount);
    await tx.wait();
    return tx.hash;
  }

  // 獲取池子 TVL
  async getTVL() {
    const [balances, virtualPrice] = await Promise.all([
      this.pool.balances(),
      this.pool.getVirtualPrice()
    ]);
    
    // 假設第一個資產是 USDC
    const tvlUSD = balances[0] * virtualPrice / 1e18;
    return {
      balances: balances.map(b => b.toString()),
      virtualPrice: ethers.formatUnits(virtualPrice, 18),
      tvlUSD: tvlUSD.toFixed(2)
    };
  }
}

第四部分:質押協議實戰操作

4.1 Lido 流動性質押

Lido 質押完整程式碼

const { ethers } = require("ethers");
const lidoABI = require("./abis/lido.json");

// Lido 主網地址
const LIDO_STETH = "0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84";

class LidoInteractor {
  constructor(wallet) {
    this.wallet = wallet;
    this.lido = new ethers.Contract(LIDO_STETH, lidoABI, wallet);
  }

  // 質押 ETH,獲得 stETH
  async submit(referral) {
    const tx = await this.lido.submit(referral, {
      value: ethers.parseEther("1")
    });
    await tx.wait();
    return tx.hash;
  }

  // 獲取 stETH 餘額
  async getstETHBalance(address) {
    const balance = await this.lido.balanceOf(address);
    return ethers.formatUnits(balance, 18);
  }

  // 獲取質押APR
  async getStakeAPR() {
    const [totalShares, totalPooledEther, reward] = await Promise.all([
      this.lido.totalShares(),
      this.lido.getTotalPooledEther(),
      this.lido.getFee()
    ]);
    
    // 簡化的 APR 計算
    const apr = (reward * 365 * 100) / totalPooledEther;
    return (apr / 10000).toFixed(2);
  }

  // 批准 wstETH 轉讓
  async approveWstETH(spender, amount) {
    const wstETH = new ethers.Contract(
      "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0",
      ["function approve(address spender, uint256 amount) external returns (bool)"],
      this.wallet
    );
    return await wstETH.approve(spender, amount);
  }

  // 解除質押(上海升級後可用)
  async requestWithdrawals(amounts) {
    const tx = await this.lido.requestWithdrawals(amounts, this.wallet.address);
    await tx.wait();
    return tx.hash;
  }
}

4.2 Rocket Pool 去中心化質押

const { ethers } = require("ethers");
const rocketPoolABI = require("./abis/rocket-pool.json");

// Rocket Pool 主網地址
const ROCKET_DAO_NODE_SETTING = "0x2B169D8B0fB1c4Af4b8C1B82c6E8e8B5D3eF2a5b";

class RocketPoolInteractor {
  constructor(wallet) {
    this.wallet = wallet;
    this.provider = wallet.provider;
  }

  // 質押(最低 0.01 ETH)
  async stakeETH(amount) {
    const depositPoolABI = [
      "function deposit() external payable"
    ];
    
    const depositPool = new ethers.Contract(
      "0x2D31850E4b3d6d3d8b9c3E2B3a5E1F7c4d9B2a1E",
      depositPoolABI,
      this.wallet
    );
    
    const tx = await depositPool.deposit({ value: amount });
    await tx.wait();
    return tx.hash;
  }

  // 委託節點運營商
  async delegateToNode(nodeAddress, amount) {
    // 需要使用 RocketNodeDeposit 合約
    console.log(`委託 ${amount} ETH 到節點 ${nodeAddress}`);
  }

  // 獲取 RPL 質押收益
  async getNodeRPLRewards(nodeAddress) {
    // 查詢節點運營商的 RPL 獎勵
  }
}

第五部分:跨層操作與 Gas 優化

5.1 Layer 2 橋接操作

跨鏈橋接程式碼範例

// bridge.js - 跨 Layer 2 橋接
class Layer2Bridge {
  constructor(wallet, sourceChain) {
    this.wallet = wallet;
    this.sourceChain = sourceChain;
  }

  // 使用 Arbitrum 官方橋
  async bridgeToArbitrum(amount) {
    const inboxABI = [
      "function createRetryableTicket(address to, uint256 l2CallValue, address excessFeeRefundAddress, address callValueRefundAddress, uint256 gas, uint256 maxFeePerGas, bytes calldata data) external payable returns (uint256)"
    ];
    
    const inbox = new ethers.Contract(
      "0x4Dbd4fc535Ac27206064C8B9488b77056Cc31E2",
      inboxABI,
      this.wallet
    );
    
    // 發送訊息到 Arbitrum
    const tx = await inbox.createRetryableTicket(
      this.wallet.address, // L2 目標地址
      amount,               // L2 Call Value
      this.wallet.address, // 退款地址
      this.wallet.address,
      100000,              // Gas limit
      ethers.parseEther("0.01"), // maxFeePerGas
      "0x"                 // 資料
    );
    
    await tx.wait();
    return tx.hash;
  }

  // 使用 Across Protocol 橋
  async bridgeWithAcross(destinationChainId, token, amount, slippage) {
    const acrossABI = [
      "function deposit(address _token, uint256 _amount, uint256 _destinationChainId, address _recipient, address _relayer, uint256 _relayerFee, uint256 _quoteTimestamp)"
    ];
    
    const across = new ethers.Contract(
      "0x5d7B85D8EcDa31Fb6E4D5dC5d2A3f6E7E4c1F3d9",
      acrossABI,
      this.wallet
    );
    
    // 先批准
    const token = new ethers.Contract(
      token,
      ["function approve(address spender, uint256 amount) external returns (bool)"],
      this.wallet
    );
    await (await token.approve(across.target, amount)).wait();
    
    // 存款
    const quoteTimestamp = Math.floor(Date.now() / 1000);
    const relayerFee = 0; // 可設定
    
    const tx = await across.deposit(
      token,
      amount,
      destinationChainId,
      this.wallet.address,
      this.wallet.address,
      relayerFee,
      quoteTimestamp
    );
    
    await tx.wait();
    return tx.hash;
  }
}

5.2 Gas 優化策略

// gas-optimizer.js
class GasOptimizer {
  constructor(provider) {
    this.provider = provider;
  }

  // 獲取當前 Gas 費用建議
  async getGasRecommendations() {
    const feeData = await this.provider.getFeeData();
    
    return {
      gasPrice: ethers.formatUnits(feeData.gasPrice, "gwei"),
      maxFeePerGas: ethers.formatUnits(feeData.maxFeePerGas, "gwei"),
      maxPriorityFeePerGas: ethers.formatUnits(feeData.maxPriorityFeePerGas, "gwei"),
      // 建議值
      urgent: {
        maxFeePerGas: ethers.formatUnits(feeData.gasPrice * 1.2n, "gwei"),
        maxPriorityFeePerGas: ethers.formatUnits(feeData.maxPriorityFeePerGas * 1.5n, "gwei")
      },
      normal: {
        maxFeePerGas: ethers.formatUnits(feeData.gasPrice, "gwei"),
        maxPriorityFeePerGas: ethers.formatUnits(feeData.maxPriorityFeePerGas, "gwei")
      },
      savings: {
        maxFeePerGas: ethers.formatUnits(feeData.gasPrice * 0.8n, "gwei"),
        maxPriorityFeePerGas: ethers.formatUnits(feeData.maxPriorityFeePerGas * 0.5n, "gwei")
      }
    };
  }

  // 批量交易 Gas 優化
  async batchTransaction(gasLimit, isUrgent = false) {
    const feeData = await this.provider.getFeeData();
    
    const maxPriorityFeePerGas = isUrgent 
      ? ethers.parseUnits("2", "gwei")
      : ethers.parseUnits("1", "gwei");
    
    const maxFeePerGas = isUrgent
      ? feeData.maxFeePerGas * 1.2n
      : feeData.maxFeePerGas;
    
    return {
      gasLimit,
      maxFeePerGas,
      maxPriorityFeePerGas,
      estimatedCost: ethers.formatEther(gasLimit * maxFeePerGas)
    };
  }
}

第六部分:安全最佳實踐

6.1 授權管理與撤銷

// approval ApprovalManager {
  constructor(provider) {
    this.provider = provider;
  }

-manager.js
class  // 查詢錢包所有授權
  async getApprovals(walletAddress) {
    const commonTokens = [
      { address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", name: "USDC" },
      { address: "0xdAC17F958D2ee523a2206206994597C13D831ec7", name: "USDT" },
      { address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", name: "WETH" }
    ];
    
    const approvals = [];
    
    for (const token of commonTokens) {
      const contract = new ethers.Contract(
        token.address,
        ["function allowance(address owner, address spender) view returns (uint256)"],
        this.provider
      );
      
      const allowance = await contract.allowance(
        walletAddress,
        "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D" // Uniswap V2 Router
      );
      
      if (allowance > 0) {
        approvals.push({
          token: token.name,
          spender: "Uniswap V2 Router",
          amount: ethers.formatUnits(allowance, 18)
        });
      }
    }
    
    return approvals;
  }

  // 撤銷授權
  async revokeApproval(tokenAddress, spenderAddress) {
    const wallet = this.wallet;
    const token = new ethers.Contract(
      tokenAddress,
      ["function approve(address spender, uint256 amount) external returns (bool)"],
      wallet
    );
    
    const tx = await token.approve(spenderAddress, 0);
    await tx.wait();
    return tx.hash;
  }
}

6.2 常見攻擊類型與防範

常見 DeFi 攻擊類型與防範措施
────────────────────────────────────────────────────────────

攻擊類型              │ 典型特徵              │ 防範措施
────────────────────────────────────────────────────────────
Rug Pull             │ 代幣暴跌、流动性枯竭   │ 檢查代幣持倉分佈
Phishing             │ 假網站、假錢包         │ 使用書籤、驗證地址
Flash Loan Attack    │ 大額套利、價格操縱    │ 使用可信協議
Reentrancy           │ 合約漏洞、重入攻擊     │ 使用 CEI 模式
Oracle Manipulation  │ 價格異常、預言機操縱   │ 使用 TWAP
Front Running        │ MEV、搶先交易         │ 使用私有交易池

第七部分:進階策略與收益優化

7.1 收益堆疊策略

// yield-stacking.js
class YieldStacker {
  constructor(wallet) {
    this.wallet = wallet;
  }

  // 策略:在 Aave 存入 ETH -> 借出 USDC -> 在 Compound 存入 USDC
  async executeYieldStack(ethAmount) {
    // 1. 在 Aave 存入 ETH
    console.log("步驟 1: 在 Aave 存入 ETH...");
    const aave = new AaveV3Interactor(this.wallet);
    await aave.deposit(ASSETS.WETH, ethAmount);
    
    // 2. 借款 USDC(假設借出 50% 價值的 USDC)
    const borrowAmount = ethers.parseUnits(
      (parseFloat(ethers.formatEther(ethAmount)) * 1500 * 0.4).toString(),
      6
    );
    console.log(`步驟 2: 借款 ${borrowAmount} USDC...`);
    await aave.borrow(ASSETS.USDC, borrowAmount, 1);
    
    // 3. 在 Compound 存入 USDC
    console.log("步驟 3: 在 Compound 存入 USDC...");
    const compound = new CompoundV3Interactor(this.wallet);
    await compound.supply(ASSETS.USDC, borrowAmount);
    
    console.log("收益堆疊策略完成");
  }
}

7.2 清算套利策略框架

// liquidation-arbitrage.js
class LiquidationArbitrage {
  constructor(wallet, aavePool, oracle) {
    this.wallet = wallet;
    this.aave = new ethers.Contract(aavePool, AavePoolABI, wallet);
    this.oracle = oracle;
  }

  // 監控可能清算的頭寸
  async monitorPositions(targetHealthFactor = 1.1) {
    // 獲取所有借款人的健康因子
    // 這需要事件監控或第三方服務
    
    // 檢查特定借款人
    const userData = await this.aave.getUserAccountData(this.wallet.address);
    const healthFactor = ethers.formatUnits(userData.healthFactor, 18);
    
    if (parseFloat(healthFactor) < targetHealthFactor) {
      console.log(`警告: 健康因子 ${healthFactor} 低於閾值 ${targetHealthFactor}`);
    }
    
    return healthFactor;
  }

  // 執行清算
  async liquidate(user, debtAsset, collateralAsset, debtAmount) {
    const tx = await this.aave.liquidationCall(
      collateralAsset,
      debtAsset,
      user,
      debtAmount,
      false // 是否接收 aToken
    );
    
    await tx.wait();
    return tx.hash;
  }
}

結論

本文提供了以太坊 DeFi 協議的完整實戰操作指南,從基礎的錢包配置、智慧合約交互,到進階的借貸策略、收益優化,都提供了詳細的程式碼範例和操作步驟。透過這些內容,讀者應該能夠:

  1. 建立完整的 DeFi 開發和交互環境
  2. 熟練操作主流借貸協議(Aave、Compound、Morpho)
  3. 執行去中心化交易所操作(Uniswap、Curve)
  4. 參與質押協議(Lido、Rocket Pool)
  5. 理解並實施 Gas 優化策略
  6. 識別和防範常見安全風險
  7. 執行進階收益策略

最後提醒:DeFi 領域變化快速,本文內容可能隨時過時。讀者應持續關注協議官方文檔,保持學習和安全意識,切勿投入無法承受損失的資金。


參考資源

  1. Aave Documentation - docs.aave.com
  2. Uniswap SDK Documentation - docs.uniswap.org
  3. Compound Documentation - docs.compound.finance
  4. Lido Documentation - docs.lido.fi
  5. Rocket Pool Documentation - docs.rocketpool.net
  6. OpenZeppelin Contracts - docs.openzeppelin.com
  7. Ethers.js Documentation - docs.ethers.org
  8. Hardhat Documentation - hardhat.org/docs

附錄:常用合約地址速查表

以太坊主網常用 DeFi 合約地址
────────────────────────────────────────────────────────────

協議          │ 合約類型         │ 地址
────────────────────────────────────────────────────────────
Aave V3      │ Pool            │ 0x87870Bca3F3fD6335C3FbdC83E7a82f43aa5B7c4
Aave V3      │ Oracle          │ 0xA50ba011c48153De246E5192C8fbf8Ed00646cc5
Compound V3  │ Comet (USDC)   │ 0xc3d688B66703497DAA19211EEdff47f25384cdc3
Uniswap V4   │ Router          │ 3bF4f46C05f2B1A7E5bD83A794D1eEaC9D3b2E82
Uniswap V3   │ Router          │ 0xE592427A0AEce92De3Edee1F18E0157C05861564
Uniswap V3   │ Factory         │ 0x1F98431c8aD98523631AE4a59f267346ea31F984
Curve        │ Registry        │ 0x90E00ACe148ca3B23Ac1bC8C240C2a7d9FEAB1b
Lido         │ stETH           │ 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84
Rocket Pool  │ Deposit Pool    │ 0x2D31850E4b3d6d3d8b9c3E2B3a5E1F7c4d9B2a1E
WETH         │ WETH            │ 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
USDC         │ USDC            │ 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
USDT         │ USDT            │ 0xdAC17F958D2ee523a2206206994597C13D831ec7

延伸閱讀與來源

這篇文章對您有幫助嗎?

評論

發表評論

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

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