mirror of openzeppelin-contracts
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openzeppelin-contracts/contracts/access/AccessControlDefaultAdminRu...

241 lines
8.7 KiB

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (access/AccessControlDefaultAdminRules.sol)
pragma solidity ^0.8.0;
import "./AccessControl.sol";
import "./IAccessControlDefaultAdminRules.sol";
import "../utils/math/SafeCast.sol";
import "../interfaces/IERC5313.sol";
/**
* @dev Extension of {AccessControl} that allows specifying special rules to manage
* the `DEFAULT_ADMIN_ROLE` holder, which is a sensitive role with special permissions
* over other roles that may potentially have privileged rights in the system.
*
* If a specific role doesn't have an admin role assigned, the holder of the
* `DEFAULT_ADMIN_ROLE` will have the ability to grant it and revoke it.
*
* This contract implements the following risk mitigations on top of {AccessControl}:
*
* * Only one account holds the `DEFAULT_ADMIN_ROLE` since deployment until it's potentially renounced.
* * Enforce a 2-step process to transfer the `DEFAULT_ADMIN_ROLE` to another account.
* * Enforce a configurable delay between the two steps, with the ability to cancel in between.
* - Even after the timer has passed to avoid locking it forever.
* * It is not possible to use another role to manage the `DEFAULT_ADMIN_ROLE`.
*
* Example usage:
*
* ```solidity
* contract MyToken is AccessControlDefaultAdminRules {
* constructor() AccessControlDefaultAdminRules(
* 3 days,
* msg.sender // Explicit initial `DEFAULT_ADMIN_ROLE` holder
* ) {}
*}
* ```
*
* NOTE: The `delay` can only be set in the constructor and is fixed thereafter.
*
* _Available since v4.9._
*/
abstract contract AccessControlDefaultAdminRules is IAccessControlDefaultAdminRules, IERC5313, AccessControl {
uint48 private immutable _defaultAdminDelay;
address private _currentDefaultAdmin;
address private _pendingDefaultAdmin;
uint48 private _defaultAdminTransferDelayedUntil;
/**
* @dev Sets the initial values for {defaultAdminDelay} in seconds and {defaultAdmin}.
*
* The `defaultAdminDelay` value is immutable. It can only be set at the constructor.
*/
constructor(uint48 defaultAdminDelay_, address initialDefaultAdmin) {
_defaultAdminDelay = defaultAdminDelay_;
_grantRole(DEFAULT_ADMIN_ROLE, initialDefaultAdmin);
}
/**
* @dev See {IERC5313-owner}.
*/
function owner() public view virtual returns (address) {
return defaultAdmin();
}
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function defaultAdminDelay() public view virtual returns (uint48) {
return _defaultAdminDelay;
}
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function defaultAdmin() public view virtual returns (address) {
return _currentDefaultAdmin;
}
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function pendingDefaultAdmin() public view virtual returns (address) {
return _pendingDefaultAdmin;
}
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function defaultAdminTransferDelayedUntil() public view virtual returns (uint48) {
return _defaultAdminTransferDelayedUntil;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControlDefaultAdminRules).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function beginDefaultAdminTransfer(address newAdmin) public virtual onlyRole(DEFAULT_ADMIN_ROLE) {
_beginDefaultAdminTransfer(newAdmin);
}
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function acceptDefaultAdminTransfer() public virtual {
require(_msgSender() == pendingDefaultAdmin(), "AccessControl: pending admin must accept");
_acceptDefaultAdminTransfer();
}
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function cancelDefaultAdminTransfer() public virtual onlyRole(DEFAULT_ADMIN_ROLE) {
_resetDefaultAdminTransfer();
}
/**
* @dev Revokes `role` from the calling account.
*
* For `DEFAULT_ADMIN_ROLE`, only allows renouncing in two steps, so it's required
* that the {defaultAdminTransferDelayedUntil} has passed and the pending default admin is the zero address.
* After its execution, it will not be possible to call `onlyRole(DEFAULT_ADMIN_ROLE)`
* functions.
*
* For other roles, see {AccessControl-renounceRole}.
*
* NOTE: Renouncing `DEFAULT_ADMIN_ROLE` will leave the contract without a defaultAdmin,
* thereby disabling any functionality that is only available to the default admin, and the
* possibility of reassigning a non-administrated role.
*/
function renounceRole(bytes32 role, address account) public virtual override(AccessControl, IAccessControl) {
if (role == DEFAULT_ADMIN_ROLE) {
require(
pendingDefaultAdmin() == address(0) && _hasDefaultAdminTransferDelayPassed(),
"AccessControl: only can renounce in two delayed steps"
);
}
super.renounceRole(role, account);
}
/**
* @dev See {AccessControl-grantRole}. Reverts for `DEFAULT_ADMIN_ROLE`.
*/
function grantRole(bytes32 role, address account) public virtual override(AccessControl, IAccessControl) {
require(role != DEFAULT_ADMIN_ROLE, "AccessControl: can't directly grant default admin role");
super.grantRole(role, account);
}
/**
* @dev See {AccessControl-revokeRole}. Reverts for `DEFAULT_ADMIN_ROLE`.
*/
function revokeRole(bytes32 role, address account) public virtual override(AccessControl, IAccessControl) {
require(role != DEFAULT_ADMIN_ROLE, "AccessControl: can't directly revoke default admin role");
super.revokeRole(role, account);
}
/**
* @dev See {AccessControl-_setRoleAdmin}. Reverts for `DEFAULT_ADMIN_ROLE`.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual override {
require(role != DEFAULT_ADMIN_ROLE, "AccessControl: can't violate default admin rules");
super._setRoleAdmin(role, adminRole);
}
/**
* @dev Grants `role` to `account`.
*
* For `DEFAULT_ADMIN_ROLE`, it only allows granting if there isn't already a role's holder
* or if the role has been previously renounced.
*
* For other roles, see {AccessControl-renounceRole}.
*
* NOTE: Exposing this function through another mechanism may make the
* `DEFAULT_ADMIN_ROLE` assignable again. Make sure to guarantee this is
* the expected behavior in your implementation.
*/
function _grantRole(bytes32 role, address account) internal virtual override {
if (role == DEFAULT_ADMIN_ROLE) {
require(defaultAdmin() == address(0), "AccessControl: default admin already granted");
_currentDefaultAdmin = account;
}
super._grantRole(role, account);
}
/**
* @dev See {acceptDefaultAdminTransfer}.
*
* Internal function without access restriction.
*/
function _acceptDefaultAdminTransfer() internal virtual {
require(_hasDefaultAdminTransferDelayPassed(), "AccessControl: transfer delay not passed");
_revokeRole(DEFAULT_ADMIN_ROLE, defaultAdmin());
_grantRole(DEFAULT_ADMIN_ROLE, pendingDefaultAdmin());
_resetDefaultAdminTransfer();
}
/**
* @dev See {beginDefaultAdminTransfer}.
*
* Internal function without access restriction.
*/
function _beginDefaultAdminTransfer(address newAdmin) internal virtual {
_defaultAdminTransferDelayedUntil = SafeCast.toUint48(block.timestamp) + defaultAdminDelay();
_pendingDefaultAdmin = newAdmin;
emit DefaultAdminRoleChangeStarted(pendingDefaultAdmin(), defaultAdminTransferDelayedUntil());
}
/**
* @dev See {AccessControl-_revokeRole}.
*/
function _revokeRole(bytes32 role, address account) internal virtual override {
if (role == DEFAULT_ADMIN_ROLE) {
delete _currentDefaultAdmin;
}
super._revokeRole(role, account);
}
/**
* @dev Resets the pending default admin and delayed until.
*/
function _resetDefaultAdminTransfer() private {
delete _pendingDefaultAdmin;
delete _defaultAdminTransferDelayedUntil;
}
/**
* @dev Checks if a {defaultAdminTransferDelayedUntil} has been set and passed.
*/
function _hasDefaultAdminTransferDelayPassed() private view returns (bool) {
uint48 delayedUntil = defaultAdminTransferDelayedUntil();
return delayedUntil > 0 && delayedUntil < block.timestamp;
}
}