Skip to main content

Overview

The EnhancedAccessControl contract provides a sophisticated role-based access control system with the following features:
  • Resource-based roles: Roles can be assigned per resource (identified by uint256)
  • Root resource override: Role assignments in ROOT_RESOURCE (0x0) automatically apply to all resources
  • Bitmap storage: Efficient storage using bitmaps for up to 32 roles and 32 admin roles
  • Assignee tracking: Track up to 15 assignees per role with built-in counting
  • Admin role hierarchy: Each role has a corresponding admin role that can grant/revoke it

Role Representation

  • A role bitmap is a uint256 where:
    • Lower 128 bits represent regular roles (0-31)
    • Upper 128 bits represent admin roles (32-63)
  • Each role is represented by a nybble (4 bits) in little-endian order
  • If a role’s left-most nybble bit is at index N, its admin role nybble starts at bit position N << 128

Constants

ROOT_RESOURCE

uint256 public constant ROOT_RESOURCE = 0
The root resource identifier. Role assignments in this resource apply globally to all resources.

Events

EACRolesChanged

event EACRolesChanged(
    uint256 indexed resource,
    address indexed account,
    uint256 oldRoleBitmap,
    uint256 newRoleBitmap
)
Emitted when an account’s roles are modified within a resource.
resource
uint256
The resource identifier where roles were changed
account
address
The account whose roles were modified
oldRoleBitmap
uint256
The previous role bitmap before the change
newRoleBitmap
uint256
The new role bitmap after the change

Errors

EACUnauthorizedAccountRoles

error EACUnauthorizedAccountRoles(uint256 resource, uint256 roleBitmap, address account)
Thrown when an account lacks required roles for an operation. Error selector: 0x4b27a133

EACCannotGrantRoles

error EACCannotGrantRoles(uint256 resource, uint256 roleBitmap, address account)
Thrown when an account attempts to grant roles without the necessary admin roles. Error selector: 0xd1a3b355

EACCannotRevokeRoles

error EACCannotRevokeRoles(uint256 resource, uint256 roleBitmap, address account)
Thrown when an account attempts to revoke roles without the necessary admin roles. Error selector: 0xa604e318

EACRootResourceNotAllowed

error EACRootResourceNotAllowed()
Thrown when attempting to use grantRoles or revokeRoles with ROOT_RESOURCE. Use grantRootRoles or revokeRootRoles instead. Error selector: 0xc2842458

EACMaxAssignees

error EACMaxAssignees(uint256 resource, uint256 role)
Thrown when attempting to grant a role that has reached the maximum of 15 assignees. Error selector: 0xf9165348

EACMinAssignees

error EACMinAssignees(uint256 resource, uint256 role)
Thrown when attempting to revoke a role that would result in negative assignee count. Error selector: 0x1f80c19b

EACInvalidRoleBitmap

error EACInvalidRoleBitmap(uint256 roleBitmap)
Thrown when a role bitmap contains invalid role bits. Error selector: 0x2a7b2d20

EACInvalidAccount

error EACInvalidAccount()
Thrown when attempting to grant roles to the zero address. Error selector: 0xec3fc592

Functions

grantRoles

function grantRoles(
    uint256 resource,
    uint256 roleBitmap,
    address account
) public virtual returns (bool)
Grants all roles in the given role bitmap to an account within a specific resource. Requirements:
  • Caller must have the admin roles for all roles being granted
  • Cannot be used with ROOT_RESOURCE (use grantRootRoles instead)
  • Account cannot be the zero address
  • Roles must not exceed maximum assignees (15 per role)
resource
uint256
The resource identifier to grant roles within (cannot be ROOT_RESOURCE)
roleBitmap
uint256
The bitmap of roles to grant
account
address
The account to grant roles to
return
bool
Returns true if roles were granted, false if the account already had all the roles
Example:
// Grant ROLE_REGISTRAR to an address for a specific name
uint256 nameId = uint256(keccak256("vitalik.eth"));
bool granted = registry.grantRoles(
    nameId,
    RegistryRolesLib.ROLE_REGISTRAR,
    0x1234567890123456789012345678901234567890
);

