Skip to content

代币治理系统

代币治理系统是去中心化项目的核心组件,用于实现基于代币的民主决策机制。本教程将介绍如何实现一个完整的代币治理系统。

功能特性

  • 提案创建和管理
  • 投票权重计算
  • 投票委托机制
  • 提案执行系统
  • 时间锁定机制

合约实现

solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

/**
 * @title TokenGovernance
 * @dev 代币治理合约实现
 */
contract TokenGovernance is Ownable, ReentrancyGuard {
    using SafeMath for uint256;
    using Counters for Counters.Counter;

    // 提案状态枚举
    enum ProposalState {
        Pending,    // 等待中
        Active,     // 活跃
        Canceled,   // 已取消
        Defeated,   // 已失败
        Succeeded,  // 已成功
        Queued,     // 已排队
        Expired,    // 已过期
        Executed    // 已执行
    }

    // 提案结构
    struct Proposal {
        uint256 id;              // 提案ID
        address proposer;        // 提案人
        address[] targets;       // 目标合约地址
        uint256[] values;        // 调用金额
        bytes[] calldatas;       // 调用数据
        uint256 startBlock;      // 开始区块
        uint256 endBlock;        // 结束区块
        uint256 forVotes;        // 赞成票
        uint256 againstVotes;    // 反对票
        uint256 abstainVotes;    // 弃权票
        bool canceled;           // 是否取消
        bool executed;           // 是否执行
        mapping(address => Receipt) receipts; // 投票记录
    }

    // 投票记录结构
    struct Receipt {
        bool hasVoted;          // 是否已投票
        uint8 support;          // 投票支持类型
        uint256 votes;          // 投票数量
    }

    // 投票配置
    struct VotingConfig {
        uint256 proposalThreshold;    // 提案门槛
        uint256 votingDelay;          // 投票延迟
        uint256 votingPeriod;         // 投票期
        uint256 quorumNumerator;      // 法定人数比例
    }

    // 状态变量
    IERC20 public token;                          // 治理代币
    VotingConfig public config;                   // 投票配置
    Counters.Counter private proposalCount;       // 提案计数器
    mapping(uint256 => Proposal) public proposals; // 提案映射
    mapping(address => address) public delegates;  // 委托映射
    mapping(address => uint256) public checkpoints; // 投票权重检查点

    // 事件
    event ProposalCreated(
        uint256 indexed proposalId,
        address indexed proposer,
        address[] targets,
        uint256[] values,
        bytes[] calldatas,
        uint256 startBlock,
        uint256 endBlock,
        string description
    );
    event ProposalCanceled(uint256 indexed proposalId);
    event ProposalExecuted(uint256 indexed proposalId);
    event VoteCast(
        address indexed voter,
        uint256 indexed proposalId,
        uint8 support,
        uint256 weight,
        string reason
    );
    event DelegateChanged(
        address indexed delegator,
        address indexed fromDelegate,
        address indexed toDelegate
    );

    /**
     * @dev 构造函数
     */
    constructor(
        address _token,
        uint256 _proposalThreshold,
        uint256 _votingDelay,
        uint256 _votingPeriod,
        uint256 _quorumNumerator
    ) {
        require(_token != address(0), "Invalid token address");
        require(_quorumNumerator <= 100, "Invalid quorum numerator");
        
        token = IERC20(_token);
        config = VotingConfig({
            proposalThreshold: _proposalThreshold,
            votingDelay: _votingDelay,
            votingPeriod: _votingPeriod,
            quorumNumerator: _quorumNumerator
        });
    }

    /**
     * @dev 创建提案
     */
    function propose(
        address[] memory targets,
        uint256[] memory values,
        bytes[] memory calldatas,
        string memory description
    ) external returns (uint256) {
        require(
            getVotes(msg.sender) >= config.proposalThreshold,
            "Insufficient votes"
        );
        require(
            targets.length == values.length &&
            targets.length == calldatas.length,
            "Invalid proposal"
        );

        uint256 proposalId = proposalCount.current();
        proposalCount.increment();

        Proposal storage proposal = proposals[proposalId];
        proposal.id = proposalId;
        proposal.proposer = msg.sender;
        proposal.targets = targets;
        proposal.values = values;
        proposal.calldatas = calldatas;
        proposal.startBlock = block.number.add(config.votingDelay);
        proposal.endBlock = proposal.startBlock.add(config.votingPeriod);

        emit ProposalCreated(
            proposalId,
            msg.sender,
            targets,
            values,
            calldatas,
            proposal.startBlock,
            proposal.endBlock,
            description
        );

        return proposalId;
    }

    /**
     * @dev 投票
     */
    function castVote(
        uint256 proposalId,
        uint8 support,
        string memory reason
    ) external {
        require(state(proposalId) == ProposalState.Active, "Voting is closed");
        require(support <= 2, "Invalid vote type");

        Proposal storage proposal = proposals[proposalId];
        Receipt storage receipt = proposal.receipts[msg.sender];
        require(!receipt.hasVoted, "Already voted");

        uint256 votes = getVotes(msg.sender);
        receipt.hasVoted = true;
        receipt.support = support;
        receipt.votes = votes;

        if (support == 0) {
            proposal.againstVotes = proposal.againstVotes.add(votes);
        } else if (support == 1) {
            proposal.forVotes = proposal.forVotes.add(votes);
        } else {
            proposal.abstainVotes = proposal.abstainVotes.add(votes);
        }

        emit VoteCast(msg.sender, proposalId, support, votes, reason);
    }

    /**
     * @dev 执行提案
     */
    function execute(uint256 proposalId) external payable {
        require(
            state(proposalId) == ProposalState.Succeeded,
            "Proposal not succeeded"
        );

        Proposal storage proposal = proposals[proposalId];
        proposal.executed = true;

        for (uint256 i = 0; i < proposal.targets.length; i++) {
            (bool success, ) = proposal.targets[i].call{value: proposal.values[i]}(
                proposal.calldatas[i]
            );
            require(success, "Proposal execution failed");
        }

        emit ProposalExecuted(proposalId);
    }

    /**
     * @dev 取消提案
     */
    function cancel(uint256 proposalId) external {
        require(
            state(proposalId) != ProposalState.Executed,
            "Cannot cancel executed proposal"
        );

        Proposal storage proposal = proposals[proposalId];
        require(
            msg.sender == proposal.proposer ||
            getVotes(proposal.proposer) < config.proposalThreshold,
            "Cannot cancel"
        );

        proposal.canceled = true;
        emit ProposalCanceled(proposalId);
    }

    /**
     * @dev 委托投票权
     */
    function delegate(address delegatee) external {
        address currentDelegate = delegates[msg.sender];
        delegates[msg.sender] = delegatee;

        emit DelegateChanged(msg.sender, currentDelegate, delegatee);
        _moveDelegates(currentDelegate, delegatee, getVotes(msg.sender));
    }

    /**
     * @dev 获取提案状态
     */
    function state(uint256 proposalId) public view returns (ProposalState) {
        Proposal storage proposal = proposals[proposalId];

        if (proposal.canceled) {
            return ProposalState.Canceled;
        }

        if (proposal.executed) {
            return ProposalState.Executed;
        }

        uint256 currentBlock = block.number;

        if (currentBlock < proposal.startBlock) {
            return ProposalState.Pending;
        }

        if (currentBlock <= proposal.endBlock) {
            return ProposalState.Active;
        }

        if (_quorumReached(proposalId) && _voteSucceeded(proposalId)) {
            return ProposalState.Succeeded;
        }

        return ProposalState.Defeated;
    }

    /**
     * @dev 获取投票权重
     */
    function getVotes(address account) public view returns (uint256) {
        return token.balanceOf(account);
    }

    /**
     * @dev 检查是否达到法定人数
     */
    function _quorumReached(uint256 proposalId) internal view returns (bool) {
        Proposal storage proposal = proposals[proposalId];
        uint256 totalSupply = token.totalSupply();
        uint256 quorum = totalSupply.mul(config.quorumNumerator).div(100);
        
        return proposal.forVotes.add(proposal.againstVotes) >= quorum;
    }

    /**
     * @dev 检查提案是否通过
     */
    function _voteSucceeded(uint256 proposalId) internal view returns (bool) {
        Proposal storage proposal = proposals[proposalId];
        return proposal.forVotes > proposal.againstVotes;
    }

    /**
     * @dev 移动委托投票权
     */
    function _moveDelegates(
        address srcRep,
        address dstRep,
        uint256 amount
    ) internal {
        if (srcRep != dstRep && amount > 0) {
            if (srcRep != address(0)) {
                checkpoints[srcRep] = checkpoints[srcRep].sub(amount);
            }
            if (dstRep != address(0)) {
                checkpoints[dstRep] = checkpoints[dstRep].add(amount);
            }
        }
    }

    /**
     * @dev 更新投票配置(仅管理员)
     */
    function updateVotingConfig(
        uint256 _proposalThreshold,
        uint256 _votingDelay,
        uint256 _votingPeriod,
        uint256 _quorumNumerator
    ) external onlyOwner {
        require(_quorumNumerator <= 100, "Invalid quorum numerator");
        
        config.proposalThreshold = _proposalThreshold;
        config.votingDelay = _votingDelay;
        config.votingPeriod = _votingPeriod;
        config.quorumNumerator = _quorumNumerator;
    }
}

