Skip to content

Commit 5fb4474

Browse files
authored
Diamond Access Control (#89)
* init ac * added tests * added require * cosmetic
1 parent 93e37cd commit 5fb4474

File tree

7 files changed

+381
-4
lines changed

7 files changed

+381
-4
lines changed
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.4;
3+
4+
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
5+
6+
import {DiamondAccessControlStorage, IAccessControl} from "./DiamondAccessControlStorage.sol";
7+
8+
/**
9+
* @notice The Diamond standard module
10+
*
11+
* This is modified version of OpenZeppelin's AccessControl contract to be used as a Storage contract
12+
* by the Diamond Standard.
13+
*/
14+
abstract contract DiamondAccessControl is DiamondAccessControlStorage {
15+
/**
16+
* @dev Modifier that checks that an account has a specific role. Reverts
17+
* with a standardized message including the required role.
18+
*
19+
* The format of the revert reason is given by the following regular expression:
20+
*
21+
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
22+
*/
23+
modifier onlyRole(bytes32 role_) {
24+
_checkRole(role_);
25+
_;
26+
}
27+
28+
/**
29+
* @notice Sets `DEFAULT_ADMIN_ROLE` to `msg.sender`
30+
*/
31+
function __DiamondAccessControl_init()
32+
internal
33+
onlyInitializing(DIAMOND_ACCESS_CONTROL_STORAGE_SLOT)
34+
{
35+
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
36+
}
37+
38+
/**
39+
* @inheritdoc IAccessControl
40+
*/
41+
function grantRole(
42+
bytes32 role_,
43+
address account_
44+
) public virtual override onlyRole(getRoleAdmin(role_)) {
45+
_grantRole(role_, account_);
46+
}
47+
48+
/**
49+
* @inheritdoc IAccessControl
50+
*/
51+
function revokeRole(
52+
bytes32 role_,
53+
address account_
54+
) public virtual override onlyRole(getRoleAdmin(role_)) {
55+
_revokeRole(role_, account_);
56+
}
57+
58+
/**
59+
* @inheritdoc IAccessControl
60+
*/
61+
function renounceRole(bytes32 role_, address account_) public virtual override {
62+
require(account_ == msg.sender, "AccessControl: can only renounce roles for self");
63+
64+
_revokeRole(role_, account_);
65+
}
66+
67+
/**
68+
* @dev Sets `adminRole` as ``role``'s admin role.
69+
*
70+
* Emits a {RoleAdminChanged} event.
71+
*/
72+
function _setRoleAdmin(bytes32 role_, bytes32 adminRole_) internal virtual {
73+
bytes32 previousAdminRole_ = getRoleAdmin(role_);
74+
75+
_getAccessControlStorage().roles[role_].adminRole = adminRole_;
76+
77+
emit RoleAdminChanged(role_, previousAdminRole_, adminRole_);
78+
}
79+
80+
/**
81+
* @dev Grants `role` to `account`.
82+
*
83+
* Internal function without access restriction.
84+
*
85+
* May emit a {RoleGranted} event.
86+
*/
87+
function _grantRole(bytes32 role_, address account_) internal virtual {
88+
require(!hasRole(role_, account_), "AccessControl: role is granted");
89+
90+
_getAccessControlStorage().roles[role_].members[account_] = true;
91+
92+
emit RoleGranted(role_, account_, msg.sender);
93+
}
94+
95+
/**
96+
* @dev Revokes `role` from `account`.
97+
*
98+
* Internal function without access restriction.
99+
*
100+
* May emit a {RoleRevoked} event.
101+
*/
102+
function _revokeRole(bytes32 role_, address account_) internal virtual {
103+
require(hasRole(role_, account_), "AccessControl: role is not granted");
104+
105+
_getAccessControlStorage().roles[role_].members[account_] = false;
106+
107+
emit RoleRevoked(role_, account_, msg.sender);
108+
}
109+
110+
/**
111+
* @dev Revert with a standard message if `_msgSender()` is missing `role`.
112+
* Overriding this function changes the behavior of the {onlyRole} modifier.
113+
*
114+
* Format of the revert message is described in {_checkRole}.
115+
*/
116+
function _checkRole(bytes32 role_) internal view virtual {
117+
_checkRole(role_, msg.sender);
118+
}
119+
120+
/**_
121+
* @dev Revert with a standard message if `account` is missing `role`.
122+
*
123+
* The format of the revert reason is given by the following regular expression:
124+
*
125+
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
126+
*/
127+
function _checkRole(bytes32 role_, address account_) internal view virtual {
128+
if (!hasRole(role_, account_)) {
129+
revert(
130+
string(
131+
abi.encodePacked(
132+
"AccessControl: account ",
133+
Strings.toHexString(account_),
134+
" is missing role ",
135+
Strings.toHexString(uint256(role_), 32)
136+
)
137+
)
138+
);
139+
}
140+
}
141+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.4;
3+
4+
import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol";
5+
6+
import {InitializableStorage} from "../utils/InitializableStorage.sol";
7+
8+
/**
9+
* @notice The Diamond standard module
10+
*
11+
* This is an AccessControl Storage contract with Diamond Standard support
12+
*/
13+
abstract contract DiamondAccessControlStorage is IAccessControl, InitializableStorage {
14+
bytes32 public constant DIAMOND_ACCESS_CONTROL_STORAGE_SLOT =
15+
keccak256("diamond.standard.diamond.access.control.storage");
16+
17+
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
18+
19+
struct RoleData {
20+
mapping(address => bool) members;
21+
bytes32 adminRole;
22+
}
23+
24+
struct DACStorage {
25+
mapping(bytes32 => RoleData) roles;
26+
}
27+
28+
function _getAccessControlStorage() internal pure returns (DACStorage storage _dacStorage) {
29+
bytes32 slot_ = DIAMOND_ACCESS_CONTROL_STORAGE_SLOT;
30+
31+
assembly {
32+
_dacStorage.slot := slot_
33+
}
34+
}
35+
36+
/**
37+
* @inheritdoc IAccessControl
38+
*/
39+
function hasRole(bytes32 role_, address account_) public view virtual override returns (bool) {
40+
return _getAccessControlStorage().roles[role_].members[account_];
41+
}
42+
43+
/**
44+
* @inheritdoc IAccessControl
45+
*/
46+
function getRoleAdmin(bytes32 role_) public view virtual override returns (bytes32) {
47+
return _getAccessControlStorage().roles[role_].adminRole;
48+
}
49+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.4;
3+
4+
import {DiamondAccessControl} from "../../../diamond/access/DiamondAccessControl.sol";
5+
6+
contract DiamondAccessControlMock is DiamondAccessControl {
7+
bytes32 public constant AGENT_ROLE = bytes32(uint256(0x01));
8+
9+
function __DiamondAccessControlDirect_init() external {
10+
__DiamondAccessControl_init();
11+
}
12+
13+
function __DiamondAccessControlMock_init()
14+
external
15+
initializer(DIAMOND_ACCESS_CONTROL_STORAGE_SLOT)
16+
{
17+
__DiamondAccessControl_init();
18+
}
19+
20+
function setRoleAdmin(
21+
bytes32 role_,
22+
bytes32 adminRole_
23+
) external onlyRole(DEFAULT_ADMIN_ROLE) {
24+
_setRoleAdmin(role_, adminRole_);
25+
}
26+
}

contracts/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@solarity/solidity-lib",
3-
"version": "2.6.18",
3+
"version": "2.6.19",
44
"license": "MIT",
55
"author": "Distributed Lab",
66
"readme": "README.md",

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@solarity/solidity-lib",
3-
"version": "2.6.18",
3+
"version": "2.6.19",
44
"license": "MIT",
55
"author": "Distributed Lab",
66
"description": "Solidity Library by Distributed Lab",

0 commit comments

Comments
 (0)