Xinmin's Blog
AdminRSS
全部AIDeFiSolidity以太坊公链实战区块链行业观察
Admin
RSS

开发完借贷协议后,我终于看懂了Uniswap DAO治理

DeFi·2025年6月4日·1 次阅读·约 26 分钟
© 2026·

说在前面

2021年开发Xai-Maker借贷协议时,我们遇到了一个让整个团队头疼的问题:谁来决定借贷利率?

传统金融里,这种事银行说了算。但在DeFi的世界,如果让项目方单方面控制利率,用户凭什么信任你?如果完全放任市场,万一出现极端情况怎么办?经过调研,我把目光投向了Uniswap——这个管理着数百亿美元资金的去中心化治理典范。

深入研究Uniswap的治理合约后,我有种"原来如此"的恍然大悟感。这套看似复杂的系统,实际上是一部精妙的"民主机器",每个齿轮都有其深层的设计哲学。今天我想从一个开发者的角度,与你分享一下这套治理机制到底有什么过人之处。

三个核心组件:治理的"铁三角"

想象一下,如果要设计一套让千万人参与决策的系统,你会怎么做?

Uniswap给出的答案是三个核心合约的完美配合:

UNI Token合约 — 相当于"选民证",不仅记录你的投票权,还能让你把票委托给信任的人。这解决了"我有UNI但没时间研究每个提案"的现实问题。

GovernorAlpha合约 — 就像"议会大厅",负责收集提案、统计投票、判断结果。虽然名字里有"Alpha"(说明这是早期版本),但功能已经相当完备。

Timelock合约 — 这是最关键的"安全阀"。任何通过的提案都不能立即执行,必须等待2-30天的公示期。这给了社区最后的反悔机会,也给了恶意提案被发现的时间。

有意思的是,Uniswap用的GovernorAlpha确实有些"年代感"了。现在更新的治理合约有更多功能,但Uniswap依然在用这套相对简单的系统。为什么?或许正是"简单即美"的体现——功能够用就行,稳定性更重要。

治理流程:从"民意测试"到"法律生效"

说起Uniswap的治理流程,我最佩服的是它的"渐进式筛选"设计。

链下阶段:把好想法"孵化"出来

首先是3天的温度检查。就像你想在朋友圈发个想法试试水一样,提案者会在论坛、Discord等地方抛出想法,看看有没有人响应。门槛很低:只要25,000个UNI支持就算通过。

接着是5天的共识检查。这时候讨论会更正式,类似于"听证会"。支持门槛提高到50,000个UNI,让提案者必须回应质疑,完善方案。

这两个环节都在Snapshot平台进行,最大的好处是不需要Gas费。

想象一下,如果每次投票都要花几十美元手续费,还有多少人愿意参与?

链上阶段:真金白银的较量

经过链下"预热",提案正式进入链上投票。这时门槛骤然提高,看看GovernorAlpha合约里的关键参数设置:

/// @notice 发起提案需要的投票权重门槛
function proposalThreshold() public pure returns (uint) {
    return 10_000_000e18; // 1000万UNI,占总供应量1%
}

/// @notice 提案通过需要的最低支持票数
function quorumVotes() public pure returns (uint) {
    return 40_000_000e18; // 4000万UNI,占总供应量4%
}

/// @notice 投票期长度(以区块计算)
function votingPeriod() public pure returns (uint) {
    return 40_320; // 约7天(按15秒/区块计算)
}

/// @notice 单个提案最多可包含的操作数
function proposalMaxOperations() public pure returns (uint) {
    return 10; // 防止复杂攻击
}

为什么门槛设置得这么高?我理解这是一种"负责任的民主"。1%的发起门槛确保提案者是真心的,不是来捣乱的;4%的通过门槛确保重大决策有足够的民意支持。

最后是执行阶段。通过的提案不会立即生效,而是进入Timelock"冷静期",Timelock合约中的时间参数设置如下:

uint public constant GRACE_PERIOD = 14 days;      // 宽限期
uint public constant MINIMUM_DELAY = 2 days;      // 最小延迟
uint public constant MAXIMUM_DELAY = 30 days;     // 最大延迟

时间成本:民主的代价

算下来,一个提案从想法到落地,最快也要17天,正常情况下需要22天,复杂提案可能长达45天。

这效率在传统公司看来简直是"龟速",但在去中心化治理中,这恰恰是安全的保障。毕竟,一旦执行错误,可能造成数亿美元的损失。