grantRootRoles

function grantRootRoles(
    uint256 roleBitmap,
    address account
) public virtual returns (bool)
Grants all roles in the given role bitmap to an account in the ROOT_RESOURCE. Roles granted in the root resource apply to all resources. Requirements:
  • Caller must have the admin roles for all roles being granted
  • Account cannot be the zero address
  • Roles must not exceed maximum assignees (15 per role)
roleBitmap
uint256
The bitmap of roles to grant
account
address
The account to grant roles to
return
bool
Returns true if roles were granted, false if the account already had all the roles
Example:
// Grant global ROLE_REGISTRAR_ADMIN to deployer
bool granted = registry.grantRootRoles(
    RegistryRolesLib.ROLE_REGISTRAR_ADMIN,
    msg.sender
);

revokeRoles

function revokeRoles(
    uint256 resource,
    uint256 roleBitmap,
    address account
) public virtual returns (bool)
Revokes all roles in the given role bitmap from an account within a specific resource. Requirements:
  • Caller must have the admin roles for all roles being revoked
  • Cannot be used with ROOT_RESOURCE (use revokeRootRoles instead)
resource
uint256
The resource identifier to revoke roles within (cannot be ROOT_RESOURCE)
roleBitmap
uint256
The bitmap of roles to revoke
account
address
The account to revoke roles from
return
bool
Returns true if roles were revoked, false if the account didn’t have any of the roles
Example:
// Revoke ROLE_REGISTRAR from an address
uint256 nameId = uint256(keccak256("vitalik.eth"));
bool revoked = registry.revokeRoles(
    nameId,
    RegistryRolesLib.ROLE_REGISTRAR,
    0x1234567890123456789012345678901234567890
);

revokeRootRoles

function revokeRootRoles(
    uint256 roleBitmap,
    address account
) public virtual returns (bool)
Revokes all roles in the given role bitmap from an account in the ROOT_RESOURCE. Requirements:
  • Caller must have the admin roles for all roles being revoked
roleBitmap
uint256
The bitmap of roles to revoke
account
address
The account to revoke roles from
return
bool
Returns true if roles were revoked, false if the account didn’t have any of the roles
Example:
// Revoke global ROLE_REGISTRAR from an address
bool revoked = registry.revokeRootRoles(
    RegistryRolesLib.ROLE_REGISTRAR,
    0x1234567890123456789012345678901234567890
);

roles

function roles(uint256 resource, address account) public view virtual returns (uint256)
Returns the role bitmap for an account within a specific resource.
resource
uint256
The resource identifier to query
account
address
The account to query
return
uint256
The role bitmap for the account in the specified resource
Example:
uint256 nameId = uint256(keccak256("vitalik.eth"));
uint256 accountRoles = registry.roles(nameId, msg.sender);

// Check if has ROLE_REGISTRAR
bool hasRegistrarRole = (accountRoles & RegistryRolesLib.ROLE_REGISTRAR) != 0;

roleCount

function roleCount(uint256 resource) public view virtual returns (uint256)
Returns the role count bitmap for a resource. Each role’s assignee count is represented by 4 bits in little-endian order.
resource
uint256
The resource identifier to query
return
uint256
The role count bitmap where each 4-bit nybble represents the number of assignees for that role (max 15)
Example:
uint256 nameId = uint256(keccak256("vitalik.eth"));
uint256 counts = registry.roleCount(nameId);

// Extract count for ROLE_REGISTRAR (role 0)
uint256 registrarCount = counts & 0xF; // First 4 bits

hasRootRoles

