Skip to content

Commit

Permalink
✨ Add checkOwnerOrRole to EnumerableRoles (#1219)
Browse files Browse the repository at this point in the history
  • Loading branch information
Vectorized authored Dec 9, 2024
1 parent 9339f25 commit 6d64c0a
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 3 deletions.
18 changes: 15 additions & 3 deletions src/auth/EnumerableRoles.sol
Original file line number Diff line number Diff line change
Expand Up @@ -244,17 +244,23 @@ abstract contract EnumerableRoles {
}
}

/// @dev Throws if the sender does not have `role`.
/// @dev Reverts if `msg.sender` does not have `role`.
function _checkRole(uint256 role) internal view virtual {
if (!_hasRole(msg.sender, role)) _revertEnumerableRolesUnauthorized();
}

/// @dev Throws if the sender does not have any roles in `encodedRoles`.
/// @dev Reverts if `msg.sender` does not have any role in `encodedRoles`.
function _checkRoles(bytes memory encodedRoles) internal view virtual {
if (!_hasAnyRoles(msg.sender, encodedRoles)) _revertEnumerableRolesUnauthorized();
}

/// @dev Throws if the sender does not have any roles in `encodedRoles`.
/// @dev Reverts if `msg.sender` is not the contract owner and does not have `role`.
function _checkOwnerOrRole(uint256 role) internal view virtual {
if (!_senderIsContractOwner()) _checkRole(role);
}

/// @dev Reverts if `msg.sender` is not the contract owner and
/// does not have any role in `encodedRoles`.
function _checkOwnerOrRoles(bytes memory encodedRoles) internal view virtual {
if (!_senderIsContractOwner()) _checkRoles(encodedRoles);
}
Expand All @@ -276,6 +282,12 @@ abstract contract EnumerableRoles {
_;
}

/// @dev Marks a function as only callable by the owner or by an account with `role`.
modifier onlyOwnerOrRole(uint256 role) virtual {
_checkOwnerOrRole(role);
_;
}

/// @dev Marks a function as only callable by the owner or
/// by an account with any role in `encodedRoles`.
/// Checks for ownership first, then checks for roles.
Expand Down
19 changes: 19 additions & 0 deletions test/EnumerableRoles.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,25 @@ contract EnumerableRolesTest is SoladyTest {
}
}

function testOnlyOwnerOrRole(uint256 allowedRole, uint256 holderRole) public {
address holder = _randomUniqueHashedAddress();
assertEq(mockEnumerableRoles.owner(), address(this));
if (holder == address(this)) return;
mockEnumerableRoles.setAllowedRole(allowedRole);
mockEnumerableRoles.setRoleDirect(holder, holderRole, true);
if (_randomChance(32)) {
mockEnumerableRoles.guardedByOnlyOwnerOrRole();
}
if (holderRole != allowedRole) {
vm.prank(holder);
vm.expectRevert(EnumerableRoles.EnumerableRolesUnauthorized.selector);
mockEnumerableRoles.guardedByOnlyOwnerOrRole();
} else {
vm.prank(holder);
mockEnumerableRoles.guardedByOnlyOwnerOrRole();
}
}

function testSetAndGetRoles(bytes32) public {
_TestTemps memory t;
t.holders = _sampleUniqueAddresses(_randomUniform() & 7);
Expand Down
9 changes: 9 additions & 0 deletions test/utils/mocks/MockEnumerableRoles.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ contract MockEnumerableRoles is EnumerableRoles, Brutalizer {
address owner;
bool ownerReverts;
bytes allowedRolesEncoded;
uint256 allowedRole;
}

event Yo();
Expand Down Expand Up @@ -57,10 +58,18 @@ contract MockEnumerableRoles is EnumerableRoles, Brutalizer {
$.allowedRolesEncoded = value;
}

function setAllowedRole(uint256 role) public {
$.allowedRole = role;
}

function guardedByOnlyOwnerOrRoles() public onlyOwnerOrRoles($.allowedRolesEncoded) {
emit Yo();
}

function guardedByOnlyOwnerOrRole() public onlyOwnerOrRole($.allowedRole) {
emit Yo();
}

function guardedByOnlyRoles() public onlyRoles($.allowedRolesEncoded) {
emit Yo();
}
Expand Down

0 comments on commit 6d64c0a

Please sign in to comment.