🏛️ 第21课:DAO治理

治理与未来 阶段五 ✅ 验证通过

🎯 学习目标:理解DAO(去中心化自治组织)的概念与治理机制,掌握提案-投票-执行流程,使用OpenZeppelin Governor实现完整的链上治理系统。

📖 一、什么是DAO?

DAO = Decentralized Autonomous Organization(去中心化自治组织)

传统组织 vs DAO:

传统公司:
• 董事会决策,CEO执行
• 法律管辖,法院仲裁
• 股权代表投票权
• 文件化章程

DAO:
• 代币持有者投票决策
• 智能合约执行,代码即法律
• 治理代币代表投票权
• 链上治理合约即章程

知名DAO:
• Uniswap DAO — 管理2B+美元国库
• MakerDAO — 管理DAI稳定币
• Aave DAO — 管理Aave借贷协议
• ConstitutionDAO — 众筹拍美国宪法副本(4700万美元)

📖 二、治理流程

DAO 治理全流程 1. 创建提案 2. 投票期 3. 时间锁 4. 执行 ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ 提案者 │ │ 代币持有者│ │ 等待期 │ │ 任何人 │ │ 持有≥阈值 │ │ 投赞成/反对│ │ 反对者退出│ │ 触发执行 │ │ 代币 │ │ 弃权 │ │ 2天 │ │ 合约调用 │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │ │ │ ▼ ▼ ▼ ▼ 提案ID生成 赞成票 > 反对票? 通过? → 进入时间锁 执行交易 + 目标合约 赞成票 ≥ 法定人数? 状态变更 + 调用数据 投票期:3-7天 + 描述 ❌ 失败路径: • 投票期结束时赞成票 < 反对票 → 提案被否决 • 赞成票未达法定人数 → 提案失败 • 时间锁期间被取消 → 提案作废

📖 三、使用OpenZeppelin Governor

// contracts/MyGovernor.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "@openzeppelin/contracts/governance/Governor.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorSettings.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorCountingSimple.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorVotes.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorVotesQuorumFraction.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorTimelockControl.sol";

/**
 * @title MyGovernor
 * @dev 完整的链上治理合约
 * 
 * 治理参数:
 * - 投票延迟: 1个区块(提案创建后1个区块才能投票)
 * - 投票期: 50400个区块(约1周)
 * - 提案门槛: 100个代币才能创建提案
 * - 法定人数: 总供应量的4%
 * - 时间锁: 2天(执行前等待期)
 */
contract MyGovernor is
    Governor,
    GovernorSettings,
    GovernorCountingSimple,
    GovernorVotes,
    GovernorVotesQuorumFraction,
    GovernorTimelockControl
{
    constructor(
        IVotes _token,
        TimelockController _timelock
    )
        Governor("MyDAO")
        GovernorSettings(
            1,       // votingDelay: 1个区块
            50400,   // votingPeriod: ~1周
            100e18   // proposalThreshold: 100代币
        )
        GovernorVotes(_token)
        GovernorVotesQuorumFraction(4) // 4%法定人数
        GovernorTimelockControl(_timelock)
    {}

    // 以下函数必须重写以解决多继承冲突
    function quorum(uint256 blockNumber)
        public view
        override(Governor, GovernorVotesQuorumFraction)
        returns (uint256)
    {
        return super.quorum(blockNumber);
    }

    function state(uint256 proposalId)
        public view
        override(Governor, GovernorTimelockControl)
        returns (ProposalState)
    {
        return super.state(proposalId);
    }

    function proposalThreshold()
        public view
        override(Governor, GovernorSettings)
        returns (uint256)
    {
        return super.proposalThreshold();
    }

    function supportsInterface(bytes4 interfaceId)
        public view
        override(Governor, GovernorTimelockControl)
        returns (bool)
    {
        return super.supportsInterface(interfaceId);
    }
}

3.1 部署治理系统

