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