Omniscia 0xPhase Audit
AccessControl Code Style Findings
AccessControl Code Style Findings
ACL-01C: Inefficient mapping
Lookups
Type | Severity | Location |
---|---|---|
Gas Optimization | AccessControl.sol:L225, L226, L244, L245 |
Description:
The linked statements perform key-based lookup operations on mapping
declarations from storage multiple times for the same key redundantly.
Example:
224function _grantRoleAccount(bytes32 role, address account) internal virtual {225 if (!_acs().roles[role].members[account]) {226 _acs().roles[role].members[account] = true;227 emit RoleAccountGranted(role, account, msg.sender);228 }229}
Recommendation:
As the lookups internally perform an expensive keccak256
operation, we advise the lookups to be cached wherever possible to a single local declaration that either holds the value of the mapping
in case of primitive types or holds a storage
pointer to the struct
contained.
Alleviation (3dd3d7bf0c2693b2f9c23bacedfa420393f7ea84):
All referenced mapping
lookups have been optimized as advised, utilizing interim variables for iterative mapping
declarations and caching values to local variables where applicable.
ACL-02C: Loop Iterator Optimization
Type | Severity | Location |
---|---|---|
Gas Optimization | AccessControl.sol:L191 |
Description:
The linked for
loop increments / decrements the iterator "safely" due to Solidity's built-in safe arithmetics (post-0.8.X
).
Example:
191for (uint256 i = 0; i < length; i++) {
Recommendation:
We advise the increment / decrement operation to be performed in an unchecked
code block as the last statement within the for
loop to optimize its execution cost.
Alleviation (3dd3d7bf0c2693b2f9c23bacedfa420393f7ea84):
All referenced loop iterators have been optimized as advised, removing their for
declaration increment statement and instead performing it in an unchecked
code block wherever needed (i.e. before a continue
statement or at the end of the for
loop's body).
ACL-03C: Multiple Top-Level Declarations
Type | Severity | Location |
---|---|---|
Code Style | AccessControl.sol:L21, L109 |
Description:
The referenced file contains multiple top-level declarations that decrease the legibility of the codebase.
Example:
21interface IAccessControl {22 /// @notice Event emitted when the admin of a role changes23 /// @param role The role that changed24 /// @param previousAdminRole The previous admin role25 /// @param newAdminRole The new admin role26 event RoleAdminChanged(27 bytes32 indexed role,28 bytes32 indexed previousAdminRole,29 bytes32 indexed newAdminRole30 );31
32 /// @notice Event emitted when the role is granted to an account33 /// @param role The role that was granted34 /// @param account The account the role was granted to35 /// @param sender The message sender36 event RoleAccountGranted(37 bytes32 indexed role,38 address indexed account,39 address indexed sender40 );41
42 /// @notice Event emitted when the role is revoked from an account43 /// @param role The role that was revoked44 /// @param account The account the role was revoked from45 /// @param sender The message sender46 event RoleAccountRevoked(47 bytes32 indexed role,48 address indexed account,49 address indexed sender50 );51
52 /// @notice Event emitted when the role is granted to a DB key53 /// @param role The role that was granted54 /// @param key The DB key the role was granted to55 /// @param sender The message sender56 event RoleKeyGranted(57 bytes32 indexed role,58 bytes32 indexed key,59 address indexed sender60 );61
62 /// @notice Event emitted when the role is revoked from a DB key63 /// @param role The role that was revoked64 /// @param key The DB key the role was revoked from65 /// @param sender The message sender66 event RoleKeyRevoked(67 bytes32 indexed role,68 bytes32 indexed key,69 address indexed sender70 );71
72 /// @notice Grants the role to the account73 /// @param role The granted role74 /// @param account The account the role is granted to75 function grantRoleAccount(bytes32 role, address account) external;76
77 /// @notice Grants the role to the DB key78 /// @param role The granted role79 /// @param key The DB key the role is granted to80 function grantRoleKey(bytes32 role, bytes32 key) external;81
82 /// @notice Revokes the role from the account83 /// @param role The revoked role84 /// @param account The account the role is revoked from85 function revokeRoleAccount(bytes32 role, address account) external;86
87 /// @notice Revokes the role from the DB key88 /// @param role The revoked role89 /// @param key The DB key the role is revoked from90 function revokeRoleKey(bytes32 role, bytes32 key) external;91
92 /// @notice Removes the role from the message sender93 /// @param role The revoked role94 /// @param account The message sender95 function renounceRole(bytes32 role, address account) external;96
97 /// @notice Checks if the account has the role98 /// @param role The role the account is checked against99 /// @param account The100 /// @return If the account has the role101 function hasRole(bytes32 role, address account) external view returns (bool);102
103 /// @notice Gets the admin of the role104 /// @param role The role to get the admin for105 /// @return The admin of the role106 function getRoleAdmin(bytes32 role) external view returns (bytes32);107}108
109contract AccessControl is IAccessControl, ERC165, Element {
Recommendation:
We advise all highlighted top-level declarations to be split into their respective code files, avoiding unnecessary imports as well as increasing the legibility of the codebase.
Alleviation (3dd3d7bf0c2693b2f9c23bacedfa420393f7ea84):
The IAccessControl
interface was properly split to its dedicated file and is now imported by the AccessControl
codebase, rendering this exhibit addressed.
ACL-04C: Redundant Repetitive Invocations of Getter Function
Type | Severity | Location |
---|---|---|
Gas Optimization | AccessControl.sol:L192 |
Description:
The Element::db
getter function is redundantly invoked multiple times within AccessControl::hasRole
on each iteration.
Example:
179/// @inheritdoc IAccessControl180function hasRole(181 bytes32 role,182 address account183) public view virtual override returns (bool) {184 RoleData storage roleData = _acs().roles[role];185
186 if (roleData.members[account]) return true;187
188 bytes32 addr = bytes32(bytes20(account));189 uint256 length = roleData.keys.length();190
191 for (uint256 i = 0; i < length; i++) {192 if (db().hasPair(roleData.keys.at(i), addr)) return true;193 }194
195 return false;196}
Recommendation:
We advise it to be invoked once and stored to a local variable that is consequently utilized within the for
loop, optimizing the code's gas cost.
Alleviation (3dd3d7bf0c2693b2f9c23bacedfa420393f7ea84):
The result of the _db
call is properly cached outside the for
loop in the updated code, optimizing each iteration's gas cost.