-
Notifications
You must be signed in to change notification settings - Fork 11
/
Governor.sol
159 lines (143 loc) · 6.17 KB
/
Governor.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.17;
import {EnumerableSet} from "./Dependencies/EnumerableSet.sol";
import {Authority} from "./Dependencies/Auth.sol";
import {RolesAuthority} from "./Dependencies/RolesAuthority.sol";
/// @notice Role based Authority that supports up to 256 roles.
/// @notice We have taken the tradeoff of additional storage usage for easier readabiliy without using off-chain / indexing services.
/// @author BadgerDAO Expanded from Solmate RolesAuthority
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/authorities/RolesAuthority.sol)
/// @author Modified from Dappsys (https://github.com/dapphub/ds-roles/blob/master/src/roles.sol)
contract Governor is RolesAuthority {
using EnumerableSet for EnumerableSet.Bytes32Set;
using EnumerableSet for EnumerableSet.AddressSet;
bytes32 NO_ROLES = bytes32(0);
struct Role {
uint8 roleId;
string roleName;
}
struct Capability {
address target;
bytes4 functionSig;
uint8[] roles;
}
mapping(uint8 => string) internal roleNames;
event RoleNameSet(uint8 indexed role, string indexed name);
/// @notice The contract constructor initializes RolesAuthority with the given owner.
/// @param _owner The address of the owner, who gains all permissions by default.
constructor(address _owner) RolesAuthority(_owner, Authority(address(this))) {}
/// @notice Returns a list of users that are assigned a specific role.
/// @dev This function searches all users and checks if they are assigned the given role.
/// @dev Intended for off-chain utility only due to inefficiency.
/// @param role The role ID to find users for.
/// @return usersWithRole An array of addresses that are assigned the given role.
function getUsersByRole(uint8 role) external view returns (address[] memory usersWithRole) {
// Search over all users: O(n) * 2
uint256 count;
for (uint256 i = 0; i < users.length(); i++) {
address user = users.at(i);
bool _canCall = doesUserHaveRole(user, role);
if (_canCall) {
count += 1;
}
}
if (count > 0) {
uint256 j = 0;
usersWithRole = new address[](count);
address[] memory _usrs = users.values();
for (uint256 i = 0; i < _usrs.length; i++) {
address user = _usrs[i];
bool _canCall = doesUserHaveRole(user, role);
if (_canCall) {
usersWithRole[j] = user;
j++;
}
}
}
}
/// @notice Returns a list of roles that an address has.
/// @dev This function searches all roles and checks if they are assigned to the given user.
/// @dev Intended for off-chain utility only due to inefficiency.
/// @param user The address of the user.
/// @return rolesForUser An array of role IDs that the user has.
function getRolesForUser(address user) external view returns (uint8[] memory rolesForUser) {
// Enumerate over all possible roles and check if enabled
uint256 count;
for (uint8 i = 0; i < type(uint8).max; i++) {
if (doesUserHaveRole(user, i)) {
count += 1;
}
}
if (count > 0) {
uint256 j = 0;
rolesForUser = new uint8[](count);
for (uint8 i = 0; i < type(uint8).max; i++) {
if (doesUserHaveRole(user, i)) {
rolesForUser[j] = i;
j++;
}
}
}
}
/// @notice Converts a byte map representation to an array of role IDs.
/// @param byteMap The bytes32 value encoding the roles.
/// @return roleIds An array of role IDs extracted from the byte map.
function getRolesFromByteMap(bytes32 byteMap) public pure returns (uint8[] memory roleIds) {
uint256 count;
for (uint8 i = 0; i < type(uint8).max; i++) {
bool roleEnabled = (uint256(byteMap >> i) & 1) != 0;
if (roleEnabled) {
count += 1;
}
}
if (count > 0) {
uint256 j = 0;
roleIds = new uint8[](count);
for (uint8 i = 0; i < type(uint8).max; i++) {
bool roleEnabled = (uint256(byteMap >> i) & 1) != 0;
if (roleEnabled) {
roleIds[j] = i;
j++;
}
}
}
}
/// @notice Converts an array of role IDs to a byte map representation.
/// @param roleIds An array of role IDs.
/// @return A bytes32 value encoding the roles.
function getByteMapFromRoles(uint8[] memory roleIds) public pure returns (bytes32) {
bytes32 _data;
for (uint8 i = 0; i < roleIds.length; i++) {
_data |= bytes32(1 << uint256(roleIds[i]));
}
return _data;
}
/// @notice Retrieves all function signatures enabled for a target address.
/// @param _target The target contract address.
/// @return _funcs An array of function signatures enabled for the target.
function getEnabledFunctionsInTarget(
address _target
) public view returns (bytes4[] memory _funcs) {
bytes32[] memory _sigs = enabledFunctionSigsByTarget[_target].values();
if (_sigs.length > 0) {
_funcs = new bytes4[](_sigs.length);
for (uint256 i = 0; i < _sigs.length; ++i) {
_funcs[i] = bytes4(_sigs[i]);
}
}
}
/// @notice Retrieves the name associated with a role ID
/// @param role The role ID
/// @return roleName The name of the role
function getRoleName(uint8 role) external view returns (string memory roleName) {
return roleNames[role];
}
/// @notice Sets the name for a specific role ID for better readability
/// @dev This function requires authorization
/// @param role The role ID
/// @param roleName The name to assign to the role
function setRoleName(uint8 role, string memory roleName) external requiresAuth {
roleNames[role] = roleName;
emit RoleNameSet(role, roleName);
}
}