委托机制:让专业的人做专业的事

说到委托机制,这是我觉得最巧妙的设计之一。

现实中,大部分UNI持有者并没有时间和精力研究每个技术提案。怎么办?委托给你信任的专家呗!这就像选举制度中的"代议制"。

但这里面有个技术难题:如何防止有人在投票期间突然买入大量代币来操纵结果?

Uniswap的解决方案是Checkpoint机制——每当代币发生转移或委托变化,系统就会在那个区块号记录一个"快照"。投票时,使用的是提案开始时的历史权重,而不是当前权重。

/// @notice 检查点结构,记录特定区块的投票权重
struct Checkpoint {
    uint32 fromBlock;    // 生效区块号
    uint96 votes;        // 投票权重
}

/// @notice 获取账户在指定区块的历史投票权重
function getPriorVotes(address account, uint blockNumber)
    public view returns (uint96) {
    require(blockNumber < block.number, "not yet determined");

    uint32 nCheckpoints = numCheckpoints[account];
    if (nCheckpoints == 0) {
        return 0;
    }

    // 检查最新检查点
    if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) {
        return checkpoints[account][nCheckpoints - 1].votes;
    }

    // 二分查找历史权重
    uint32 lower = 0;
    uint32 upper = nCheckpoints - 1;
    while (upper > lower) {
        uint32 center = upper - (upper - lower) / 2;
        // ... 二分查找逻辑
    }
    return checkpoints[account][lower].votes;
}

这套机制的精妙之处在于:既允许了灵活的委托,又防止了恶意操纵。每个人的投票权重在提案开始的那一刻就"锁定"了,买再多币也没用。

参数设计:博弈论的艺术

Uniswap的治理参数设置,我觉得是博弈论在实践中的经典案例:

环节 门槛 设计意图
温度检查 25,000 UNI 过滤明显不靠谱的想法
共识检查 50,000 UNI 确保有一定民意基础
发起提案 1000万 UNI(1%) 防止垃圾提案泛滥
通过提案 4000万 UNI(4%) 确保重大决策有足够支持

这种"递进式门槛"设计很聪明:既给了小想法萌芽的机会,又确保重大决策不被少数人绑架。

1%的发起门槛意味着,按当前价格,你大概需要几千万美元的UNI才能发起提案。这听起来很高,但考虑到Uniswap管理的资金规模,这个门槛其实很合理。

4%的通过门槛更是关键。想想看,如果门槛太低,比如1%,那可能几个大户就能通过影响整个协议的提案;如果太高,比如10%,那可能永远都通过不了任何提案。4%正好在"民主"和"效率"之间找到了平衡点。

GovernorAlpha:简单但有效的"投票机"

深入看GovernorAlpha的代码实现,我发现它的设计哲学是"简单粗暴,但管用"。

比如投票选项,只有"支持"和"反对"两种,没有现代治理合约常见的"弃权"选项。这看似简陋,但在实际使用中反而避免了很多复杂情况。

/// @notice 投票记录结构
struct Receipt {
    bool hasVoted;       // 是否已投票
    bool support;        // 是否支持(true-支持,false-反对)
    uint96 votes;        // 投票权重
}

/// @notice 内部投票逻辑
function _castVote(address voter, uint proposalId, bool support) internal {
    require(state(proposalId) == ProposalState.Active, "voting is closed");

    Proposal storage proposal = proposals[proposalId];
    Receipt storage receipt = proposal.receipts[voter];
    require(receipt.hasVoted == false, "voter already voted");

    // 获取提案开始时的历史投票权重
    uint96 votes = uni.getPriorVotes(voter, proposal.startBlock);

    if (support) {
        proposal.forVotes = add256(proposal.forVotes, votes);
    } else {
        proposal.againstVotes = add256(proposal.againstVotes, votes);
    }

    receipt.hasVoted = true;
    receipt.support = support;
    receipt.votes = votes;

    emit VoteCast(voter, proposalId, support, votes);
}

提案的生命周期也很清晰,总共8个状态:从Pending(等待开始)到Executed(执行完成),每个状态转换都有明确的条件。

enum ProposalState {
    Pending,     // 等待投票开始
    Active,      // 投票进行中
    Canceled,    // 已取消
    Defeated,    // 投票失败
    Succeeded,   // 投票成功,等待排队
    Queued,      // 已排队到Timelock
    Expired,     // 执行期过期
    Executed     // 已执行
}

