NAC_Blockchain/charter-std-zh/governance/governance.ch

505 lines
14 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

///! 治理模块: 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>,
调用数据: 数组<字节数组>
) -> u256;
/// 投票
///
/// # 参数
/// - `提案ID`: 提案唯一标识符
/// - `支持`: 投票选项0=反对, 1=赞成, 2=弃权)
///
/// # 事件
/// - `投票事件`
函数 投票(提案ID: u256, 支持: u8);
/// 执行提案
///
/// # 参数
/// - `提案ID`: 提案唯一标识符
///
/// # 事件
/// - `提案执行事件`
函数 执行提案(提案ID: u256);
/// 取消提案
///
/// # 参数
/// - `提案ID`: 提案唯一标识符
///
/// # 事件
/// - `提案取消事件`
函数 取消提案(提案ID: u256);
}
// ============================================================================
// 数据结构定义
// ============================================================================
/// 提案结构
结构 提案 {
/// 提案ID
ID: u256,
/// 提案者
提案者: 地址,
/// 提案标题
标题: 字符串,
/// 提案描述
描述: 字符串,
/// 执行目标
目标: 数组<地址>,
/// 执行数值
数值: 数组<u256>,
/// 执行调用数据
调用数据: 数组<字节数组>,
/// 开始区块
开始区块: u256,
/// 结束区块
结束区块: u256,
/// 赞成票数
赞成票数: u256,
/// 反对票数
反对票数: u256,
/// 弃权票数
弃权票数: u256,
/// 是否已执行
已执行: 布尔,
/// 是否已取消
已取消: 布尔
}
/// 提案状态枚举
枚举 提案状态枚举 {
/// 待投票
待投票,
/// 投票中
投票中,
/// 已通过
已通过,
/// 已拒绝
已拒绝,
/// 已执行
已执行,
/// 已取消
已取消
}
// ============================================================================
// 治理事件定义
// ============================================================================
/// 提案创建事件
事件 提案创建事件 {
提案ID: u256,
提案者: 地址,
标题: 字符串,
描述: 字符串,
开始区块: u256,
结束区块: u256
}
/// 投票事件
事件 投票事件 {
投票者: 地址,
提案ID: u256,
支持: u8,
权重: u256
}
/// 提案执行事件
事件 提案执行事件 {
提案ID: u256
}
/// 提案取消事件
事件 提案取消事件 {
提案ID: u256
}
// ============================================================================
// 治理基础实现
// ============================================================================
/// 治理基础实现
合约 治理基础 实现 治理 {
// ========== 状态变量 ==========
私有 _治理代币: 地址;
私有 _提案数量: u256;
私有 _提案映射: 映射<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>,
调用数据: 数组<字节数组>
) -> 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: 哈希);
}