gcx/blockchain/genex-contracts/test/Governance.t.sol

173 lines
5.1 KiB
Solidity
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.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "forge-std/Test.sol";
import "../src/Governance.sol";
contract GovernanceTest is Test {
Governance governance;
address admin = address(1);
address member1 = address(10);
address member2 = address(11);
address member3 = address(12);
address member4 = address(13);
address member5 = address(14);
address target = address(99);
function setUp() public {
vm.startPrank(admin);
address[] memory members = new address[](5);
members[0] = member1;
members[1] = member2;
members[2] = member3;
members[3] = member4;
members[4] = member5;
governance = new Governance();
governance.initialize(members, admin);
vm.stopPrank();
}
function test_ProposeCreatesProposal() public {
vm.prank(member1);
uint256 proposalId = governance.propose(target, "0x1234", "Test proposal");
(
address pTarget,
uint256 executeAfter,
uint256 approvalCount,
bool executed,
bool emergency,
address proposer,
string memory description
) = governance.getProposal(proposalId);
assertEq(pTarget, target);
assertEq(approvalCount, 1); // 提案者自动审批
assertFalse(executed);
assertFalse(emergency);
assertEq(proposer, member1);
assertEq(description, "Test proposal");
assertEq(executeAfter, block.timestamp + 48 hours);
}
function test_EmergencyProposalShortTimelock() public {
vm.prank(member1);
uint256 proposalId = governance.proposeEmergency(target, "0x1234", "Emergency");
(, uint256 executeAfter,,, bool emergency,,) = governance.getProposal(proposalId);
assertTrue(emergency);
assertEq(executeAfter, block.timestamp + 4 hours);
}
function test_ApproveAndExecute() public {
// 提案
vm.prank(member1);
uint256 proposalId = governance.propose(target, "", "Test");
// member2 和 member3 审批 (共 3 个)
vm.prank(member2);
governance.approve(proposalId);
vm.prank(member3);
governance.approve(proposalId);
(,, uint256 approvalCount,,,,) = governance.getProposal(proposalId);
assertEq(approvalCount, 3);
// 快进 48h
vm.warp(block.timestamp + 48 hours);
// 构造一个可执行的target
// 由于 target 没有代码call 会成功
vm.prank(member1);
governance.execute(proposalId);
(,,, bool executed,,,) = governance.getProposal(proposalId);
assertTrue(executed);
}
function test_ExecuteNotEnoughApprovalsReverts() public {
vm.prank(member1);
uint256 proposalId = governance.propose(target, "", "Test");
// 只有 1 个审批(提案者自己)
vm.warp(block.timestamp + 48 hours);
vm.prank(member1);
vm.expectRevert("Governance: not enough approvals");
governance.execute(proposalId);
}
function test_ExecuteTimelockNotExpiredReverts() public {
vm.prank(member1);
uint256 proposalId = governance.propose(target, "", "Test");
vm.prank(member2);
governance.approve(proposalId);
vm.prank(member3);
governance.approve(proposalId);
// 不快进时间
vm.prank(member1);
vm.expectRevert("Governance: timelock not expired");
governance.execute(proposalId);
}
function test_DoubleApproveReverts() public {
vm.prank(member1);
uint256 proposalId = governance.propose(target, "", "Test");
vm.prank(member1);
vm.expectRevert("Governance: already approved");
governance.approve(proposalId);
}
function test_CancelByProposer() public {
vm.prank(member1);
uint256 proposalId = governance.propose(target, "", "Test");
vm.prank(member1);
governance.cancel(proposalId);
(,,, bool executed,,,) = governance.getProposal(proposalId);
assertTrue(executed); // 标记为已执行以阻止未来执行
}
function test_CancelByNonProposerReverts() public {
vm.prank(member1);
uint256 proposalId = governance.propose(target, "", "Test");
vm.prank(member2);
vm.expectRevert("Governance: not authorized");
governance.cancel(proposalId);
}
function test_HasApproved() public {
vm.prank(member1);
uint256 proposalId = governance.propose(target, "", "Test");
assertTrue(governance.hasApproved(proposalId, member1));
assertFalse(governance.hasApproved(proposalId, member2));
}
function test_OnlyMultisigCanPropose() public {
address random = address(888);
vm.prank(random);
vm.expectRevert();
governance.propose(target, "", "Test");
}
function test_RecordPreviousImplementation() public {
address proxy = address(100);
address impl = address(101);
vm.prank(member1);
governance.recordPreviousImplementation(proxy, impl);
assertEq(governance.previousImplementations(proxy), impl);
}
}