///! 治理模块: DAO治理协议 ///! NAC的去中心化治理标准协议 ///! ///! **版本**: v1.0 ///! **模块**: charter-std-zh/governance/governance.ch 使用 资产::gnacs::GNACS编码; 使用 主权::规则::主权类型; // ============================================================================ // 治理接口定义 // ============================================================================ /// 治理接口 /// /// 定义DAO治理的标准操作 接口 治理 { // ========== 查询函数 ========== /// 查询治理代币地址 函数 治理代币() -> 地址; /// 查询提案数量 函数 提案数量() -> u256; /// 查询提案信息 /// /// # 参数 /// - `提案ID`: 提案唯一标识符 函数 提案信息(提案ID: u256) -> 提案; /// 查询提案状态 /// /// # 参数 /// - `提案ID`: 提案唯一标识符 函数 提案状态(提案ID: u256) -> 提案状态枚举; /// 查询用户投票权重 /// /// # 参数 /// - `用户`: 用户地址 /// - `区块号`: 快照区块号 函数 投票权重(用户: 地址, 区块号: u256) -> u256; /// 查询用户是否已投票 /// /// # 参数 /// - `提案ID`: 提案唯一标识符 /// - `用户`: 用户地址 函数 是否已投票(提案ID: u256, 用户: 地址) -> 布尔; /// 查询提案投票结果 /// /// # 参数 /// - `提案ID`: 提案唯一标识符 函数 投票结果(提案ID: u256) -> (u256, u256, u256); // (赞成, 反对, 弃权) /// 查询提案阈值 函数 提案阈值() -> u256; /// 查询投票阈值 函数 投票阈值() -> u256; /// 查询投票延迟 函数 投票延迟() -> u256; /// 查询投票期限 函数 投票期限() -> u256; // ========== 状态变更函数 ========== /// 创建提案 /// /// # 参数 /// - `标题`: 提案标题 /// - `描述`: 提案描述 /// - `目标`: 执行目标合约地址数组 /// - `数值`: 执行调用的ETH数值数组 /// - `调用数据`: 执行调用的数据数组 /// /// # 返回 /// - `u256`: 提案ID /// /// # 事件 /// - `提案创建事件` 函数 创建提案( 标题: 字符串, 描述: 字符串, 目标: 数组<地址>, 数值: 数组, 调用数据: 数组<字节数组> ) -> u256; /// 投票 /// /// # 参数 /// - `提案ID`: 提案唯一标识符 /// - `支持`: 投票选项(0=反对, 1=赞成, 2=弃权) /// /// # 事件 /// - `投票事件` 函数 投票(提案ID: u256, 支持: u8); /// 执行提案 /// /// # 参数 /// - `提案ID`: 提案唯一标识符 /// /// # 事件 /// - `提案执行事件` 函数 执行提案(提案ID: u256); /// 取消提案 /// /// # 参数 /// - `提案ID`: 提案唯一标识符 /// /// # 事件 /// - `提案取消事件` 函数 取消提案(提案ID: u256); } // ============================================================================ // 数据结构定义 // ============================================================================ /// 提案结构 结构 提案 { /// 提案ID ID: u256, /// 提案者 提案者: 地址, /// 提案标题 标题: 字符串, /// 提案描述 描述: 字符串, /// 执行目标 目标: 数组<地址>, /// 执行数值 数值: 数组, /// 执行调用数据 调用数据: 数组<字节数组>, /// 开始区块 开始区块: u256, /// 结束区块 结束区块: u256, /// 赞成票数 赞成票数: u256, /// 反对票数 反对票数: u256, /// 弃权票数 弃权票数: u256, /// 是否已执行 已执行: 布尔, /// 是否已取消 已取消: 布尔 } /// 提案状态枚举 枚举 提案状态枚举 { /// 待投票 待投票, /// 投票中 投票中, /// 已通过 已通过, /// 已拒绝 已拒绝, /// 已执行 已执行, /// 已取消 已取消 } // ============================================================================ // 治理事件定义 // ============================================================================ /// 提案创建事件 事件 提案创建事件 { 提案ID: u256, 提案者: 地址, 标题: 字符串, 描述: 字符串, 开始区块: u256, 结束区块: u256 } /// 投票事件 事件 投票事件 { 投票者: 地址, 提案ID: u256, 支持: u8, 权重: u256 } /// 提案执行事件 事件 提案执行事件 { 提案ID: u256 } /// 提案取消事件 事件 提案取消事件 { 提案ID: u256 } // ============================================================================ // 治理基础实现 // ============================================================================ /// 治理基础实现 合约 治理基础 实现 治理 { // ========== 状态变量 ========== 私有 _治理代币: 地址; 私有 _提案数量: u256; 私有 _提案映射: 映射; 私有 _已投票映射: 映射>; 私有 _提案阈值: u256; // 创建提案所需的最小代币数量 私有 _投票阈值: u256; // 提案通过所需的最小赞成票比例(基点,10000=100%) 私有 _投票延迟: u256; // 提案创建后到投票开始的区块数 私有 _投票期限: u256; // 投票持续的区块数 // ========== 构造函数 ========== 构造函数( 治理代币: 地址, 提案阈值: u256, 投票阈值: u256, 投票延迟: u256, 投票期限: u256 ) { 要求(治理代币 != 地址::零地址(), "治理: 代币地址无效"); 要求(投票阈值 <= 10000, "治理: 投票阈值无效"); _治理代币 = 治理代币; _提案阈值 = 提案阈值; _投票阈值 = 投票阈值; _投票延迟 = 投票延迟; _投票期限 = 投票期限; _提案数量 = 0; } // ========== 查询函数实现 ========== 函数 治理代币() -> 地址 { 返回 _治理代币; } 函数 提案数量() -> u256 { 返回 _提案数量; } 函数 提案信息(提案ID: u256) -> 提案 { 要求(提案ID < _提案数量, "治理: 提案不存在"); 返回 _提案映射.获取(提案ID); } 函数 提案状态(提案ID: u256) -> 提案状态枚举 { 要求(提案ID < _提案数量, "治理: 提案不存在"); 让 提案 = 提案信息(提案ID); 如果 提案.已取消 { 返回 提案状态枚举::已取消; } 如果 提案.已执行 { 返回 提案状态枚举::已执行; } 让 当前区块 = 区块::号(); 如果 当前区块 < 提案.开始区块 { 返回 提案状态枚举::待投票; } 如果 当前区块 <= 提案.结束区块 { 返回 提案状态枚举::投票中; } // 投票已结束,检查是否通过 让 总票数 = 提案.赞成票数 + 提案.反对票数 + 提案.弃权票数; 如果 总票数 == 0 { 返回 提案状态枚举::已拒绝; } 让 赞成比例 = 提案.赞成票数 * 10000 / 总票数; 如果 赞成比例 >= _投票阈值 { 返回 提案状态枚举::已通过; } 否则 { 返回 提案状态枚举::已拒绝; } } 函数 投票权重(用户: 地址, 区块号: u256) -> u256 { // 简化实现:使用当前余额 // 实际应该使用快照机制 返回 ACC20(_治理代币).持有量(用户); } 函数 是否已投票(提案ID: u256, 用户: 地址) -> 布尔 { 要求(提案ID < _提案数量, "治理: 提案不存在"); 返回 _已投票映射.获取或默认(提案ID, 映射::新建()).获取或默认(用户, 假); } 函数 投票结果(提案ID: u256) -> (u256, u256, u256) { 要求(提案ID < _提案数量, "治理: 提案不存在"); 让 提案 = 提案信息(提案ID); 返回 (提案.赞成票数, 提案.反对票数, 提案.弃权票数); } 函数 提案阈值() -> u256 { 返回 _提案阈值; } 函数 投票阈值() -> u256 { 返回 _投票阈值; } 函数 投票延迟() -> u256 { 返回 _投票延迟; } 函数 投票期限() -> u256 { 返回 _投票期限; } // ========== 状态变更函数实现 ========== 函数 创建提案( 标题: 字符串, 描述: 字符串, 目标: 数组<地址>, 数值: 数组, 调用数据: 数组<字节数组> ) -> u256 { // 检查提案者权重 让 提案者权重 = 投票权重(消息::发送者(), 区块::号()); 要求(提案者权重 >= _提案阈值, "治理: 代币数量不足"); // 检查参数 要求(目标.长度() == 数值.长度() && 目标.长度() == 调用数据.长度(), "治理: 参数长度不匹配"); 要求(目标.长度() > 0, "治理: 目标为空"); // 创建提案 让 提案ID = _提案数量; 让 开始区块 = 区块::号() + _投票延迟; 让 结束区块 = 开始区块 + _投票期限; 让 新提案 = 提案 { ID: 提案ID, 提案者: 消息::发送者(), 标题: 标题, 描述: 描述, 目标: 目标, 数值: 数值, 调用数据: 调用数据, 开始区块: 开始区块, 结束区块: 结束区块, 赞成票数: 0, 反对票数: 0, 弃权票数: 0, 已执行: 假, 已取消: 假 }; _提案映射.插入(提案ID, 新提案); _提案数量 = _提案数量 + 1; 触发 提案创建事件 { 提案ID: 提案ID, 提案者: 消息::发送者(), 标题: 标题, 描述: 描述, 开始区块: 开始区块, 结束区块: 结束区块 }; 返回 提案ID; } 函数 投票(提案ID: u256, 支持: u8) { 要求(提案ID < _提案数量, "治理: 提案不存在"); 要求(支持 <= 2, "治理: 投票选项无效"); 要求(!是否已投票(提案ID, 消息::发送者()), "治理: 已投票"); 让 状态 = 提案状态(提案ID); 要求(状态 == 提案状态枚举::投票中, "治理: 不在投票期"); // 获取投票权重 让 提案 = 提案信息(提案ID); 让 权重 = 投票权重(消息::发送者(), 提案.开始区块); 要求(权重 > 0, "治理: 无投票权"); // 记录投票 让 可变 已投票映射 = _已投票映射.获取或默认(提案ID, 映射::新建()); 已投票映射.插入(消息::发送者(), 真); _已投票映射.插入(提案ID, 已投票映射); // 更新票数 让 可变 提案 = _提案映射.获取(提案ID); 如果 支持 == 0 { 提案.反对票数 = 提案.反对票数 + 权重; } 否则如果 支持 == 1 { 提案.赞成票数 = 提案.赞成票数 + 权重; } 否则 { 提案.弃权票数 = 提案.弃权票数 + 权重; } _提案映射.插入(提案ID, 提案); 触发 投票事件 { 投票者: 消息::发送者(), 提案ID: 提案ID, 支持: 支持, 权重: 权重 }; } 函数 执行提案(提案ID: u256) { 要求(提案ID < _提案数量, "治理: 提案不存在"); 让 状态 = 提案状态(提案ID); 要求(状态 == 提案状态枚举::已通过, "治理: 提案未通过"); 让 可变 提案 = _提案映射.获取(提案ID); 要求(!提案.已执行, "治理: 已执行"); // 执行提案 对于 i 在 0..提案.目标.长度() { 让 目标 = 提案.目标[i]; 让 数值 = 提案.数值[i]; 让 数据 = 提案.调用数据[i]; // 调用目标合约 让 (成功, _) = 目标.调用带值(数值, 数据); 要求(成功, "治理: 执行失败"); } 提案.已执行 = 真; _提案映射.插入(提案ID, 提案); 触发 提案执行事件 { 提案ID: 提案ID }; } 函数 取消提案(提案ID: u256) { 要求(提案ID < _提案数量, "治理: 提案不存在"); 让 可变 提案 = _提案映射.获取(提案ID); 要求(消息::发送者() == 提案.提案者, "治理: 非提案者"); 要求(!提案.已执行, "治理: 已执行"); 要求(!提案.已取消, "治理: 已取消"); 让 状态 = 提案状态(提案ID); 要求(状态 == 提案状态枚举::待投票 || 状态 == 提案状态枚举::投票中, "治理: 无法取消"); 提案.已取消 = 真; _提案映射.插入(提案ID, 提案); 触发 提案取消事件 { 提案ID: 提案ID }; } } // ============================================================================ // 时间锁接口 // ============================================================================ /// 时间锁接口 /// /// 定义延迟执行的标准操作 接口 时间锁 { /// 查询最小延迟 函数 最小延迟() -> u256; /// 查询最大延迟 函数 最大延迟() -> u256; /// 查询操作是否已排队 函数 是否已排队(操作ID: 哈希) -> 布尔; /// 排队操作 函数 排队( 目标: 地址, 数值: u256, 数据: 字节数组, 执行时间: u256 ) -> 哈希; /// 执行操作 函数 执行( 目标: 地址, 数值: u256, 数据: 字节数组 ); /// 取消操作 函数 取消(操作ID: 哈希); }