-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAuthManager.sol
142 lines (120 loc) · 4.06 KB
/
AuthManager.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
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.12;
pragma abicoder v2;
import "@openzeppelin/contracts/proxy/utils/Initializable.sol";
import "../interfaces/IAuthManager.sol";
contract AuthManager is IAuthManager, Initializable {
// mapping which contains roles for address
mapping(address => bytes32[]) internal members;
// constant for showing that element not found in array
uint256 internal constant NOT_FOUND = type(uint256).max;
// hash for SUPER role
bytes32 public immutable SUPER_ROLE;
// event emitted when new member for role added
event AddMember(address member, bytes32 role);
// event emitted when member removed from role
event RemoveMember(address member, bytes32 role);
constructor () {
SUPER_ROLE = keccak256("SUPER_ROLE");
}
/**
* @notice Initialize contract after deploying
*/
function initialize() external initializer {
members[msg.sender] = [SUPER_ROLE];
emit AddMember(msg.sender, SUPER_ROLE);
}
/**
* @notice Function returns roles array for member
* @param _member - address of member
*/
function roles(address _member) external view returns (bytes32[] memory) {
return members[_member];
}
/**
* @notice Check if member has a specific role
* @param role - hash of role string
* @param _member - address of member
*/
function has(
bytes32 role,
address _member
) external view override returns (bool) {
return _find(members[_member], role) != NOT_FOUND;
}
/**
* @notice Add new role for member. Only SUPER_ROLE can add new roles
* @param role - hash of a role string
* @param member - address of member
*/
function add(bytes32 role, address member) external override {
require(
_find(members[msg.sender], SUPER_ROLE) != NOT_FOUND,
"FORBIDDEN"
);
bytes32[] storage _roles = members[member];
require(_find(_roles, role) == NOT_FOUND, "ALREADY_MEMBER");
_roles.push(role);
emit AddMember(member, role);
}
/**
* @notice Add new role for member by string. Only SUPER_ROLE can add new roles
* @param roleString - role string
* @param member - address of member
*/
function addByString(string calldata roleString, address member) external {
require(
_find(members[msg.sender], SUPER_ROLE) != NOT_FOUND,
"FORBIDDEN"
);
bytes32[] storage _roles = members[member];
bytes32 role = keccak256(bytes(roleString));
require(_find(_roles, role) == NOT_FOUND, "ALREADY_MEMBER");
_roles.push(role);
emit AddMember(member, role);
}
/**
* @notice Remove role from member. Only SUPER_ROLE can add new roles
* @param role - hash of a role string
* @param member - address of member
*/
function remove(bytes32 role, address member) external override {
require(
_find(members[msg.sender], SUPER_ROLE) != NOT_FOUND,
"FORBIDDEN"
);
require(msg.sender != member || role != SUPER_ROLE, "INVALID");
bytes32[] storage _roles = members[member];
uint256 i = _find(_roles, role);
require(i != NOT_FOUND, "MEMBER_N_FOUND");
if (_roles.length == 1) {
delete members[member];
} else {
if (i < _roles.length - 1) {
_roles[i] = _roles[_roles.length - 1];
}
_roles.pop();
}
emit RemoveMember(member, role);
}
/**
* @notice Search _role index in _roles array
* @param _roles - array of roles hashes
* @param _role - hash of role string
*/
function _find(
bytes32[] storage _roles,
bytes32 _role
) internal view returns (uint256) {
uint256 length = _roles.length;
for (uint256 i = 0; i < length;) {
if (_role == _roles[i]) {
return i;
}
unchecked {
++i;
}
}
return NOT_FOUND;
}
}