function state(uint proposalId) public view returns (ProposalState) {
    Proposal storage proposal = proposals[proposalId];

    if (proposal.canceled) {
        return ProposalState.Canceled;
    } else if (block.number <= proposal.startBlock) {
        return ProposalState.Pending;
    } else if (block.number <= proposal.endBlock) {
        return ProposalState.Active;
    } else if (proposal.forVotes <= proposal.againstVotes ||
               proposal.forVotes < quorumVotes()) {
        return ProposalState.Defeated;
    } else if (proposal.eta == 0) {
        return ProposalState.Succeeded;
    } else if (proposal.executed) {
        return ProposalState.Executed;
    } else if (block.timestamp >= add256(proposal.eta, timelock.GRACE_PERIOD())) {
        return ProposalState.Expired;
    } else {
        return ProposalState.Queued;
    }
}

最有意思的是,GovernorAlpha限制每个地址同时只能有一个活跃提案。这防止了"提案轰炸"攻击,也确保了每个提案都能得到充分的讨论。

function propose(...) public returns (uint) {
    // 检查提案者是否有足够投票权
    require(
        uni.getPriorVotes(msg.sender, sub256(block.number, 1)) > proposalThreshold(),
        "proposer votes below proposal threshold"
    );

    // 检查是否有其他活跃提案
    uint latestProposalId = latestProposalIds[msg.sender];
    if (latestProposalId != 0) {
        ProposalState proposersLatestProposalState = state(latestProposalId);
        require(
            proposersLatestProposalState != ProposalState.Active &&
            proposersLatestProposalState != ProposalState.Pending,
            "one live proposal per proposer"
        );
    }

    // ... 创建提案逻辑
}

Timelock:最后的"安全网"

如果说GovernorAlpha是民主决策的机器,那Timelock就是防止决策错误的保险丝。

任何通过的提案都必须先进入"排队"状态,等待指定的时间后才能执行。这个等待期最短2天,最长30天,具体时长取决于提案的重要性。

function queueTransaction(
    address target,
    uint value,
    string memory signature,
    bytes memory data,
    uint eta
) public returns (bytes32) {
    require(msg.sender == admin, "Call must come from admin");
    require(
        eta >= getBlockTimestamp().add(delay),
        "Estimated execution block must satisfy delay"
    );

    bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));
    queuedTransactions[txHash] = true;

    emit QueueTransaction(txHash, target, value, signature, data, eta);
    return txHash;
}

function executeTransaction(
    address target,
    uint value,
    string memory signature,
    bytes memory data,
    uint eta
) public payable returns (bytes memory) {
    require(msg.sender == admin, "Call must come from admin");

    bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));
    require(queuedTransactions[txHash], "Transaction hasn't been queued");
    require(getBlockTimestamp() >= eta, "Transaction hasn't surpassed time lock");
    require(
        getBlockTimestamp() <= eta.add(GRACE_PERIOD),
        "Transaction is stale"
    );

    queuedTransactions[txHash] = false;

    // 执行交易
    bytes memory callData = bytes(signature).length == 0 ?
        data :
        abi.encodePacked(bytes4(keccak256(bytes(signature))), data);

    (bool success, bytes memory returnData) = target.call{value: value}(callData);
    require(success, "Transaction execution reverted");

    emit ExecuteTransaction(txHash, target, value, signature, data, eta);
    return returnData;
}

更巧妙的是,即使等待期结束,提案也只有14天的"宽限期"来执行。超过这个时间窗口,提案就自动过期,需要重新走流程。

这种设计的深层逻辑是:给社区"后悔"的机会,也给恶意提案被发现的时间。想象一下,如果有人通过某种方式推动了一个有害的提案,至少还有几天到几十天的时间来阻止它。

效率vs安全:一个永恒的权衡

从效率角度看,Uniswap的治理确实"慢"。一个简单的参数修改可能需要几个星期才能生效。但从安全角度看,这种"慢"恰恰是必要的。

在传统公司,CEO可能一个电话就能改变重要决策。但在管理数百亿美元的去中心化协议中,任何匆忙的决定都可能带来灾难性后果。

我们在设计Xai-Maker的治理机制时,也面临着同样的权衡。最终我们选择了类似的渐进式流程,虽然慢一点,但至少能睡得安稳。

DAO治理的适用边界:什么时候适合用DAO?

经过深度研究Uniswap的治理机制,我开始思考一个更现实的问题:什么情况下适合用DAO?

