///! # 提案管理系统 ///! ///! 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, /// 执行交易哈希 execution_tx: Option, /// 执行时间 executed_at: Option, /// 取消原因 cancellation_reason: Option } /// 提案操作 struct ProposalAction { /// 目标合约 target: Address, /// 函数签名 function_sig: String, /// 调用数据 call_data: Bytes, /// 转账金额 value: u256, /// 描述 description: String } /// 提案元数据 struct ProposalMetadata { /// 提案ID proposal_id: Hash, /// 标签 tags: Vec, /// 相关链接 links: Vec, /// 讨论链接 discussion_url: Option, /// 文档哈希 document_hash: Option } // ============================================================================ // 提案事件 // ============================================================================ /// 提案创建事件 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; /// 提案操作 (proposal_id => actions) let _proposal_actions: Map>; /// 提案元数据 (proposal_id => metadata) let _proposal_metadata: Map; /// 提案者提案列表 (proposer => proposal_ids) let _proposer_proposals: Map>; /// 投票系统地址 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 ) -> 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, links: Vec, discussion_url: Option, document_hash: Option ) -> 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`: 元数据 pub fn get_proposal_metadata(proposal_id: Hash) -> Option { 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`: 操作列表 pub fn get_proposal_actions(proposal_id: Hash) -> Vec { return self._proposal_actions.get(proposal_id).unwrap_or(Vec::new()); } /// 获取提案者的提案列表 /// /// # 参数 /// - `proposer`: 提案者地址 /// /// # 返回 /// - `Vec`: 提案ID列表 pub fn get_proposer_proposals(proposer: Address) -> Vec { 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 }