关键概念

提案机制

提案系统支持:

  • 提案创建
  • 状态管理
  • 执行机制
  • 取消功能

投票机制

投票系统包括:

  • 权重计算
  • 委托投票
  • 投票记录
  • 结果统计

权限控制

权限管理:

  • 提案权限
  • 投票权限
  • 执行权限
  • 管理权限

安全考虑

  1. 提案安全

    • 门槛验证
    • 执行检查
    • 时间控制
    • 状态保护
  2. 投票安全

    • 权重验证
    • 重复投票检查
    • 委托安全
    • 结果计算
  3. 执行安全

    • 权限验证
    • 执行超时
    • 回滚处理
    • 状态同步
  4. 系统安全

    • 参数限制
    • 数据验证
    • 异常处理
    • 升级保护

最佳实践

  1. 提案管理

    • 合理的门槛
    • 充分的讨论期
    • 适当的投票期
    • 明确的执行机制
  2. 投票设计

    • 公平的权重
    • 灵活的委托
    • 透明的记录
    • 可靠的统计
  3. 系统维护

    • 参数优化
    • 数据监控
    • 异常处理
    • 升级规划
  4. 社区参与

    • 提案引导
    • 投票激励
    • 结果公示
    • 执行监督

扩展功能

  1. 多签名治理
  2. 分级投票权
  3. 提案激励
  4. 自动执行
  5. 治理代币

