CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-openzeppelin--contracts

Secure Smart Contract library for Solidity with battle-tested implementations of token standards, access control, governance, and essential utilities for building decentralized applications.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

access-control.mddocs/

Access Control

Comprehensive access control mechanisms including single-owner patterns and flexible role-based access control systems for secure smart contract administration.

Capabilities

Single Owner Pattern

Simple ownership model with transfer and renouncement capabilities for contracts requiring single administrator access.

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 */
abstract contract Ownable is Context {
    /**
     * @dev Sets the initial owner to the address provided by the deployer
     */
    constructor(address initialOwner);
    
    /**
     * @dev Returns the address of the current owner
     */
    function owner() public view virtual returns (address);
    
    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`)
     * Can only be called by the current owner
     */
    function transferOwnership(address newOwner) public virtual onlyOwner;
    
    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner
     */
    function renounceOwnership() public virtual onlyOwner;
    
    /**
     * @dev Throws if called by any account other than the owner
     */
    modifier onlyOwner();
}

Usage Example:

import "@openzeppelin/contracts/access/Ownable.sol";

contract MyContract is Ownable {
    uint256 private _value;
    
    constructor(address initialOwner) Ownable(initialOwner) {}
    
    function setValue(uint256 newValue) public onlyOwner {
        _value = newValue;
    }
    
    function getValue() public view returns (uint256) {
        return _value;
    }
}

Two-Step Ownership Transfer

Enhanced ownership pattern that requires new owner acceptance to prevent accidental transfers to invalid addresses.

/**
 * @dev Contract module which provides access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions, and ownership transfer is a two-step process.
 */
abstract contract Ownable2Step is Ownable {
    /**
     * @dev Returns the address of the pending owner
     */
    function pendingOwner() public view virtual returns (address);
    
    /**
     * @dev Starts the ownership transfer of the contract to a new account
     * Replaces the pending transfer if there is one
     */
    function transferOwnership(address newOwner) public virtual override onlyOwner;
    
    /**
     * @dev The new owner accepts the ownership transfer
     */
    function acceptOwnership() public virtual;
}

Usage Example:

import "@openzeppelin/contracts/access/Ownable2Step.sol";

contract SecureContract is Ownable2Step {
    constructor(address initialOwner) Ownable(initialOwner) {}
    
    // Contract functions requiring ownership
    function sensitiveOperation() public onlyOwner {
        // Protected operation
    }
}

// Transfer process:
// 1. Current owner calls transferOwnership(newOwnerAddress)
// 2. New owner calls acceptOwnership() to complete transfer

Role-Based Access Control

Flexible role-based access control system supporting multiple roles with hierarchical administration.

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. Roles are referred to by their `bytes32` identifier.
 */
abstract contract AccessControl is Context, IAccessControl, ERC165 {
    /**
     * @dev Returns `true` if `account` has been granted `role`
     */
    function hasRole(bytes32 role, address account) public view virtual returns (bool);
    
    /**
     * @dev Returns the admin role that controls `role`
     */
    function getRoleAdmin(bytes32 role) public view virtual returns (bytes32);
    
    /**
     * @dev Grants `role` to `account`
     * If `account` had not been already granted `role`, emits a {RoleGranted} event
     */
    function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role));
    
    /**
     * @dev Revokes `role` from `account`
     * If `account` had been granted `role`, emits a {RoleRevoked} event
     */
    function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role));
    
    /**
     * @dev Revokes `role` from the calling account
     */
    function renounceRole(bytes32 role, address callerConfirmation) public virtual;
    
    /**
     * @dev Sets `adminRole` as ``role``'s admin role
     * Internal function without access restriction
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual;
    
    /**
     * @dev Grants `role` to `account`
     * Internal function without access restriction
     */
    function _grantRole(bytes32 role, address account) internal virtual;
    
    /**
     * @dev Revokes `role` from `account`
     * Internal function without access restriction
     */
    function _revokeRole(bytes32 role, address account) internal virtual;
    
    /**
     * @dev Modifier that checks that an account has a specific role
     */
    modifier onlyRole(bytes32 role);
}

Usage Example:

import "@openzeppelin/contracts/access/AccessControl.sol";

contract MyContract is AccessControl {
    bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
    bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE");
    
    constructor(address defaultAdmin) {
        _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);
    }
    
    function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) {
        // Minting logic
    }
    
    function burn(uint256 amount) public onlyRole(BURNER_ROLE) {
        // Burning logic
    }
    
    function setupRoles(address minter, address burner) public onlyRole(DEFAULT_ADMIN_ROLE) {
        _grantRole(MINTER_ROLE, minter);
        _grantRole(BURNER_ROLE, burner);
    }
}

Enhanced Access Control Extensions

Advanced access control features including enumerable roles and default admin rules.

// Enumerable Access Control - Track role members
abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {
    /**
     * @dev Returns one of the accounts that have `role`
     */
    function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address);
    
    /**
     * @dev Returns the number of accounts that have `role`
     */
    function getRoleMemberCount(bytes32 role) public view virtual returns (uint256);
    
    /**
     * @dev Returns an array of all accounts that have `role`
     */
    function getRoleMembers(bytes32 role) public view virtual returns (address[] memory);
}

// Default Admin Rules - Enhanced admin role management
abstract contract AccessControlDefaultAdminRules is IAccessControlDefaultAdminRules, AccessControl {
    /**
     * @dev Returns the address of the current default admin
     */
    function defaultAdmin() public view virtual returns (address);
    
    /**
     * @dev Returns the address of the pending default admin
     */
    function pendingDefaultAdmin() public view virtual returns (address);
    
    /**
     * @dev Returns the remaining time in seconds until the default admin transfer delay ends
     */
    function defaultAdminDelayIncreaseWait() public view virtual returns (uint48);
    
    /**
     * @dev Starts a default admin transfer by setting a pending default admin
     */
    function beginDefaultAdminTransfer(address newAdmin) public virtual onlyRole(DEFAULT_ADMIN_ROLE);
    
    /**
     * @dev Accepts the pending default admin transfer
     */
    function acceptDefaultAdminTransfer() public virtual;
    
    /**
     * @dev Cancels a pending default admin transfer
     */
    function cancelDefaultAdminTransfer() public virtual onlyRole(DEFAULT_ADMIN_ROLE);
}

Access Manager

Advanced access management system for complex authorization scenarios with time-based controls.

/**
 * @dev AccessManager is a central contract to store the permissions of a system.
 * It provides a flexible and modular access control mechanism.
 */
contract AccessManager is Context, Multicall, IAccessManager {
    /**
     * @dev Check if an account can perform an operation
     */
    function canCall(address caller, address target, bytes4 selector) public view virtual returns (bool immediate, uint32 delay);
    
    /**
     * @dev Get the role of an account
     */
    function getAccess(uint64 roleId, address account) public view virtual returns (uint48 since, uint32 currentDelay, uint32 pendingDelay, uint48 effect);
    
    /**
     * @dev Grant a role to an account
     */
    function grantRole(uint64 roleId, address account, uint32 executionDelay) public virtual onlyAuthorized;
    
    /**
     * @dev Revoke a role from an account
     */
    function revokeRole(uint64 roleId, address account) public virtual onlyAuthorized;
    
    /**
     * @dev Set the role required to call a function
     */
    function setTargetFunctionRole(address target, bytes4[] calldata selectors, uint64 roleId) public virtual onlyAuthorized;
    
    /**
     * @dev Schedule an operation that is subject to a delay
     */
    function schedule(address target, bytes calldata data, uint48 when) public virtual returns (bytes32 operationId);
    
    /**
     * @dev Execute a scheduled operation
     */
    function execute(address target, bytes calldata data) public payable virtual returns (bytes32 operationId);
    
    /**
     * @dev Cancel a scheduled operation
     */
    function cancel(address caller, address target, bytes calldata data) public virtual returns (bytes32 operationId);
}

Access Control Interfaces

// Core Access Control Interface
interface IAccessControl {
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
    
    function hasRole(bytes32 role, address account) external view returns (bool);
    function getRoleAdmin(bytes32 role) external view returns (bytes32);
    function grantRole(bytes32 role, address account) external;
    function revokeRole(bytes32 role, address account) external;
    function renounceRole(bytes32 role, address callerConfirmation) external;
}

// Enumerable Access Control Interface
interface IAccessControlEnumerable is IAccessControl {
    function getRoleMember(bytes32 role, uint256 index) external view returns (address);
    function getRoleMemberCount(bytes32 role) external view returns (uint256);
}

// Default Admin Rules Interface
interface IAccessControlDefaultAdminRules is IAccessControl {
    event DefaultAdminTransferScheduled(address indexed newAdmin, uint48 acceptSchedule);
    event DefaultAdminTransferCanceled();
    event DefaultAdminDelayChangeScheduled(uint48 newDelay, uint48 effectSchedule);
    event DefaultAdminDelayChangeCanceled();
    
    function defaultAdmin() external view returns (address);
    function pendingDefaultAdmin() external view returns (address, uint48);
    function defaultAdminDelay() external view returns (uint48);
    function pendingDefaultAdminDelay() external view returns (uint48, uint48);
    function defaultAdminDelayIncreaseWait() external view returns (uint48);
}

// Access Manager Interface
interface IAccessManager {
    event RoleGranted(uint64 indexed roleId, address indexed account, uint32 delay, uint48 since, address indexed caller);
    event RoleRevoked(uint64 indexed roleId, address indexed account, address indexed caller);
    event OperationScheduled(bytes32 indexed operationId, uint32 indexed nonce, uint48 schedule, address caller, address target, bytes data);
    event OperationExecuted(bytes32 indexed operationId, uint32 indexed nonce, address caller, address target, bytes data);
    event OperationCanceled(bytes32 indexed operationId, uint32 indexed nonce, address caller, address target, bytes data);
    
    function canCall(address caller, address target, bytes4 selector) external view returns (bool allowed, uint32 delay);
    function expiration() external view returns (uint32);
    function minSetback() external view returns (uint32);
    function isTargetClosed(address target) external view returns (bool);
    function getTargetFunctionRole(address target, bytes4 selector) external view returns (uint64);
    function getAccess(uint64 roleId, address account) external view returns (uint48, uint32, uint32, uint48);
    function hasRole(uint64 roleId, address account) external view returns (bool, uint32);
}

Common Patterns

Basic Access Control Pattern

import "@openzeppelin/contracts/access/Ownable.sol";

contract SimpleContract is Ownable {
    mapping(address => bool) public authorized;
    
    constructor(address initialOwner) Ownable(initialOwner) {}
    
    function authorizeUser(address user) public onlyOwner {
        authorized[user] = true;
    }
    
    function revokeUser(address user) public onlyOwner {
        authorized[user] = false;
    }
    
    function protectedFunction() public {
        require(authorized[msg.sender], "Not authorized");
        // Function logic
    }
}

Multi-Role Pattern

import "@openzeppelin/contracts/access/AccessControl.sol";

contract MultiRoleContract is AccessControl {
    bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
    bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE");
    bytes32 public constant USER_ROLE = keccak256("USER_ROLE");
    
    constructor(address defaultAdmin) {
        _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);
        _grantRole(ADMIN_ROLE, defaultAdmin);
        
        // Set role hierarchy
        _setRoleAdmin(OPERATOR_ROLE, ADMIN_ROLE);
        _setRoleAdmin(USER_ROLE, OPERATOR_ROLE);
    }
    
    function adminFunction() public onlyRole(ADMIN_ROLE) {
        // Admin-only functionality
    }
    
    function operatorFunction() public onlyRole(OPERATOR_ROLE) {
        // Operator functionality
    }
    
    function userFunction() public onlyRole(USER_ROLE) {
        // User functionality
    }
}

Combined Access Control Pattern

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";

contract HybridAccessContract is Ownable, AccessControl {
    bytes32 public constant MANAGER_ROLE = keccak256("MANAGER_ROLE");
    
    constructor(address initialOwner) Ownable(initialOwner) {
        _grantRole(DEFAULT_ADMIN_ROLE, initialOwner);
    }
    
    // Owner can grant roles
    function grantManagerRole(address account) public onlyOwner {
        grantRole(MANAGER_ROLE, account);
    }
    
    // Managers can perform operations
    function manageOperation() public onlyRole(MANAGER_ROLE) {
        // Management functionality
    }
    
    // Owner retains ultimate control
    function emergencyFunction() public onlyOwner {
        // Emergency functionality
    }
}

Install with Tessl CLI

npx tessl i tessl/npm-openzeppelin--contracts

docs

access-control.md

account-abstraction.md

finance.md

governance.md

index.md

mathematical-utilities.md

meta-transactions.md

proxy-patterns.md

security-utilities.md

token-standards.md

tile.json