Skip to content

Commit 78ba58e

Browse files
committed
test done
1 parent ed6d156 commit 78ba58e

File tree

5 files changed

+244
-0
lines changed

5 files changed

+244
-0
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// SPDX-License-Identifier: MIT
2+
// Compatible with OpenZeppelin Contracts ^5.5.0
3+
pragma solidity ^0.8.33;
4+
5+
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
6+
7+
contract Box is Ownable {
8+
uint256 private s_number;
9+
10+
event NumberChanged(uint256 number);
11+
12+
constructor() Ownable(msg.sender) {}
13+
14+
function store(uint256 newNumber) public onlyOwner {
15+
s_number = newNumber;
16+
emit NumberChanged(newNumber);
17+
}
18+
19+
function getNumber() public view returns (uint256) {
20+
return s_number;
21+
}
22+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// SPDX-License-Identifier: MIT
2+
// Compatible with OpenZeppelin Contracts ^5.5.0
3+
pragma solidity ^0.8.27;
4+
5+
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
6+
import {ERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
7+
import {ERC20Votes} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol";
8+
import {Nonces} from "@openzeppelin/contracts/utils/Nonces.sol";
9+
10+
contract GovToken is ERC20, ERC20Permit, ERC20Votes {
11+
constructor() ERC20("GovToken", "GTK") ERC20Permit("GovToken") {}
12+
13+
function mint(address to, uint256 amount) public {
14+
_mint(to, amount);
15+
}
16+
17+
// The following functions are overrides required by Solidity.
18+
19+
function _update(address from, address to, uint256 value) internal override(ERC20, ERC20Votes) {
20+
super._update(from, to, value);
21+
}
22+
23+
function nonces(address owner) public view override(ERC20Permit, Nonces) returns (uint256) {
24+
return super.nonces(owner);
25+
}
26+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// SPDX-License-Identifier: MIT
2+
// Compatible with OpenZeppelin Contracts ^5.5.0
3+
pragma solidity ^0.8.27;
4+
5+
import {Governor} from "@openzeppelin/contracts/governance/Governor.sol";
6+
import {GovernorCountingSimple} from "@openzeppelin/contracts/governance/extensions/GovernorCountingSimple.sol";
7+
import {GovernorSettings} from "@openzeppelin/contracts/governance/extensions/GovernorSettings.sol";
8+
import {GovernorTimelockControl} from "@openzeppelin/contracts/governance/extensions/GovernorTimelockControl.sol";
9+
import {GovernorVotes} from "@openzeppelin/contracts/governance/extensions/GovernorVotes.sol";
10+
import {
11+
GovernorVotesQuorumFraction
12+
} from "@openzeppelin/contracts/governance/extensions/GovernorVotesQuorumFraction.sol";
13+
import {IVotes} from "@openzeppelin/contracts/governance/utils/IVotes.sol";
14+
import {TimelockController} from "@openzeppelin/contracts/governance/TimelockController.sol";
15+
16+
contract MyGovernor is
17+
Governor,
18+
GovernorSettings,
19+
GovernorCountingSimple,
20+
GovernorVotes,
21+
GovernorVotesQuorumFraction,
22+
GovernorTimelockControl
23+
{
24+
constructor(IVotes _token, TimelockController _timelock)
25+
Governor("MyGovernor")
26+
GovernorSettings(
27+
7200,
28+
/* 1 day */
29+
50400,
30+
/* 1 week */
31+
0
32+
)
33+
GovernorVotes(_token)
34+
GovernorVotesQuorumFraction(4)
35+
GovernorTimelockControl(_timelock)
36+
{}
37+
38+
// The following functions are overrides required by Solidity.
39+
40+
function state(uint256 proposalId) public view override(Governor, GovernorTimelockControl) returns (ProposalState) {
41+
return super.state(proposalId);
42+
}
43+
44+
function proposalNeedsQueuing(uint256 proposalId)
45+
public
46+
view
47+
override(Governor, GovernorTimelockControl)
48+
returns (bool)
49+
{
50+
return super.proposalNeedsQueuing(proposalId);
51+
}
52+
53+
function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) {
54+
return super.proposalThreshold();
55+
}
56+
57+
function _queueOperations(
58+
uint256 proposalId,
59+
address[] memory targets,
60+
uint256[] memory values,
61+
bytes[] memory calldatas,
62+
bytes32 descriptionHash
63+
) internal override(Governor, GovernorTimelockControl) returns (uint48) {
64+
return super._queueOperations(proposalId, targets, values, calldatas, descriptionHash);
65+
}
66+
67+
function _executeOperations(
68+
uint256 proposalId,
69+
address[] memory targets,
70+
uint256[] memory values,
71+
bytes[] memory calldatas,
72+
bytes32 descriptionHash
73+
) internal override(Governor, GovernorTimelockControl) {
74+
super._executeOperations(proposalId, targets, values, calldatas, descriptionHash);
75+
}
76+
77+
function _cancel(
78+
address[] memory targets,
79+
uint256[] memory values,
80+
bytes[] memory calldatas,
81+
bytes32 descriptionHash
82+
) internal override(Governor, GovernorTimelockControl) returns (uint256) {
83+
return super._cancel(targets, values, calldatas, descriptionHash);
84+
}
85+
86+
function _executor() internal view override(Governor, GovernorTimelockControl) returns (address) {
87+
return super._executor();
88+
}
89+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// SPDX-License-Identifier: MIT
2+
// Compatible with OpenZeppelin Contracts ^5.5.0
3+
pragma solidity ^0.8.33;
4+
5+
import {TimelockController} from "@openzeppelin/contracts/governance/TimelockController.sol";
6+
7+
contract Timelock is TimelockController {
8+
constructor(uint256 minDelay, address[] memory proposers, address[] memory executors)
9+
TimelockController(minDelay, proposers, executors, msg.sender)
10+
{}
11+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// SPDX-License-Identifier: MIT
2+
// Compatible with OpenZeppelin Contracts ^5.5.0
3+
pragma solidity ^0.8.33;
4+
5+
import {Test} from "@forge-std/Test.sol";
6+
import {MyGovernor} from "../src/Governor.sol";
7+
import {GovToken} from "../src/GovToken.sol";
8+
import {Timelock} from "../src/Timelock.sol";
9+
import {Box} from "../src/Box.sol";
10+
import {console} from "forge-std/console.sol";
11+
12+
contract GovernorTest is Test {
13+
MyGovernor public governor;
14+
GovToken public govToken;
15+
Timelock public timelock;
16+
Box public box;
17+
18+
address public user = makeAddr("user");
19+
uint256 public constant INITIAL_SUPPLY = 100 ether;
20+
21+
address[] public proposers = [user];
22+
address[] public executors = [user];
23+
24+
uint256 public constant MIN_DELAY = 3600; // 1 hour
25+
uint256 public constant QUORUM_PERCENTAGE = 4; // 4%
26+
uint256 public constant VOTING_DELAY = 7200; // 1 day in blocks
27+
uint256 public constant VOTING_PERIOD = 50400; // 1 week in blocks
28+
29+
function setUp() public {
30+
govToken = new GovToken();
31+
govToken.mint(user, INITIAL_SUPPLY);
32+
33+
vm.startPrank(user);
34+
govToken.delegate(user);
35+
timelock = new Timelock(MIN_DELAY, proposers, executors);
36+
37+
governor = new MyGovernor(govToken, timelock);
38+
39+
bytes32 proposerRole = timelock.PROPOSER_ROLE();
40+
bytes32 executorRole = timelock.EXECUTOR_ROLE();
41+
bytes32 adminRole = timelock.DEFAULT_ADMIN_ROLE();
42+
43+
timelock.grantRole(proposerRole, address(governor));
44+
timelock.grantRole(executorRole, address(governor));
45+
timelock.revokeRole(adminRole, address(this));
46+
vm.stopPrank();
47+
48+
box = new Box();
49+
box.transferOwnership(address(timelock));
50+
51+
}
52+
53+
function testCantUpdateBoxWithoutGovernance() public {
54+
vm.expectRevert();
55+
box.store(1);
56+
}
57+
58+
function testCanUpdateBoxWithGovernance() public {
59+
uint256 valueToStore = 12423;
60+
string memory description = "Store 12423 in the box";
61+
bytes memory encodedParams = abi.encodeWithSignature("store(uint256)", valueToStore);
62+
63+
address[] memory targets = new address[](1);
64+
uint256[] memory values = new uint256[](1);
65+
bytes[] memory calldatas = new bytes[](1);
66+
67+
values[0] = 0;
68+
calldatas[0] = encodedParams;
69+
targets[0] = address(box);
70+
71+
uint256 proposalId = governor.propose(targets, values, calldatas, description);
72+
console.log("Proposal State:", uint256(governor.state(proposalId)));
73+
74+
vm.warp(block.timestamp + VOTING_DELAY + 1);
75+
vm.roll(block.number + VOTING_DELAY + 1);
76+
77+
console.log("Proposal State:", uint256(governor.state(proposalId)));
78+
79+
string memory reason = "I like this proposal";
80+
uint8 voteWay = 1; // 1 = For
81+
vm.prank(user);
82+
governor.castVoteWithReason(proposalId, voteWay, reason);
83+
84+
vm.warp(block.timestamp + VOTING_PERIOD + 1);
85+
vm.roll(block.number + VOTING_PERIOD + 1);
86+
87+
bytes32 descriptionHash = keccak256(abi.encodePacked(description));
88+
governor.queue(targets, values, calldatas, descriptionHash);
89+
90+
vm.warp(block.timestamp + MIN_DELAY + 1);
91+
vm.roll(block.number + 1);
92+
93+
governor.execute(targets, values, calldatas, descriptionHash);
94+
assertEq(box.getNumber(), valueToStore);
95+
}
96+
}

0 commit comments

Comments
 (0)