function hasRootRoles(uint256 roleBitmap, address account) public view virtual returns (bool)
Checks if an account has been granted all the specified roles in the ROOT_RESOURCE.
roleBitmap
uint256
The bitmap of roles to check
account
address
The account to check
return
bool
Returns true if the account has all specified roles in ROOT_RESOURCE, false otherwise
Example:
bool isGlobalAdmin = registry.hasRootRoles(
    RegistryRolesLib.ROLE_REGISTRAR_ADMIN,
    msg.sender
);

hasRoles

function hasRoles(
    uint256 resource,
    uint256 roleBitmap,
    address account
) public view virtual returns (bool)
Checks if an account has been granted all the specified roles in either the given resource or the ROOT_RESOURCE.
resource
uint256
The resource identifier to check
roleBitmap
uint256
The bitmap of roles to check
account
address
The account to check
return
bool
Returns true if the account has all specified roles in either the resource or ROOT_RESOURCE, false otherwise
Example:
uint256 nameId = uint256(keccak256("vitalik.eth"));
bool canRegister = registry.hasRoles(
    nameId,
    RegistryRolesLib.ROLE_REGISTRAR,
    msg.sender
);

hasAssignees

function hasAssignees(uint256 resource, uint256 roleBitmap) public view virtual returns (bool)
Checks if any of the roles in the given role bitmap has at least one assignee in the specified resource.
resource
uint256
The resource identifier to check
roleBitmap
uint256
The bitmap of roles to check
return
bool
Returns true if any role in the bitmap has assignees, false otherwise
Example:
uint256 nameId = uint256(keccak256("vitalik.eth"));
bool hasRegistrars = registry.hasAssignees(
    nameId,
    RegistryRolesLib.ROLE_REGISTRAR
);

getAssigneeCount

function getAssigneeCount(
    uint256 resource,
    uint256 roleBitmap
) public view virtual returns (uint256 counts, uint256 mask)
Gets the number of assignees for each role in the given role bitmap.
resource
uint256
The resource identifier to query
roleBitmap
uint256
The bitmap of roles to query
counts
uint256
The number of assignees for each role, expressed as a packed array of 4-bit integers
mask
uint256
The mask corresponding to the given role bitmap
Example:
uint256 nameId = uint256(keccak256("vitalik.eth"));
(uint256 counts, uint256 mask) = registry.getAssigneeCount(
    nameId,
    RegistryRolesLib.ROLE_REGISTRAR
);

// Extract the count for ROLE_REGISTRAR
uint256 registrarCount = counts & 0xF;

supportsInterface

function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool)
Returns true if the contract implements the interface defined by interfaceId. Supports IEnhancedAccessControl interface.
interfaceId
bytes4
The interface identifier to check
return
bool
Returns true if the contract implements the interface, false otherwise

Modifiers

onlyRoles

modifier onlyRoles(uint256 resource, uint256 roleBitmap)
Requires that the caller has all the specified roles within the given resource or ROOT_RESOURCE. Example:
function registerName(uint256 nameId, string memory name) 
    public 
    onlyRoles(nameId, RegistryRolesLib.ROLE_REGISTRAR) 
{
    // Only accounts with ROLE_REGISTRAR for this name can execute
}

onlyRootRoles

modifier onlyRootRoles(uint256 roleBitmap)
Requires that the caller has all the specified roles within the ROOT_RESOURCE. Example:
function setGlobalConfig() 
    public 
    onlyRootRoles(RegistryRolesLib.ROLE_UPGRADE_ADMIN) 
{
    // Only accounts with global ROLE_UPGRADE_ADMIN can execute
}

canGrantRoles

modifier canGrantRoles(uint256 resource, uint256 roleBitmap)
Requires that the caller has the admin roles necessary to grant all the specified roles.

canRevokeRoles

modifier canRevokeRoles(uint256 resource, uint256 roleBitmap)
Requires that the caller has the admin roles necessary to revoke all the specified roles.

Internal Functions

_grantRoles

function _grantRoles(
    uint256 resource,
    uint256 roleBitmap,
    address account,
    bool executeCallbacks
) internal virtual returns (bool)
Internal function to grant roles without access control checks. Used by inheriting contracts.

