前言
继上一篇 DAO 基础理论与代码落地的讲解,本文继续深入DAO2.0核心理论,并带来可直接落地的代码实践,带你完成从基础到进阶的技术跨越。
概述
DAO 1.0 与 DAO 2.0 的核心区别在于从“初级的自动化投票”进化到“复杂的治理与流动性管理”。DAO 1.0 解决了基础的组织去中心化问题,而 DAO 2.0 致力于解决治理低效、流动性不可持续以及跨组织协作等深层次挑战
DAO1.0 vs DAO2.0关键差异
1. 核心定义与重心
- DAO 1.0(基础自动化) :主要关注通过智能合约实现组织的初步运行,如提案、投票和国库资金拨付。其核心是“代码即法律”,强调规则的透明度和不可篡改性。
- DAO 2.0(管理与演化) :重心转向“治理的治理”(Management of Management)。它不仅是规则的执行,更引入了算法自动适配、管理会计和实时审计等系统,使组织能根据外部环境(如市场波动、Gas 费变化)自动调整策略。
2. 流动性与经济模型(DeFi 2.0 视角)
- DAO 1.0:通常依赖流动性挖矿(Yield Farming)吸引外部资金。用户持有流动性,一旦奖励减少,资金便会迅速流失,导致“雇佣兵资本”问题。
- DAO 2.0:引入了协议控制流动性(Protocol-Owned Liquidity, POL) 。组织通过债券等机制直接拥有自己的流动性,增强了财务稳定性,减少了对第三方投资者的依赖。
3. 协作维度
- DAO 1.0:侧重于 DAO 内部成员的交互,即解决一个组织内部如何达成共识。
- DAO 2.0:开启了 DAO2DAO (D2D) 时代。研究和实践转向不同 DAO 之间的协作、跨链资产管理以及生态系统级别的资源整合。
4. 技术与工具演进
- DAO 1.0:受限于 Layer 1 的高昂 Gas 费和较低的吞吐量,治理决策成本高且响应慢。
- DAO 2.0:利用 Layer 2 扩展方案、更复杂的智能合约架构(如 Hedera Smart Contracts 2.0)以及模块化治理工具,实现了更高的交易速度、数据精确度和参与自由度。
关键差异总结表
| 维度 | DAO 1.0 | DAO 2.0 |
|---|---|---|
| 治理重心 | 基础投票与资金拨付 | 动态自适应治理、算法审计 |
| 流动性控制 | 参与者持有(不稳定) | 协议自身持有(POL,可持续) |
| 协作范围 | 内部成员交互 | 跨组织 (DAO2DAO) 协作 |
| 解决痛点 | 中心化权威问题 | 治理效率低、流动性不稳、高成本 |
| 典型特征 | “代码即法律” | “管理之上的管理” |
DAO 1.0 vs 2.0 落地表现对比
1. 协议控制流动性 (Protocol-Owned Liquidity, POL)
这是 DAO 2.0 最早的爆发点(源于 DeFi 2.0 运动)。
- 场景:DAO 不再发放高额代币奖励(挖矿)来租用流动性,而是通过债券(Bonds)机制用协议代币换取用户的 LP Token。
- 落地案例:OlympusDAO。它将流动性永久留在 DAO 金库(Timelock)中,使组织拥有极强的财务韧性,避免了“挖矿、提现、砸盘”的恶性循环。
2. DAO2DAO (D2D) 协同治理与资产互换
DAO 1.0 是个人与组织的交互,2.0 开启了组织间的商业协作。
- 场景:两个 DAO 通过智能合约进行库藏资产互换(Token Swaps)、共同出资建立联合激励池,或建立跨协议的治理约束。
- 落地案例:PrimeDAO。它开发了专门用于 D2D 协作的工具(如 Joint Ventures),允许两个 DAO 共同管理一个子金库,实现生态捆绑。
3. 子 DAO (Sub-DAOs) 与模块化职能部门
解决大型 DAO 治理低效(所有人投所有票)的问题。
- 场景:母 DAO 将预算和权限分配给专注特定职能的子 DAO(如审计组、开发组、风险组)。子 DAO 在授权范围内自主决策,母 DAO 保留最终否决权。
- 落地案例:MakerDAO (Endgame 计划) 。它拆分出多个“元子 DAO”(MetaDAOs),每个子 DAO 有独立的代币和治理逻辑,降低了主协议的治理负荷。
4. 自动化算法治理 (Algorithmic Governance)
将治理从“纯人为判断”升级为“算法触发”。
- 场景:利用 Oracle(预言机) 监测链上指标。当某些参数(如稳定币脱锚、国库清算风险)达到阈值时,合约自动触发防御性提案或参数调整,无需等待漫长的人工投票。
- 落地案例:Lido 或 Aave。其风险控制模块可以在紧急状态下由算法自动暂停特定借贷市场,这种“实时响应”是 DAO 2.0 的标志。
5. 跨链治理 (Cross-chain Governance)
随着多链生态发展,DAO 必须具备跨链指挥权。
- 场景:治理提案在以太坊主网发起并投票,执行结果通过跨链桥(如 LayerZero, Axelar)自动触发 Layer 2 或其他公链上的合约修改。
- 落地案例:Uniswap。它的治理依然在 L1,但可以通过跨链指令管理部署在 Polygon、Arbitrum 等链上的协议参数。
DAO 1.0 vs 2.0 落地表现对比
| 特性 | DAO 1.0 表现 | DAO 2.0 表现 |
|---|---|---|
| 金库管理 | 闲置资产,仅用于拨款 | 积极投资、POL、流动性管理 |
| 执行效率 | 依赖多签,人工操作多 | 时间锁自动化、算法触发执行 |
| 组织结构 | 扁平化,决策拥堵 | 层级化(子 DAO)、模块化治理 |
| 激励机制 | 简单的代币奖励 | 动态归属(Vesting)、基于贡献的声誉系统 |
智能合约落地全流程
智能合约
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
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";
import "@openzeppelin/contracts/governance/TimelockController.sol";
contract MyToken is ERC20, ERC20Permit, ERC20Votes {
constructor() ERC20("Governance Token", "GT") ERC20Permit("Governance Token") {
_mint(msg.sender, 1000000 * 10**decimals());
}
// 解决 ERC20Permit 和 Governor(Nonces) 的冲突
function nonces(address owner) public view override(ERC20Permit, Nonces) returns (uint256) {
return super.nonces(owner);
}
function _update(address from, address to, uint256 value) internal override(ERC20, ERC20Votes) {
super._update(from, to, value);
}
}
// 包装一下,让 Hardhat 能够识别并编译它
contract MyTimelock is TimelockController {
constructor(
uint256 minDelay,
address[] memory proposers,
address[] memory executors,
address admin
) TimelockController(minDelay, proposers, executors, admin) {}
}
contract MyGovernor is
Governor,
GovernorSettings,
GovernorCountingSimple,
GovernorVotes,
GovernorVotesQuorumFraction,
GovernorTimelockControl
{
constructor(IVotes _token, TimelockController _timelock)
Governor("MyDAO_2.0")
GovernorSettings(1, 10, 0)
GovernorVotes(_token)
GovernorVotesQuorumFraction(4)
GovernorTimelockControl(_timelock)
{}
// --- 核心修复:简化 override 列表,只保留基类 Governor ---
function votingDelay() public view override(Governor, GovernorSettings) returns (uint256) {
return super.votingDelay();
}
function votingPeriod() public view override(Governor, GovernorSettings) returns (uint256) {
return super.votingPeriod();
}
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();
}
// 这里是报错的关键:简化为 override(Governor)
function supportsInterface(bytes4 interfaceId) public view override(Governor) returns (bool) {
return super.supportsInterface(interfaceId);
}
// V5 内部执行逻辑
function _executeOperations(uint256 proposalId, address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash)
internal override(Governor, GovernorTimelockControl)
{
super._executeOperations(proposalId, targets, values, calldatas, descriptionHash);
}
function _queueOperations(uint256 proposalId, address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash)
internal override(Governor, GovernorTimelockControl) returns (uint48)
{
return super._queueOperations(proposalId, targets, values, calldatas, descriptionHash);
}
function _cancel(address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash)
internal override(Governor, GovernorTimelockControl) returns (uint256)
{
return super._cancel(targets, values, calldatas, descriptionHash);
}
function _executor() internal view override(Governor, GovernorTimelockControl) returns (address) {
return super._executor();
}
function proposalNeedsQueuing(uint256 proposalId) public view override(Governor, GovernorTimelockControl) returns (bool) {
return super.proposalNeedsQueuing(proposalId);
}
}
测试脚本
测试用例说明
- 完成从提案发起、投票、进入时间锁到成功拨付资金的完整 2.0 流程
- 赞成票未达标时提案应被拒绝
import assert from "node:assert/strict";
import { describe, it, beforeEach } from "node:test";
import { network } from "hardhat";
import { keccak256, encodePacked, encodeFunctionData, decodeEventLog, zeroAddress } from 'viem';
describe("DAO 2.0 Governance Lifecycle (V5 + Viem)", function () {
let token: any;
let timelock: any;
let governor: any;
let publicClient: any;
let testClient: any;
let deployer: any, voter: any, proposer: any;
beforeEach(async function () {
const { viem } = await (network as any).connect();
publicClient = await viem.getPublicClient();
testClient = await viem.getTestClient();
[deployer, voter, proposer] = await viem.getWalletClients();
// --- 修复 1: 使用完全限定名 (Fully Qualified Name) 解决 HHE1001 ---
token = await viem.deployContract("contracts/DAO2.0.sol:MyToken", []);
// Timelock 通常在库里,如果没有重名可以直接用,稳妥起见也可以指定
timelock = await viem.deployContract("contracts/DAO2.0.sol:MyTimelock", [
0n,
[],
[],
deployer.account.address
]);
governor = await viem.deployContract("contracts/DAO2.0.sol:MyGovernor", [
token.address,
timelock.address
]);
// --- 核心修复点:分配足够的代币以满足 Quorum (4%) ---
// 假设总供应量是 1,000,000。4% 是 40,000。
// 我们给 voter 分配 100,000 (10%) 确保绝对通过。
const amount = 100000n * 10n ** 18n;
await token.write.transfer([voter.account.address, amount]);
// 关键:必须在 delegate 后推进区块,Governor 才会记录快照
await token.write.delegate([voter.account.address], { account: voter.account });
// 给金库充钱(供提案拨付用)
await token.write.transfer([timelock.address, amount]);
// 推进区块以确保 delegate 产生的快照被 Governor 识别
await testClient.mine({ blocks: 5 });
// 4. 权限设置 (保持不变)
const PROPOSER_ROLE = keccak256(encodePacked(['string'], ['PROPOSER_ROLE']));
const EXECUTOR_ROLE = keccak256(encodePacked(['string'], ['EXECUTOR_ROLE']));
await timelock.write.grantRole([PROPOSER_ROLE, governor.address]);
await timelock.write.grantRole([EXECUTOR_ROLE, zeroAddress]);
});
it("应该完成从提案发起、投票、进入时间锁到成功拨付资金的完整 2.0 流程", async function () {
const calldata = encodeFunctionData({
abi: token.abi,
functionName: 'transfer',
args: [proposer.account.address, 100n * 10n ** 18n]
});
const description = "DAO 2.0: Grant Funding";
const descHash = keccak256(encodePacked(['string'], [description]));
// 1. Propose
const txHash = await governor.write.propose([
[token.address], [0n], [calldata], description
], { account: proposer.account });
const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
// --- 修复 2: 健壮的事件解码 (适配 V5 多个 Log 的情况) ---
const event = decodeEventLog({
abi: governor.abi,
eventName: 'ProposalCreated',
// 遍历 logs 找到对应的事件
...receipt.logs.find((log: any) => {
try {
const decoded = decodeEventLog({ abi: governor.abi, ...log });
return decoded.eventName === 'ProposalCreated';
} catch { return false; }
})
});
const proposalId = (event.args as any).proposalId;
// 2. Vote
await testClient.mine({ blocks: 2 });
await governor.write.castVote([proposalId, 1], { account: voter.account });
// 3. Queue
await testClient.mine({ blocks: 15 });
const currentState = await governor.read.state([proposalId]);
console.log("Proposal State after voting:", currentState); // 应该输出 4 (Succeeded)
assert.equal(Number(currentState), 4, "提案应当成功通过,而不是 Defeated");
await governor.write.queue([[token.address], [0n], [calldata], descHash]);
// 4. Execute
await governor.write.execute([[token.address], [0n], [calldata], descHash]);
// 验证
const balance = await token.read.balanceOf([proposer.account.address]);
assert.equal(balance, 100n * 10n ** 18n, "资金应由 Timelock 拨付成功");
});
it("当赞成票未达标时提案应被拒绝 (Defeated)", async function () {
const tx = await governor.write.propose([[token.address], [0n], ['0x'], "Fail Test"]);
const receipt = await publicClient.waitForTransactionReceipt({ hash: tx });
const event = decodeEventLog({
abi: governor.abi, eventName: 'ProposalCreated',
...receipt.logs.find((log: any) => log.topics[0] === keccak256(encodePacked(['string'], ['ProposalCreated(uint256,address,address[],uint256[],string[],bytes[],uint256,uint256,string)'])))
});
const proposalId = (event.args as any).proposalId;
await testClient.mine({ blocks: 2 });
await governor.write.castVote([proposalId, 0], { account: voter.account });
await testClient.mine({ blocks: 15 });
const state = await governor.read.state([proposalId]);
assert.equal(Number(state), 3, "状态应为 Defeated");
});
});
部署脚本
// scripts/deploy.js
import { network, artifacts } from "hardhat";
async function main() {
// 连接网络
const { viem } = await network.connect({ network: network.name });//指定网络进行链接
// 获取客户端
const [deployer] = await viem.getWalletClients();
const publicClient = await viem.getPublicClient();
const deployerAddress = deployer.account.address;
console.log("部署者的地址:", deployerAddress);
// 加载合约
const TokenArtifact = await artifacts.readArtifact("contracts/DAO2.0.sol:MyToken");
const GovernorArtifact = await artifacts.readArtifact("contracts/DAO2.0.sol:MyGovernor");
const TimelockArtifact = await artifacts.readArtifact("contracts/DAO2.0.sol:MyTimelock");
const TokenHash = await deployer.deployContract({
abi: TokenArtifact.abi,//获取abi
bytecode: TokenArtifact.bytecode,//硬编码
args: [],
});
const TokenReceipt = await publicClient.waitForTransactionReceipt({ hash: TokenHash });
console.log("Token合约地址:", TokenReceipt.contractAddress);
const TimelockHash = await deployer.deployContract({
abi: TimelockArtifact.abi,//获取abi
bytecode: TimelockArtifact.bytecode,//硬编码
args: [0n, [], [], deployerAddress],
});
const TimelockReceipt = await publicClient.waitForTransactionReceipt({ hash: TimelockHash });
console.log("Timelock合约地址:", TimelockReceipt.contractAddress);
// 部署
const GovernorHash = await deployer.deployContract({
abi: GovernorArtifact.abi,//获取abi
bytecode: GovernorArtifact.bytecode,//硬编码
args: [TokenReceipt.contractAddress, TimelockReceipt.contractAddress],
});
const GovernorReceipt = await publicClient.waitForTransactionReceipt({ hash: GovernorHash });
console.log("Governor合约地址:", GovernorReceipt.contractAddress);
}
main().catch(console.error);
结语
至此,本文已完成 DAO2.0 从理论到代码落地的全流程讲解,并系统对比了 DAO1.0 与 DAO2.0 的核心差异。希望能为大家理解与实践新一代 DAO 提供清晰参考。