1
+ // SPDX-License-Identifier: MIT
2
+
3
+ pragma solidity ^ 0.8.20 ;
4
+
5
+ import { IAuthority } from "@openzeppelin/contracts/access/manager/IAuthority.sol " ;
6
+ import { Masks } from "../utils/Masks.sol " ;
7
+
8
+ contract AccessManagerLight is IAuthority {
9
+ using Masks for * ;
10
+
11
+ uint8 public constant ADMIN = 0x00 ;
12
+ uint8 public constant PUBLIC = 0xFF ;
13
+ Masks.Mask public immutable ADMIN_MASK = ADMIN.toMask ();
14
+ Masks.Mask public immutable PUBLIC_MASK = PUBLIC.toMask ();
15
+
16
+ mapping (address => Masks.Mask ) private _permissions;
17
+ mapping (address => mapping (bytes4 => Masks.Mask)) private _restrictions;
18
+ mapping (uint8 => Masks.Mask ) private _admin;
19
+
20
+ event GroupAdded (address indexed user , uint8 indexed group );
21
+ event GroupRemoved (address indexed user , uint8 indexed group );
22
+ event GroupAdmins (uint8 indexed group , Masks.Mask admins );
23
+ event Requirements (address indexed target , bytes4 indexed selector , Masks.Mask groups );
24
+
25
+ error MissingPermissions (address user , Masks.Mask permissions , Masks.Mask restriction );
26
+
27
+ modifier onlyRole (Masks.Mask restriction ) {
28
+ Masks.Mask permissions = getGroups (msg .sender );
29
+ if (permissions.intersection (restriction).isEmpty ()) {
30
+ revert MissingPermissions (msg .sender , permissions, restriction);
31
+ }
32
+ _;
33
+ }
34
+
35
+ constructor (address admin ) {
36
+ _addGroup (admin, 0 );
37
+ }
38
+
39
+ // Getters
40
+ function canCall (address caller , address target , bytes4 selector ) public view returns (bool ) {
41
+ return ! getGroups (caller).intersection (getRequirements (target, selector)).isEmpty ();
42
+ }
43
+
44
+ function getGroups (address user ) public view returns (Masks.Mask) {
45
+ return _permissions[user].union (PUBLIC_MASK);
46
+ }
47
+
48
+ function getGroupAdmins (uint8 group ) public view returns (Masks.Mask) {
49
+ return _admin[group].union (ADMIN_MASK); // Admin have power over all groups
50
+ }
51
+
52
+ function getRequirements (address target , bytes4 selector ) public view returns (Masks.Mask) {
53
+ return _restrictions[target][selector].union (ADMIN_MASK); // Admins can call an function
54
+ }
55
+
56
+ // Group management
57
+ function addGroup (address user , uint8 group ) public onlyRole (getGroupAdmins (group)) {
58
+ _addGroup (user, group);
59
+ }
60
+
61
+ function remGroup (address user , uint8 group ) public onlyRole (getGroupAdmins (group)) {
62
+ _remGroup (user, group);
63
+ }
64
+
65
+ function _addGroup (address user , uint8 group ) internal {
66
+ _permissions[user] = _permissions[user].union (group.toMask ());
67
+ emit GroupAdded (user, group);
68
+ }
69
+
70
+ function _remGroup (address user , uint8 group ) internal {
71
+ _permissions[user] = _permissions[user].difference (group.toMask ());
72
+ emit GroupRemoved (user, group);
73
+ }
74
+
75
+ // Group admin management
76
+ function setGroupAdmins (uint8 group , uint8 [] calldata admins ) public onlyRole (ADMIN_MASK) {
77
+ _setGroupAdmins (group, admins.toMask ());
78
+ }
79
+
80
+ function _setGroupAdmins (uint8 group , Masks.Mask admins ) internal {
81
+ _admin[group] = admins;
82
+ emit GroupAdmins (group, admins);
83
+ }
84
+
85
+ // Requirement management
86
+ function setRequirements (address target , bytes4 [] calldata selectors , uint8 [] calldata groups ) public onlyRole (ADMIN_MASK) {
87
+ Masks.Mask mask = groups.toMask ();
88
+ for (uint256 i = 0 ; i < selectors.length ; ++ i) {
89
+ _setRequirements (target, selectors[i], mask);
90
+ }
91
+ }
92
+
93
+ function _setRequirements (address target , bytes4 selector , Masks.Mask groups ) internal {
94
+ _restrictions[target][selector] = groups;
95
+ emit Requirements (target, selector, groups);
96
+ }
97
+ }
0 commit comments