应用场景

  1. 协议治理

    • 参数调整
    • 升级决策
    • 资金分配
    • 战略规划
  2. 社区管理

    • 提案管理
    • 投票管理
    • 执行监督
    • 权益分配
  3. 项目发展

    • 路线决策
    • 资源分配
    • 合作审批
    • 风险控制

总结

代币治理系统是去中心化项目的重要基础。通过本教程,你可以:

  • 实现民主决策机制
  • 保障社区权益
  • 促进有效治理
  • 推动项目发展

常见问题解答(FAQ)

基础概念

Q: 什么是代币治理?

A: 代币治理是一种社区自治机制,主要特点包括:

  • 社区参与决策
  • 代币投票权重
  • 提案管理系统
  • 自动化执行
  • 透明公平治理

Q: 治理机制有哪些类型?

A: 主要类型包括:

  • 直接民主型
  • 代表制型
  • 混合治理型
  • 分层治理型
  • 专业委员会型

操作相关

Q: 如何参与代币治理?

A: 参与步骤包括:

  • 持有治理代币
  • 查看治理提案
  • 参与投票表决
  • 跟踪提案执行
  • 监督治理过程

Q: 如何优化治理效果?

A: 优化方法包括:

  • 完善提案机制
  • 优化投票流程
  • 提高参与度
  • 加强透明度
  • 保持社区活力

安全相关

Q: 治理机制有哪些风险?

A: 主要风险包括:

  • 投票操纵
  • 治理攻击
  • 提案滥用
  • 执行延迟
  • 社区分裂

Q: 如何确保治理安全?

A: 安全措施包括:

  • 多重签名控制
  • 投票锁定机制
  • 提案门槛设置
  • 延迟执行期
  • 紧急暂停机制

Released under the MIT License by Vogeb.