// scripts/deploy-governance.js
async function main() {
  // 1. 部署治理代币(必须实现IVotes/ERC20Votes)
  const GovToken = await hre.ethers.getContractFactory("GovToken");
  const token = await GovToken.deploy();
  console.log("GovToken:", await token.getAddress());

  // 2. 部署时间锁控制器
  const minDelay = 2 * 24 * 60 * 60; // 2天
  const Timelock = await hre.ethers.getContractFactory("TimelockController");
  const timelock = await Timelock.deploy(
    minDelay,
    [],    // proposers: 初始为空,由Governor管理
    [],    // executors: 初始为空
    owner.address
  );
  console.log("Timelock:", await timelock.getAddress());

  // 3. 部署Governor
  const Governor = await hre.ethers.getContractFactory("MyGovernor");
  const governor = await Governor.deploy(token.getAddress(), timelock.getAddress());
  console.log("Governor:", await governor.getAddress());

  // 4. 设置时间锁角色
  const proposerRole = await timelock.PROPOSER_ROLE();
  const executorRole = await timelock.EXECUTOR_ROLE();
  await timelock.grantRole(proposerRole, await governor.getAddress());
  await timelock.grantRole(executorRole, hre.ethers.ZeroAddress); // 任何人可执行
  await timelock.revokeRole(await timelock.TIMELOCK_ADMIN_ROLE(), owner.address);

  console.log("✅ 治理系统部署完成!");
}

📖 四、提案与投票实战

// 创建提案:修改协议参数
async function createProposal(governor, targetContract, newFeeRate) {
  // 编码要调用的函数
  const encodedFunction = targetContract.interface.encodeFunctionData(
    "setFeeRate",
    [newFeeRate]
  );

  // 创建提案
  const tx = await governor.propose(
    [await targetContract.getAddress()],  // 目标合约地址
    [0],                                    // 发送的ETH(0)
    [encodedFunction],                      // 调用数据
    "Proposal: 将手续费率从0.3%降低到0.2%"  // 提案描述
  );

  const receipt = await tx.wait();
  const proposalId = receipt.logs[0].args.proposalId;
  console.log("提案已创建,ID:", proposalId);

  return proposalId;
}

// 投票
async function castVote(governor, proposalId, support) {
  // support: 0=反对, 1=赞成, 2=弃权
  const tx = await governor.castVote(proposalId, support);
  await tx.wait();
  console.log(support === 1 ? "赞成票已投出" : "反对票已投出");
}

// 执行提案
async function executeProposal(governor, targetContract, newFeeRate, description) {
  const encodedFunction = targetContract.interface.encodeFunctionData(
    "setFeeRate",
    [newFeeRate]
  );

  const tx = await governor.execute(
    [await targetContract.getAddress()],
    [0],
    [encodedFunction],
    hre.ethers.id(description) // 描述的哈希
  );

  await tx.wait();
  console.log("✅ 提案已执行!手续费率已更新");
}

📖 五、治理攻击与防御

常见治理攻击:

1. 闪电贷治理攻击
• 借入大量代币 → 投票 → 归还代币
• 防御:使用快照投票(在提案创建前的区块快照)

2. 女巫攻击(Sybil)
• 将代币分散到多个地址绕过提案门槛
• 防御:设置合理的提案门槛

3. 投票贿赂
• 贿赂代币持有者按特定方式投票
• 防御:暗投票、秘密提交/揭示

4. 治理僵尸
• 不活跃的代币持有者不投票
• 防御:法定人数要求、委托投票

🧪 练习

1. DAO治理中时间锁(Timelock)的作用是什么? 2. 为什么需要快照(Checkpoint)来记录投票权? 3. 法定人数(Quorum)是什么?
🏛️

🏆 成就解锁:治理先驱

你已掌握DAO治理!从治理流程到OpenZeppelin Governor,从提案投票到安全防御,你拥有了构建去中心化组织的能力。

关键收获:

✅ DAO概念与治理流程
✅ OpenZeppelin Governor完整实现
✅ 时间锁与执行机制
✅ 提案创建、投票、执行实操
✅ 治理攻击与防御策略

📋 课程目录