-
Notifications
You must be signed in to change notification settings - Fork 74
/
VaultAuthorityModule.sol
201 lines (163 loc) · 9.31 KB
/
VaultAuthorityModule.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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.10;
import {Auth, Authority} from "solmate/auth/Auth.sol";
/// @title Rari Vault Authority Module
/// @notice Module for managing access to secured Vault operations.
/// @author Modified from Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/auth/authorities/RolesAuthority.sol)
contract VaultAuthorityModule is Auth, Authority {
/*///////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
/// @notice Creates a Vault configuration module.
/// @param _owner The owner of the module.
/// @param _authority The Authority of the module.
constructor(address _owner, Authority _authority) Auth(_owner, _authority) {}
/*///////////////////////////////////////////////////////////////
CUSTOM TARGET AUTHORITY STORAGE
//////////////////////////////////////////////////////////////*/
/// @notice Maps targets to a custom Authority to use for authorization.
mapping(address => Authority) public getTargetCustomAuthority;
/*///////////////////////////////////////////////////////////////
USER ROLE STORAGE
//////////////////////////////////////////////////////////////*/
/// @notice Maps users to a bytes32 set of all the roles assigned to them.
mapping(address => bytes32) public getUserRoles;
/// @notice Gets whether a user has a specific role.
/// @param user The user to check for.
/// @param role The role to check if the user has.
/// @return A boolean indicating whether the user has the role.
function doesUserHaveRole(address user, uint8 role) external view returns (bool) {
unchecked {
// Generate a mask for the role.
bytes32 shifted = bytes32(uint256(uint256(2)**uint256(role)));
// Check if the user has the role using the generated mask.
return bytes32(0) != getUserRoles[user] & shifted;
}
}
/*///////////////////////////////////////////////////////////////
ROLE CAPABILITY STORAGE
//////////////////////////////////////////////////////////////*/
/// @notice Maps function signatures to a set of all roles that can call the given function.
mapping(bytes4 => bytes32) public getRoleCapabilities;
/// @notice Maps function signatures to a boolean indicating whether anyone can call the given function.
mapping(bytes4 => bool) public isCapabilityPublic;
/// @notice Gets whether a role has a specific capability.
/// @param role The role to check for.
/// @param functionSig function to check the role is capable of calling.
/// @return A boolean indicating whether the role has the capability.
function doesRoleHaveCapability(uint8 role, bytes4 functionSig) external view virtual returns (bool) {
unchecked {
// Generate a mask for the role.
bytes32 shifted = bytes32(uint256(uint256(2)**uint256(role)));
// Check if the role has the capability using the generated mask.
return bytes32(0) != getRoleCapabilities[functionSig] & shifted;
}
}
/*///////////////////////////////////////////////////////////////
AUTHORIZATION LOGIC
//////////////////////////////////////////////////////////////*/
/// @notice Returns if a user can call a given target's function.
/// @param user The user to check for.
/// @param target The target the user is trying to call.
/// @param functionSig The function signature the user is trying to call.
/// @return A boolean indicating if the user can call the function on the target.
/// @dev First checks whether the target has a custom Authority assigned to it, if so returns
/// whether the custom Authority would allow the user to call the desired function on the target,
/// otherwise returns whether the user is able to call the desired function on any target contract.
function canCall(
address user,
address target,
bytes4 functionSig
) external view override returns (bool) {
// Get the target's custom Authority. Will be address(0) if none.
Authority customAuthority = getTargetCustomAuthority[target];
// If a custom Authority is set, return whether the Authority allows the user to call the function.
if (address(customAuthority) != address(0)) return customAuthority.canCall(user, target, functionSig);
// Return whether the user has an authorized role or the capability is publicly accessible.
return bytes32(0) != getUserRoles[user] & getRoleCapabilities[functionSig] || isCapabilityPublic[functionSig];
}
/*///////////////////////////////////////////////////////////////
CUSTOM TARGET AUTHORITY CONFIGURATION LOGIC
//////////////////////////////////////////////////////////////*/
/// @notice Emitted when a custom Authority is set for a target.
/// @param target The target who had a custom Authority set.
/// @param authority The custom Authority set for the target.
event TargetCustomAuthorityUpdated(address indexed target, Authority indexed authority);
/// @notice Sets a custom Authority for a target.
/// @param target The target to set a custom Authority for.
/// @param customAuthority The custom Authority to set.
function setTargetCustomAuthority(address target, Authority customAuthority) external requiresAuth {
// Update the target's custom Authority.
getTargetCustomAuthority[target] = customAuthority;
emit TargetCustomAuthorityUpdated(target, customAuthority);
}
/*///////////////////////////////////////////////////////////////
ROLE CAPABILITY CONFIGURATION LOGIC
//////////////////////////////////////////////////////////////*/
/// @notice Emitted when a role's capabilities are updated.
/// @param role The role whose capabilities were updated.
/// @param functionSig The function the role was enabled to call or not.
/// @param enabled Whether the role is now able to call the function or not.
event RoleCapabilityUpdated(uint8 indexed role, bytes4 indexed functionSig, bool enabled);
/// @notice Sets a capability for a role.
/// @param role The role to set a capability for.
/// @param functionSig The function to enable the role to call or not.
/// @param enabled Whether the role should be able to call the function or not.
function setRoleCapability(
uint8 role,
bytes4 functionSig,
bool enabled
) external requiresAuth {
// Get the previous set of role capabilities.
bytes32 lastCapabilities = getRoleCapabilities[functionSig];
unchecked {
// Generate a mask for the role.
bytes32 shifted = bytes32(uint256(uint256(2)**uint256(role)));
// Update the role's capability set with the role mask.
getRoleCapabilities[functionSig] = enabled ? lastCapabilities | shifted : lastCapabilities & ~shifted;
}
emit RoleCapabilityUpdated(role, functionSig, enabled);
}
/*///////////////////////////////////////////////////////////////
PUBLIC CAPABILITY CONFIGURATION LOGIC
//////////////////////////////////////////////////////////////*/
/// @notice Emitted when whether a capability is public is updated.
/// @param functionSig The function that was made public or not.
/// @param enabled Whether the function is not publicly callable or not.
event PublicCapabilityUpdated(bytes4 indexed functionSig, bool enabled);
/// @notice Sets whether a capability is public or not.
/// @param functionSig The function make public or not.
/// @param enabled Whether the function should be public or not.
function setPublicCapability(bytes4 functionSig, bool enabled) external requiresAuth {
// Update whether the capability is public.
isCapabilityPublic[functionSig] = enabled;
emit PublicCapabilityUpdated(functionSig, enabled);
}
/*///////////////////////////////////////////////////////////////
USER ROLE ASSIGNMENT LOGIC
//////////////////////////////////////////////////////////////*/
/// @notice Emitted when a user's role is updated.
/// @param user The user who had their role updated.
/// @param role The role the user had assigned/removed.
/// @param enabled Whether the user had the role assigned/removed.
event UserRoleUpdated(address indexed user, uint8 indexed role, bool enabled);
/// @notice Assigns a role to a user.
/// @param user The user to assign a role to.
/// @param role The role to assign to the user.
/// @param enabled Whether the user should have the role or not.
function setUserRole(
address user,
uint8 role,
bool enabled
) external requiresAuth {
// Get the previous set of roles.
bytes32 lastRoles = getUserRoles[user];
unchecked {
// Generate a mask for the role.
bytes32 shifted = bytes32(uint256(uint256(2)**uint256(role)));
// Update the user's role set with the role mask.
getUserRoles[user] = enabled ? lastRoles | shifted : lastRoles & ~shifted;
}
emit UserRoleUpdated(user, role, enabled);
}
}