// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; /// @title Governance — 治理合约 /// @notice 3/5 多签 + 48h 时间锁 + 紧急 4h 通道 + 合约升级回滚 /// @dev 管理所有合约的升级、参数调整、紧急冻结 contract Governance is Initializable, AccessControlUpgradeable { bytes32 public constant MULTISIG_ROLE = keccak256("MULTISIG_ROLE"); uint256 public constant REQUIRED_SIGNATURES = 3; // 3/5 多签 uint256 public constant EMERGENCY_SIGNATURES = 4; // 紧急需 4/5 uint256 public constant TIMELOCK = 48 hours; // 标准时间锁 uint256 public constant EMERGENCY_TIMELOCK = 4 hours; // 紧急时间锁 uint256 public nextProposalId; struct Proposal { bytes callData; address target; uint256 executeAfter; uint256 approvalCount; bool executed; bool emergency; address proposer; string description; uint256 createdAt; } mapping(uint256 => Proposal) public proposals; mapping(uint256 => mapping(address => bool)) public approvals; // 合约升级回滚支持 mapping(address => address) public previousImplementations; // --- Events --- event ProposalCreated( uint256 indexed proposalId, address indexed proposer, address target, bool emergency, string description ); event ProposalApproved(uint256 indexed proposalId, address indexed approver, uint256 approvalCount); event ProposalExecuted(uint256 indexed proposalId, address indexed executor); event ProposalCancelled(uint256 indexed proposalId); event ContractRolledBack(address indexed proxy, address indexed previousImpl); event PreviousImplementationRecorded(address indexed proxy, address indexed impl); function initialize(address[] memory multisigMembers, address admin) external initializer { __AccessControl_init(); _grantRole(DEFAULT_ADMIN_ROLE, admin); for (uint256 i = 0; i < multisigMembers.length; i++) { _grantRole(MULTISIG_ROLE, multisigMembers[i]); } } // ======================== // 提案管理 // ======================== /// @notice 创建标准提案(48h 时间锁) function propose( address target, bytes calldata data, string calldata description ) external onlyRole(MULTISIG_ROLE) returns (uint256 proposalId) { proposalId = _createProposal(target, data, description, false); } /// @notice 创建紧急提案(4h 时间锁) function proposeEmergency( address target, bytes calldata data, string calldata description ) external onlyRole(MULTISIG_ROLE) returns (uint256 proposalId) { proposalId = _createProposal(target, data, description, true); } /// @notice 审批提案 function approve(uint256 proposalId) external onlyRole(MULTISIG_ROLE) { Proposal storage p = proposals[proposalId]; require(p.target != address(0), "Governance: proposal not found"); require(!p.executed, "Governance: already executed"); require(!approvals[proposalId][msg.sender], "Governance: already approved"); approvals[proposalId][msg.sender] = true; p.approvalCount++; emit ProposalApproved(proposalId, msg.sender, p.approvalCount); } /// @notice 执行提案 function execute(uint256 proposalId) external onlyRole(MULTISIG_ROLE) { Proposal storage p = proposals[proposalId]; require(p.target != address(0), "Governance: proposal not found"); require(!p.executed, "Governance: already executed"); // 签名数量检查 uint256 required = p.emergency ? EMERGENCY_SIGNATURES : REQUIRED_SIGNATURES; require(p.approvalCount >= required, "Governance: not enough approvals"); // 时间锁检查 require(block.timestamp >= p.executeAfter, "Governance: timelock not expired"); p.executed = true; (bool success,) = p.target.call(p.callData); require(success, "Governance: execution failed"); emit ProposalExecuted(proposalId, msg.sender); } /// @notice 取消提案(仅提案者或 Admin) function cancel(uint256 proposalId) external { Proposal storage p = proposals[proposalId]; require(p.target != address(0), "Governance: proposal not found"); require(!p.executed, "Governance: already executed"); require( p.proposer == msg.sender || hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "Governance: not authorized" ); // 标记为已执行来阻止未来执行 p.executed = true; emit ProposalCancelled(proposalId); } // ======================== // 合约升级回滚 // ======================== /// @notice 升级时记录前一版本 Implementation 地址 function recordPreviousImplementation(address proxy, address currentImpl) external onlyRole(MULTISIG_ROLE) { previousImplementations[proxy] = currentImpl; emit PreviousImplementationRecorded(proxy, currentImpl); } /// @notice 紧急回滚至上一版本(需 4/5 多签) /// @dev 通过紧急提案调用此方法 function rollback(address proxy) external onlyRole(MULTISIG_ROLE) { address prevImpl = previousImplementations[proxy]; require(prevImpl != address(0), "Governance: no previous version"); // 调用 proxy 的 upgradeTo (bool success,) = proxy.call( abi.encodeWithSignature("upgradeTo(address)", prevImpl) ); require(success, "Governance: rollback failed"); emit ContractRolledBack(proxy, prevImpl); } // ======================== // 查询 // ======================== /// @notice 查询提案详情 function getProposal(uint256 proposalId) external view returns ( address target, uint256 executeAfter, uint256 approvalCount, bool executed, bool emergency, address proposer, string memory description ) { Proposal storage p = proposals[proposalId]; return (p.target, p.executeAfter, p.approvalCount, p.executed, p.emergency, p.proposer, p.description); } /// @notice 查询某地址是否已审批 function hasApproved(uint256 proposalId, address member) external view returns (bool) { return approvals[proposalId][member]; } // ======================== // Internal // ======================== function _createProposal( address target, bytes calldata data, string calldata description, bool emergency ) internal returns (uint256 proposalId) { require(target != address(0), "Governance: zero target"); proposalId = nextProposalId++; uint256 timelock = emergency ? EMERGENCY_TIMELOCK : TIMELOCK; proposals[proposalId] = Proposal({ callData: data, target: target, executeAfter: block.timestamp + timelock, approvalCount: 1, // 提案者自动审批 executed: false, emergency: emergency, proposer: msg.sender, description: description, createdAt: block.timestamp }); approvals[proposalId][msg.sender] = true; emit ProposalCreated(proposalId, msg.sender, target, emergency, description); } }