Overview
TheRol abstract contract provides a comprehensive role-based access control (RBAC) system for Agora DAOs. It extends OpenZeppelin’s AccessControl contract and adds custom role management, member tracking, and permission validation logic.
Contract: AgoraDao/Rol.solType: Abstract Contract
Inherits: OpenZeppelin
AccessControl
Role Constants
The system defines four primary roles asbytes32 constants:
Role Hierarchy
Inherited from AccessControl
Highest privilege level - DAO creator/owner
Can assign AUDITOR_ROLE and revoke any role
Cannot be assigned to others (only admin can revoke roles)
Highest privilege level - DAO creator/owner
Can assign AUDITOR_ROLE and revoke any role
Cannot be assigned to others (only admin can revoke roles)
Second-highest privilege
Can assign TASK_MANAGER_ROLE, PROPOSAL_MANAGER_ROLE, and USER_ROLE
Only assignable by DEFAULT_ADMIN_ROLE
Used for DAO governance and oversight
Can assign TASK_MANAGER_ROLE, PROPOSAL_MANAGER_ROLE, and USER_ROLE
Only assignable by DEFAULT_ADMIN_ROLE
Used for DAO governance and oversight
Management role
Assignable by DEFAULT_ADMIN_ROLE or AUDITOR_ROLE
Manages task-related operations (when task system is implemented)
Assignable by DEFAULT_ADMIN_ROLE or AUDITOR_ROLE
Manages task-related operations (when task system is implemented)
Management role
Assignable by DEFAULT_ADMIN_ROLE or AUDITOR_ROLE
Manages proposal-related operations (when proposal system is implemented)
Assignable by DEFAULT_ADMIN_ROLE or AUDITOR_ROLE
Manages proposal-related operations (when proposal system is implemented)
Basic membership role
Granted when users join a DAO
Represents regular DAO members
Granted when users join a DAO
Represents regular DAO members
State Variables
Mappings
Maps each role to an array of addresses holding that role
Enables enumeration of all members with a specific role
Enables enumeration of all members with a specific role
Tracks whether an address is registered in a role’s member list
Prevents duplicate entries in roleUsers array
Prevents duplicate entries in roleUsers array
Stores the array index of each member in roleUsers
Enables O(1) removal of members from the array
Enables O(1) removal of members from the array
Functions
registerRole
Assigns a role to a user with comprehensive permission checks.The role identifier to assign (e.g., AUDITOR_ROLE, TASK_MANAGER_ROLE)
The address to receive the role
- For AUDITOR_ROLE: Only DEFAULT_ADMIN_ROLE can assign
- For other roles: DEFAULT_ADMIN_ROLE or AUDITOR_ROLE can assign
- Caller cannot assign roles to themselves
- Cannot assign DEFAULT_ADMIN_ROLE
- Validates permissions and inputs
- Grants role via
_grantRole - Marks user as member in
isMemberOfRole - Adds user to
roleUsersarray - Records position in
memberPosition - Emits
RoleRegisteredevent
registerRoleBatch
Assigns a role to multiple users in a single transaction.The role identifier to assign to all users
Array of addresses to receive the role
- Same as
registerRole - For AUDITOR_ROLE: Only DEFAULT_ADMIN_ROLE
- For other roles: DEFAULT_ADMIN_ROLE or AUDITOR_ROLE
registerRole for each user.
Example:
deleteRole
Revokes a role from a user and removes them from tracking arrays.The role identifier to revoke
The address to revoke the role from
- Only DEFAULT_ADMIN_ROLE can revoke roles
- Caller cannot revoke their own role
- Validates permissions and user status
- Revokes role via
_revokeRole - Marks user as not a member in
isMemberOfRole - Removes user from
roleUsersarray using swap-and-pop technique - Updates position mapping for moved user
- Deletes position entry for removed user
- Emits
RoleDeletedevent
getMemberByRole
Returns all addresses assigned to a specific role.The role identifier to query
Array of all addresses holding the specified role
isRole
Checks if an address has a specific role.The role identifier to check
The address to check
True if the address has the role, false otherwise
getAllByRole
Alias forgetMemberByRole - returns all addresses with a specific role.
_joinDaoUser (Internal)
Internal function for granting USER_ROLE when users join a DAO.The address joining as a user
- Validates user is not already registered
- Grants USER_ROLE
- Updates tracking mappings and arrays
- Emits RoleRegistered event with executor as address(0)
AgoraDao.joinDao() and bypasses the normal permission checks since it’s part of the join flow.
Events
RoleRegistered
Emitted when a role is successfully assigned to a user.The role that was assigned
The address that received the role
The address that performed the assignment (address(0) for _joinDaoUser)
RoleDeleted
Emitted when a role is revoked from a user.The role that was revoked
The address that lost the role
The admin address that performed the revocation
Permission Matrix
| Action | Required Role | Can Assign/Revoke |
|---|---|---|
| Assign AUDITOR_ROLE | DEFAULT_ADMIN_ROLE | AUDITOR_ROLE |
| Assign TASK_MANAGER_ROLE | DEFAULT_ADMIN_ROLE or AUDITOR_ROLE | TASK_MANAGER_ROLE |
| Assign PROPOSAL_MANAGER_ROLE | DEFAULT_ADMIN_ROLE or AUDITOR_ROLE | PROPOSAL_MANAGER_ROLE |
| Assign USER_ROLE | DEFAULT_ADMIN_ROLE or AUDITOR_ROLE | USER_ROLE |
| Revoke any role | DEFAULT_ADMIN_ROLE | Any role |
| Join as user | Anyone (via joinDao) | USER_ROLE |
Usage Example
Access Control Flow
Security Considerations
- Self-Assignment Prevention: Users cannot assign roles to themselves
- Admin Protection: DEFAULT_ADMIN_ROLE cannot be reassigned or removed through registerRole
- Self-Revocation Prevention: Users cannot revoke their own roles
- Duplicate Prevention: Checks prevent adding users to role arrays multiple times
- Zero Address Protection: Rejects zero address for all role operations
- Permission Hierarchy: Enforces strict permission requirements for role assignment