patternjavascriptTip
OpenZeppelin: using AccessControl instead of Ownable for fine-grained permissions
Viewed 0 times
OpenZeppelin Contracts 5.x
OpenZeppelinAccessControlMINTER_ROLEonlyRoleRBACroles
Error Messages
Problem
Ownable provides a single owner address for admin functions, but many contracts need multiple roles with different permissions.
Solution
Use OpenZeppelin's AccessControl. Define bytes32 role constants, grant them in the constructor, and guard functions with onlyRole.
import '@openzeppelin/contracts/access/AccessControl.sol';
bytes32 public constant MINTER_ROLE = keccak256('MINTER_ROLE');
_grantRole(MINTER_ROLE, minter);
function mint(address to, uint256 amount) external onlyRole(MINTER_ROLE) { ... }Why
Role-based access control is more flexible and follows the principle of least privilege — each actor only has the permissions it needs.
Gotchas
- DEFAULT_ADMIN_ROLE must be carefully managed — the account with this role can grant/revoke all other roles
- AccessControlDefaultAdminRules adds delays to admin transfers for safer governance
- Role hashes are just keccak256 of the string — use constant definitions to avoid typos across contracts
Code Snippets
AccessControl with multiple roles
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import '@openzeppelin/contracts/access/AccessControl.sol';
import '@openzeppelin/contracts/token/ERC20/ERC20.sol';
contract RoleToken is ERC20, AccessControl {
bytes32 public constant MINTER_ROLE = keccak256('MINTER_ROLE');
bytes32 public constant PAUSER_ROLE = keccak256('PAUSER_ROLE');
constructor(address admin, address minter) ERC20('RoleToken', 'RT') {
_grantRole(DEFAULT_ADMIN_ROLE, admin);
_grantRole(MINTER_ROLE, minter);
}
function mint(address to, uint256 amount) external onlyRole(MINTER_ROLE) {
_mint(to, amount);
}
}Context
Building contracts with multiple admin functions requiring different permission levels
Revisions (0)
No revisions yet.