在Web3圈子里,我们经常听到"未来公司的组织形式就是DAO"这样的论调。但经过几年的实践,我发现理想很丰满,现实很骨感。

DAO的"甜蜜点"

从Uniswap的成功经验来看,DAO适用需要满足几个关键条件:

1. 利益相关者众多,决策影响面大 Uniswap管理着数百亿美元资金,每个参数调整都影响成千上万用户。这种情况下去中心化决策是必要的。但如果你的项目只有几个核心用户,为了调整一个参数要走22天流程,这不是民主,这是自虐。

2. 安全性优于效率,决策可以"慢一点" 协议级别的重大升级、资金分配可以慢几个星期,但一旦出错可能万劫不复。但如果需要快速响应市场变化,DAO治理可能让你错失良机。

3. 治理对象相对客观,不需要太多主观判断 代码升级、参数调整有相对客观的评判标准。但产品设计、品牌策略这类需要主观判断的决策,DAO往往力不从心。想象一下让几万人投票决定UI颜色——这画面太美我不敢看。

DAO不适合的场景

早期项目快速迭代期:需要"快速试错、快速调整",民主流程天然与"快速"相冲突。

复杂专业决策:智能合约安全审计、算法优化等,普通代币持有者投票其实是"伪民主"。

信息不对称场景:商业谈判、战略合作等无法完全公开的决策。

混合治理:更现实的选择

最成功的项目往往采用"混合治理":

  • 核心协议参数:DAO治理,追求安全和信任
  • 产品迭代:核心团队主导,追求效率
  • 资金分配:DAO治理,确保透明
  • 日常运营:委托专业团队

Uniswap实际上也是这样做的——重大决策通过DAO,日常开发还是由专业团队负责。

给创业者的建议

先问目的:治理的目的是获得信任、分散风险,还是因为"DAO很酷"?

从边缘开始:从社区活动、小额资金分配开始实验,积累经验后再扩大范围。

保留紧急机制:即使Uniswap也保留了Guardian角色,完全去中心化在现阶段还不现实。

DAO不是万能药,也不是必需品。它更像是一种工具,适合特定的场景和阶段。Uniswap的成功证明了DAO在协议层面的可行性,但不意味着所有项目都应该复制这套模式。

写在最后

回过头看,Uniswap的治理系统并不完美,但它找到了一个相对平衡的解决方案。在安全性、效率性和民主性之间,它选择了安全和民主,适度牺牲了效率。

对于我们这些后来者,Uniswap最大的价值不是提供了一个完美的模板,而是证明了去中心化治理是可行的。它用实际行动告诉我们:代码可以是法律,社区可以是正攵府,技术可以服务于更崇高的理想。

也许未来真会出现完全去中心化的组织,但在那之前,我们需要的不是盲目理想主义,而是务实的渐进式探索。就像Uniswap的治理——不完美,但足够好;不激进,但很稳定。

这也是我为什么选择在这个行业深耕的原因——我们不仅仅是在写代码,更是在重新定义人类协作的方式。

继续阅读

基于全文检索与主题相似度

DeFi2023年12月4日

【DAO】从Uniswap学习DAO治理

自17年学习区块链以来,笔者先后参与开发诸多web3项目,如DeFi借贷、NFT交易平台、链游、IDO、O2C、DAO、版权、Fabric等DAPPs,近期想做些知识沉淀与分享,坚持原创,内容持续更新,欢迎关注我的公众号。 本文主要分享Uniswap是怎样做治理的,读完全文大约需要12分钟。 主要内

DeFi2025年6月12日

Uniswap v1到v4的进化之路:面试官最爱问的技术要点

说在前面 作为一个在Web3领域深耕多年的开发者,我经常被面试官问到Uniswap各个版本之间的区别。 今天,我想用最直白的方式,带你理解Uniswap从v1到v4的核心变化,让你在面对相关问题时能够条理清晰地回答。 核心区别一览 先给你一个全局视角,Uniswap四个版本的关键变化: - v1:开

DeFi2025年5月30日

Uniswap V3最优路径算法全解:别再傻傻直接换币了

在区块链的世界里,DEX的效率,说白了,直接决定了你交易时能不能“多省点、多赚点”。你有没有遇到过这种情况:在Uniswap V3上把 ETH换成USDC,有时候直接兑换就挺划算的,有时候却发现绕个弯,比如先换成WBTC,再换成USDC,反而能多拿一点? 这可不是巧合,而是一套精心设计的最优路径查找