NAC_Blockchain/charter-std/governance/proposal.ch

704 lines
20 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.

///! # 提案管理系统
///!
///! Proposal Management System
///! 提供提案创建、执行和历史管理功能
///!
///! **版本**: v1.0
///! **模块**: charter-std/governance/proposal.ch
use utils::math::{safe_add, safe_sub};
use utils::crypto::sha3_384_hash;
// ============================================================================
// 提案枚举
// ============================================================================
/// 提案类型
pub enum ProposalType {
/// 参数修改
ParameterChange,
/// 资金支出
Treasury,
/// 合约升级
Upgrade,
/// 文本提案
Text,
/// 自定义
Custom
}
/// 提案状态
pub enum ProposalStatus {
/// 草稿
Draft,
/// 待投票
Pending,
/// 投票中
Active,
/// 已通过
Passed,
/// 未通过
Rejected,
/// 已执行
Executed,
/// 已取消
Cancelled,
/// 已过期
Expired
}
// ============================================================================
// 提案结构
// ============================================================================
/// 提案
struct Proposal {
/// 提案ID
proposal_id: Hash,
/// 提案类型
proposal_type: ProposalType,
/// 标题
title: String,
/// 描述
description: String,
/// 提案者
proposer: Address,
/// 创建时间
created_at: Timestamp,
/// 投票开始时间
voting_start: Timestamp,
/// 投票结束时间
voting_end: Timestamp,
/// 执行延迟(秒)
execution_delay: Duration,
/// 最早执行时间
earliest_execution: Timestamp,
/// 执行截止时间
execution_deadline: Timestamp,
/// 提案状态
status: ProposalStatus,
/// 投票ID
vote_id: Option<Hash>,
/// 执行交易哈希
execution_tx: Option<Hash>,
/// 执行时间
executed_at: Option<Timestamp>,
/// 取消原因
cancellation_reason: Option<String>
}
/// 提案操作
struct ProposalAction {
/// 目标合约
target: Address,
/// 函数签名
function_sig: String,
/// 调用数据
call_data: Bytes,
/// 转账金额
value: u256,
/// 描述
description: String
}
/// 提案元数据
struct ProposalMetadata {
/// 提案ID
proposal_id: Hash,
/// 标签
tags: Vec<String>,
/// 相关链接
links: Vec<String>,
/// 讨论链接
discussion_url: Option<String>,
/// 文档哈希
document_hash: Option<Hash>
}
// ============================================================================
// 提案事件
// ============================================================================
/// 提案创建事件
event ProposalCreated {
proposal_id: Hash,
proposer: Address,
title: String,
proposal_type: ProposalType,
timestamp: Timestamp
}
/// 提案提交事件
event ProposalSubmitted {
proposal_id: Hash,
vote_id: Hash,
voting_start: Timestamp,
voting_end: Timestamp,
timestamp: Timestamp
}
/// 提案通过事件
event ProposalPassed {
proposal_id: Hash,
vote_id: Hash,
timestamp: Timestamp
}
/// 提案拒绝事件
event ProposalRejected {
proposal_id: Hash,
vote_id: Hash,
timestamp: Timestamp
}
/// 提案执行事件
event ProposalExecuted {
proposal_id: Hash,
executor: Address,
execution_tx: Hash,
timestamp: Timestamp
}
/// 提案取消事件
event ProposalCancelled {
proposal_id: Hash,
canceller: Address,
reason: String,
timestamp: Timestamp
}
// ============================================================================
// 提案管理系统
// ============================================================================
/// 提案管理系统
certificate ProposalManagement {
/// 提案 (proposal_id => proposal)
let _proposals: Map<Hash, Proposal>;
/// 提案操作 (proposal_id => actions)
let _proposal_actions: Map<Hash, Vec<ProposalAction>>;
/// 提案元数据 (proposal_id => metadata)
let _proposal_metadata: Map<Hash, ProposalMetadata>;
/// 提案者提案列表 (proposer => proposal_ids)
let _proposer_proposals: Map<Address, Vec<Hash>>;
/// 投票系统地址
let _voting_system: Address;
/// 治理代币地址
let _governance_token: Address;
/// 时间锁地址
let _timelock: Address;
/// 管理员地址
let _admin: Address;
/// 提案门槛(需要的代币数量)
let _proposal_threshold: u256;
/// 默认投票期限(秒)
let _default_voting_period: Duration;
/// 默认执行延迟(秒)
let _default_execution_delay: Duration;
/// 执行窗口期(秒)
let _execution_window: Duration;
// ========== 构造函数 ==========
constructor(
voting_system: Address,
governance_token: Address,
timelock: Address,
proposal_threshold: u256,
voting_period: Duration,
execution_delay: Duration,
execution_window: Duration
) {
require(!voting_system.is_zero(), "Invalid voting system");
require(!governance_token.is_zero(), "Invalid governance token");
require(!timelock.is_zero(), "Invalid timelock");
require(proposal_threshold > 0, "Threshold must be positive");
require(voting_period > 0, "Voting period must be positive");
require(execution_delay > 0, "Execution delay must be positive");
require(execution_window > 0, "Execution window must be positive");
self._voting_system = voting_system;
self._governance_token = governance_token;
self._timelock = timelock;
self._admin = msg.sender;
self._proposal_threshold = proposal_threshold;
self._default_voting_period = voting_period;
self._default_execution_delay = execution_delay;
self._execution_window = execution_window;
}
// ========== 提案创建 ==========
/// 创建提案
///
/// # 参数
/// - `proposal_type`: 提案类型
/// - `title`: 标题
/// - `description`: 描述
/// - `actions`: 操作列表
///
/// # 返回
/// - `Hash`: 提案ID
pub fn create_proposal(
proposal_type: ProposalType,
title: String,
description: String,
actions: Vec<ProposalAction>
) -> Hash {
require(!title.is_empty(), "Title required");
require(!description.is_empty(), "Description required");
// 检查提案门槛(实际需要查询治理代币余额)
let proposer_balance = self._get_token_balance(msg.sender);
require(
proposer_balance >= self._proposal_threshold,
"Insufficient tokens to propose"
);
// 生成提案ID
let proposal_id = self._generate_proposal_id(msg.sender, title.clone());
let proposal = Proposal {
proposal_id: proposal_id,
proposal_type: proposal_type,
title: title.clone(),
description: description,
proposer: msg.sender,
created_at: block.timestamp,
voting_start: 0,
voting_end: 0,
execution_delay: self._default_execution_delay,
earliest_execution: 0,
execution_deadline: 0,
status: ProposalStatus::Draft,
vote_id: None,
execution_tx: None,
executed_at: None,
cancellation_reason: None
};
self._proposals[proposal_id] = proposal;
self._proposal_actions[proposal_id] = actions;
// 添加到提案者列表
if !self._proposer_proposals.contains_key(msg.sender) {
self._proposer_proposals[msg.sender] = Vec::new();
}
self._proposer_proposals[msg.sender].push(proposal_id);
emit ProposalCreated {
proposal_id: proposal_id,
proposer: msg.sender,
title: title,
proposal_type: proposal_type,
timestamp: block.timestamp
};
return proposal_id;
}
/// 提交提案进行投票
///
/// # 参数
/// - `proposal_id`: 提案ID
/// - `voting_period`: 投票期限0表示使用默认值
///
/// # 返回
/// - `Hash`: 投票ID
pub fn submit_proposal(
proposal_id: Hash,
voting_period: Duration
) -> Hash {
require(self._proposals.contains_key(proposal_id), "Proposal not found");
let mut proposal = self._proposals[proposal_id];
require(proposal.proposer == msg.sender, "Not the proposer");
require(proposal.status == ProposalStatus::Draft, "Not in draft status");
let period = if voting_period == 0 {
self._default_voting_period
} else {
voting_period
};
let voting_start = block.timestamp;
let voting_end = block.timestamp + period;
// 创建投票(实际需要调用投票系统合约)
let vote_id = self._create_vote(proposal_id, proposal.title.clone(), period);
proposal.voting_start = voting_start;
proposal.voting_end = voting_end;
proposal.status = ProposalStatus::Active;
proposal.vote_id = Some(vote_id);
// 计算执行时间窗口
proposal.earliest_execution = voting_end + proposal.execution_delay;
proposal.execution_deadline = proposal.earliest_execution + self._execution_window;
self._proposals[proposal_id] = proposal;
emit ProposalSubmitted {
proposal_id: proposal_id,
vote_id: vote_id,
voting_start: voting_start,
voting_end: voting_end,
timestamp: block.timestamp
};
return vote_id;
}
// ========== 提案执行 ==========
/// 执行提案
///
/// # 参数
/// - `proposal_id`: 提案ID
///
/// # 返回
/// - `bool`: 是否成功
pub fn execute_proposal(proposal_id: Hash) -> bool {
require(self._proposals.contains_key(proposal_id), "Proposal not found");
let mut proposal = self._proposals[proposal_id];
require(proposal.status == ProposalStatus::Passed, "Proposal not passed");
require(
block.timestamp >= proposal.earliest_execution,
"Execution delay not met"
);
require(
block.timestamp <= proposal.execution_deadline,
"Execution deadline passed"
);
// 获取提案操作
let actions = self._proposal_actions.get(proposal_id).unwrap_or(Vec::new());
// 执行所有操作(实际需要通过时间锁执行)
for action in actions {
self._execute_action(action);
}
// 生成执行交易哈希
let execution_tx = tx.hash;
proposal.status = ProposalStatus::Executed;
proposal.execution_tx = Some(execution_tx);
proposal.executed_at = Some(block.timestamp);
self._proposals[proposal_id] = proposal;
emit ProposalExecuted {
proposal_id: proposal_id,
executor: msg.sender,
execution_tx: execution_tx,
timestamp: block.timestamp
};
return true;
}
/// 更新提案状态(根据投票结果)
///
/// # 参数
/// - `proposal_id`: 提案ID
///
/// # 返回
/// - `bool`: 是否成功
pub fn update_proposal_status(proposal_id: Hash) -> bool {
require(self._proposals.contains_key(proposal_id), "Proposal not found");
let mut proposal = self._proposals[proposal_id];
require(proposal.status == ProposalStatus::Active, "Proposal not active");
require(block.timestamp >= proposal.voting_end, "Voting not ended");
// 获取投票结果(实际需要调用投票系统合约)
let vote_result = self._get_vote_result(proposal.vote_id.unwrap());
match vote_result {
VoteResult::Passed => {
proposal.status = ProposalStatus::Passed;
emit ProposalPassed {
proposal_id: proposal_id,
vote_id: proposal.vote_id.unwrap(),
timestamp: block.timestamp
};
},
_ => {
proposal.status = ProposalStatus::Rejected;
emit ProposalRejected {
proposal_id: proposal_id,
vote_id: proposal.vote_id.unwrap(),
timestamp: block.timestamp
};
}
}
self._proposals[proposal_id] = proposal;
return true;
}
/// 取消提案
///
/// # 参数
/// - `proposal_id`: 提案ID
/// - `reason`: 取消原因
///
/// # 返回
/// - `bool`: 是否成功
pub fn cancel_proposal(proposal_id: Hash, reason: String) -> bool {
require(self._proposals.contains_key(proposal_id), "Proposal not found");
let mut proposal = self._proposals[proposal_id];
require(
msg.sender == proposal.proposer || msg.sender == self._admin,
"Not authorized"
);
require(
proposal.status == ProposalStatus::Draft ||
proposal.status == ProposalStatus::Pending ||
proposal.status == ProposalStatus::Active,
"Cannot cancel"
);
proposal.status = ProposalStatus::Cancelled;
proposal.cancellation_reason = Some(reason.clone());
self._proposals[proposal_id] = proposal;
emit ProposalCancelled {
proposal_id: proposal_id,
canceller: msg.sender,
reason: reason,
timestamp: block.timestamp
};
return true;
}
// ========== 元数据管理 ==========
/// 设置提案元数据
///
/// # 参数
/// - `proposal_id`: 提案ID
/// - `tags`: 标签
/// - `links`: 相关链接
/// - `discussion_url`: 讨论链接
/// - `document_hash`: 文档哈希
///
/// # 返回
/// - `bool`: 是否成功
pub fn set_proposal_metadata(
proposal_id: Hash,
tags: Vec<String>,
links: Vec<String>,
discussion_url: Option<String>,
document_hash: Option<Hash>
) -> bool {
require(self._proposals.contains_key(proposal_id), "Proposal not found");
let proposal = self._proposals[proposal_id];
require(proposal.proposer == msg.sender, "Not the proposer");
let metadata = ProposalMetadata {
proposal_id: proposal_id,
tags: tags,
links: links,
discussion_url: discussion_url,
document_hash: document_hash
};
self._proposal_metadata[proposal_id] = metadata;
return true;
}
/// 获取提案元数据
///
/// # 参数
/// - `proposal_id`: 提案ID
///
/// # 返回
/// - `Option<ProposalMetadata>`: 元数据
pub fn get_proposal_metadata(proposal_id: Hash) -> Option<ProposalMetadata> {
return self._proposal_metadata.get(proposal_id);
}
// ========== 查询函数 ==========
/// 获取提案
///
/// # 参数
/// - `proposal_id`: 提案ID
///
/// # 返回
/// - `Proposal`: 提案信息
pub fn get_proposal(proposal_id: Hash) -> Proposal {
require(self._proposals.contains_key(proposal_id), "Proposal not found");
return self._proposals[proposal_id];
}
/// 获取提案操作
///
/// # 参数
/// - `proposal_id`: 提案ID
///
/// # 返回
/// - `Vec<ProposalAction>`: 操作列表
pub fn get_proposal_actions(proposal_id: Hash) -> Vec<ProposalAction> {
return self._proposal_actions.get(proposal_id).unwrap_or(Vec::new());
}
/// 获取提案者的提案列表
///
/// # 参数
/// - `proposer`: 提案者地址
///
/// # 返回
/// - `Vec<Hash>`: 提案ID列表
pub fn get_proposer_proposals(proposer: Address) -> Vec<Hash> {
return self._proposer_proposals.get(proposer).unwrap_or(Vec::new());
}
/// 检查提案是否可执行
///
/// # 参数
/// - `proposal_id`: 提案ID
///
/// # 返回
/// - `bool`: 是否可执行
pub fn is_executable(proposal_id: Hash) -> bool {
if !self._proposals.contains_key(proposal_id) {
return false;
}
let proposal = self._proposals[proposal_id];
return proposal.status == ProposalStatus::Passed &&
block.timestamp >= proposal.earliest_execution &&
block.timestamp <= proposal.execution_deadline;
}
// ========== 内部函数 ==========
/// 生成提案ID
fn _generate_proposal_id(proposer: Address, title: String) -> Hash {
let mut data = Bytes::new();
data.extend(proposer.as_bytes());
data.extend(title.as_bytes());
data.extend(block.timestamp.to_bytes());
data.extend(tx.hash.as_bytes());
return sha3_384_hash(data);
}
/// 获取代币余额(简化,实际需要调用代币合约)
fn _get_token_balance(account: Address) -> u256 {
return 1000; // 简化
}
/// 创建投票(简化,实际需要调用投票系统合约)
fn _create_vote(proposal_id: Hash, title: String, period: Duration) -> Hash {
// 实际需要调用投票系统的create_vote函数
return sha3_384_hash(proposal_id.as_bytes());
}
/// 获取投票结果(简化,实际需要调用投票系统合约)
fn _get_vote_result(vote_id: Hash) -> VoteResult {
// 实际需要调用投票系统的get_vote_result函数
return VoteResult::Passed;
}
/// 执行操作(简化,实际需要通过时间锁执行)
fn _execute_action(action: ProposalAction) {
// 实际需要通过时间锁合约执行
// timelock.execute(action.target, action.function_sig, action.call_data, action.value)
}
// ========== 管理函数 ==========
/// 设置提案门槛
pub fn set_proposal_threshold(threshold: u256) -> bool {
require(msg.sender == self._admin, "Only admin");
require(threshold > 0, "Threshold must be positive");
self._proposal_threshold = threshold;
return true;
}
/// 设置默认投票期限
pub fn set_default_voting_period(period: Duration) -> bool {
require(msg.sender == self._admin, "Only admin");
require(period > 0, "Period must be positive");
self._default_voting_period = period;
return true;
}
/// 设置默认执行延迟
pub fn set_default_execution_delay(delay: Duration) -> bool {
require(msg.sender == self._admin, "Only admin");
require(delay > 0, "Delay must be positive");
self._default_execution_delay = delay;
return true;
}
}
// ============================================================================
// 投票结果枚举从voting.ch引用
// ============================================================================
enum VoteResult {
Undecided,
Passed,
Failed,
QuorumNotReached
}