Skip to content

Commit e9bf9cf

Browse files
committed
test: governor unit tests
1 parent 8e69a43 commit e9bf9cf

File tree

13 files changed

+1306
-14
lines changed

13 files changed

+1306
-14
lines changed

contracts/mocks/generic/RegistryGeneric.sol

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ contract RegistryGeneric is IRegistry {
1717
revert("Unsupported");
1818
}
1919

20-
function getSystemPause() external override virtual pure returns (SystemPause memory) {
20+
function getSystemPause() external override virtual view returns (SystemPause memory) {
2121
revert("Unsupported");
2222
}
2323

@@ -45,35 +45,35 @@ contract RegistryGeneric is IRegistry {
4545
revert("Unsupported");
4646
}
4747

48-
function getLastMemberId() external pure returns (uint) {
48+
function getLastMemberId() external virtual view returns (uint) {
4949
revert("Unsupported");
5050
}
5151

52-
function getMemberAddress(uint) external pure returns (address) {
52+
function getMemberAddress(uint) external virtual view returns (address) {
5353
revert("Unsupported");
5454
}
5555

56-
function getMemberAddressBySeat(uint) external pure returns (address) {
56+
function getMemberAddressBySeat(uint) external virtual view returns (address) {
5757
revert("Unsupported");
5858
}
5959

60-
function isProxyContract(uint) external pure returns (bool) {
60+
function isProxyContract(uint) external virtual view returns (bool) {
6161
revert("Unsupported");
6262
}
6363

64-
function isAdvisoryBoardMember(address) external pure returns (bool) {
64+
function isAdvisoryBoardMember(address) external virtual view returns (bool) {
6565
revert("Unsupported");
6666
}
6767

68-
function getAdvisoryBoardSeat(address) external pure returns (uint) {
68+
function getAdvisoryBoardSeat(address) external virtual view returns (uint) {
6969
revert("Unsupported");
7070
}
7171

7272
function getAdvisoryBoardSeat(uint, uint) external pure {
7373
revert("Unsupported");
7474
}
7575

76-
function swapAdvisoryBoardMember(uint, uint) external pure {
76+
function swapAdvisoryBoardMember(uint, uint) external virtual {
7777
revert("Unsupported");
7878
}
7979

@@ -125,7 +125,7 @@ contract RegistryGeneric is IRegistry {
125125
revert("Unsupported");
126126
}
127127

128-
function getContracts(uint[] memory) external pure returns (Contract[] memory) {
128+
function getContracts(uint[] memory) external virtual view returns (Contract[] memory) {
129129
revert("Unsupported");
130130
}
131131

contracts/mocks/generic/TokenControllerGeneric.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ contract TokenControllerGeneric is ITokenController {
3636
revert("mint unsupported");
3737
}
3838

39-
function lockForMemberVote(address, uint) external pure {
39+
function lockForMemberVote(address, uint) external virtual {
4040
revert("lockForMemberVote unsupported");
4141
}
4242

@@ -52,7 +52,7 @@ contract TokenControllerGeneric is ITokenController {
5252
revert("totalSupply unsupported");
5353
}
5454

55-
function totalBalanceOf(address) external pure returns (uint) {
55+
function totalBalanceOf(address) external view virtual returns (uint) {
5656
revert("totalBalanceOf unsupported");
5757
}
5858

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// SPDX-License-Identifier: GPL-3.0-only
2+
3+
pragma solidity ^0.8.18;
4+
5+
import "../../generic/RegistryGeneric.sol";
6+
7+
contract GVMockRegistry is RegistryGeneric {
8+
// contracts
9+
mapping(uint index => Contract) internal contracts;
10+
mapping(address contractAddress => uint index) internal contractIndexes;
11+
12+
uint public membersCount;
13+
mapping(uint memberId => address member) public members;
14+
mapping(address member => uint memberId) public memberIds;
15+
mapping(uint memberId => uint seat) public memberToSeat;
16+
17+
SystemPause internal systemPause; // 3 slots
18+
19+
function addContract(uint index, address contractAddress, bool isProxy) external override {
20+
contracts[index] = Contract({addr: contractAddress, isProxy: isProxy});
21+
contractIndexes[contractAddress] = index;
22+
}
23+
24+
function getContractIndexByAddress(address contractAddress) external override view returns (uint) {
25+
return contractIndexes[contractAddress];
26+
}
27+
28+
function getContractAddressByIndex(uint index) external override view returns (address payable) {
29+
return payable(contracts[index].addr);
30+
}
31+
32+
function getPauseConfig() public override view returns (uint config) {
33+
return systemPause.config;
34+
}
35+
36+
function setPauseConfig(uint config) external {
37+
systemPause.config = uint48(config);
38+
}
39+
40+
function isAdvisoryBoardMember(address member) external override view returns (bool) {
41+
uint memberId = memberIds[member];
42+
return memberToSeat[memberId] != 0;
43+
}
44+
45+
function isMember(address member) external override view returns (bool) {
46+
return memberIds[member] != 0;
47+
}
48+
49+
function setAdvisoryBoardMember(address member, uint seat) public {
50+
uint memberId = memberIds[member];
51+
memberToSeat[memberId] = seat;
52+
}
53+
54+
function setMember(address member) public {
55+
uint memberId = ++membersCount;
56+
members[memberId] = member;
57+
memberIds[member] = memberId;
58+
}
59+
60+
// Override the functions that Governor needs
61+
function getMemberId(address member) external override view returns (uint) {
62+
return memberIds[member];
63+
}
64+
65+
function getAdvisoryBoardSeat(address member) external override view returns (uint) {
66+
uint memberId = memberIds[member];
67+
return memberToSeat[memberId];
68+
}
69+
70+
function swapAdvisoryBoardMember(uint from, uint to) external override {
71+
// This is a mock implementation - in real contract it would swap the seats
72+
require(from > 0 && to > 0, "Invalid member IDs");
73+
require(from <= membersCount && to <= membersCount, "Member ID out of range");
74+
75+
// Swap the seats
76+
uint tempSeat = memberToSeat[from];
77+
memberToSeat[from] = memberToSeat[to];
78+
memberToSeat[to] = tempSeat;
79+
}
80+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// SPDX-License-Identifier: GPL-3.0-only
2+
3+
pragma solidity ^0.8.18;
4+
5+
import "../../generic/TokenControllerGeneric.sol";
6+
7+
contract GVMockTokenController is TokenControllerGeneric {
8+
9+
mapping(address => uint) internal lockedUserTokens;
10+
mapping(address => uint) internal totalTokenAmount;
11+
uint internal _totalSupply;
12+
13+
function totalBalanceOf(address member) external override view returns (uint) {
14+
return totalTokenAmount[member];
15+
}
16+
17+
function setTotalBalanceOf(address member, uint amount) external {
18+
totalTokenAmount[member] = amount;
19+
}
20+
21+
function totalSupply() external override view returns (uint) {
22+
return _totalSupply;
23+
}
24+
25+
function setTotalSupply(uint amount) external {
26+
_totalSupply = amount;
27+
}
28+
29+
function lockForMemberVote(address _of, uint duration) external override {
30+
lockedUserTokens[_of] = block.timestamp + duration;
31+
}
32+
}

contracts/modules/governance/Governor.sol

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ contract Governor is IGovernor, RegistryAware, Multicall {
3030

3131
ITokenController public immutable tokenController;
3232

33-
uint public constant TIMELOCK_PERIOD = 12 hours;
33+
uint public constant TIMELOCK_PERIOD = 1 days;
3434
uint public constant VOTING_PERIOD = 3 days;
3535
uint public constant ADVISORY_BOARD_THRESHOLD = 3;
3636
uint public constant MEMBER_VOTE_QUORUM_PERCENTAGE = 15; // 15% of token supply
@@ -99,7 +99,7 @@ contract Governor is IGovernor, RegistryAware, Multicall {
9999
kind: kind,
100100
proposedAt: block.timestamp.toUint32(),
101101
voteBefore: (block.timestamp + VOTING_PERIOD).toUint32(),
102-
executeAfter: (block.timestamp + VOTING_PERIOD + TIMELOCK_PERIOD).toUint32(),
102+
executeAfter: (block.timestamp + TIMELOCK_PERIOD).toUint32(),
103103
status: ProposalStatus.Proposed
104104
});
105105

@@ -123,7 +123,6 @@ contract Governor is IGovernor, RegistryAware, Multicall {
123123
require(proposal.kind == ProposalKind.AdvisoryBoard, CannotCancelMemberProposal());
124124
require(proposal.status != ProposalStatus.Executed, ProposalAlreadyExecuted());
125125
require(proposal.status != ProposalStatus.Canceled, ProposalIsCanceled());
126-
// todo: consider checking if it's actually in proposed status
127126

128127
proposal.status = ProposalStatus.Canceled;
129128
proposals[proposalId] = proposal;
@@ -169,6 +168,10 @@ contract Governor is IGovernor, RegistryAware, Multicall {
169168
proposal.executeAfter = (block.timestamp + TIMELOCK_PERIOD).toUint32();
170169
}
171170

171+
if(!isAbProposal) {
172+
_lockTokenTransfers(msg.sender, block.timestamp + TIMELOCK_PERIOD);
173+
}
174+
172175
emit VoteCast(proposalId, proposal.kind, voterId, choice, weight);
173176
}
174177

@@ -231,4 +234,8 @@ contract Governor is IGovernor, RegistryAware, Multicall {
231234
emit ProposalExecuted(proposalId);
232235
}
233236

237+
function getProposal(uint proposalId) external view returns (Proposal memory proposal) {
238+
return proposals[proposalId];
239+
}
240+
234241
}

lib/constants.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,12 @@ const ClaimMethod = {
184184
DeprecatedYTC: 1,
185185
};
186186

187+
const VoteType = {
188+
Against: 0,
189+
For: 1,
190+
Abstain: 2,
191+
};
192+
187193
module.exports = {
188194
Assets,
189195
ProposalCategory,
@@ -200,4 +206,5 @@ module.exports = {
200206
ClaimMethod,
201207
ContractIndexes,
202208
PauseTypes,
209+
VoteType,
203210
};

0 commit comments

Comments
 (0)