_revokeRoles

function _revokeRoles(
    uint256 resource,
    uint256 roleBitmap,
    address account,
    bool executeCallbacks
) internal virtual returns (bool)
Internal function to revoke roles without access control checks. Used by inheriting contracts.

_revokeAllRoles

function _revokeAllRoles(
    uint256 resource,
    address account,
    bool executeCallbacks
) internal virtual returns (bool)
Internal function to revoke all roles from an account within a resource.

_transferRoles

function _transferRoles(
    uint256 resource,
    address srcAccount,
    address dstAccount,
    bool executeCallbacks
) internal virtual
Transfers all roles from srcAccount to dstAccount within the same resource. First revokes roles from source, then grants to destination to avoid exceeding max assignee limits.

_onRolesGranted

function _onRolesGranted(
    uint256 resource,
    address account,
    uint256 oldRoles,
    uint256 newRoles,
    uint256 roleBitmap
) internal virtual
Callback hook called when roles are granted. Can be overridden by inheriting contracts to implement custom logic.

_onRolesRevoked

function _onRolesRevoked(
    uint256 resource,
    address account,
    uint256 oldRoles,
    uint256 newRoles,
    uint256 roleBitmap
) internal virtual
Callback hook called when roles are revoked. Can be overridden by inheriting contracts to implement custom logic.

_checkRoles

function _checkRoles(
    uint256 resource,
    uint256 roleBitmap,
    address account
) internal view virtual
Reverts if the account does not have all the specified roles. Used internally by modifiers.

_checkCanGrantRoles

function _checkCanGrantRoles(
    uint256 resource,
    uint256 roleBitmap,
    address account
) internal view virtual
Reverts if the account does not have the admin roles necessary to grant all the specified roles.

_checkCanRevokeRoles

function _checkCanRevokeRoles(
    uint256 resource,
    uint256 roleBitmap,
    address account
) internal view virtual
Reverts if the account does not have the admin roles necessary to revoke all the specified roles.

_getSettableRoles

function _getSettableRoles(
    uint256 resource,
    address account
) internal view virtual returns (uint256)
Returns the roles (both regular and admin) that an account can grant. An account can grant a regular role if they have the corresponding admin role, and can grant an admin role if they have that same admin role.

_getRevokableRoles

function _getRevokableRoles(
    uint256 resource,
    address account
) internal view virtual returns (uint256)
Returns the roles (including admin roles) that an account can revoke.

Usage Patterns

Checking Multiple Roles

// Check if account has both ROLE_REGISTRAR and ROLE_RENEW
uint256 requiredRoles = RegistryRolesLib.ROLE_REGISTRAR | RegistryRolesLib.ROLE_RENEW;
bool hasAll = registry.hasRoles(nameId, requiredRoles, account);

Granting Multiple Roles at Once

// Grant both ROLE_REGISTRAR and ROLE_RENEW in one transaction
uint256 rolesToGrant = RegistryRolesLib.ROLE_REGISTRAR | RegistryRolesLib.ROLE_RENEW;
registry.grantRoles(nameId, rolesToGrant, account);

Setting Up Role Hierarchy

// First grant admin role to yourself
registry.grantRootRoles(RegistryRolesLib.ROLE_REGISTRAR_ADMIN, msg.sender);

// Now you can grant ROLE_REGISTRAR to others
registry.grantRootRoles(RegistryRolesLib.ROLE_REGISTRAR, otherAccount);

Resource-Specific Permissions

// Grant permission for a specific name only
uint256 nameId = uint256(keccak256("vitalik.eth"));
registry.grantRoles(nameId, RegistryRolesLib.ROLE_RESOLVER, account);

// This permission only applies to "vitalik.eth", not other names

See Also

  • RegistryRolesLib - Registry-specific role definitions
  • Source: contracts/src/access-control/EnhancedAccessControl.sol:26

Build docs developers (and LLMs) love