LOADING

加载过慢请开启缓存 浏览器默认开启

Code review: Openzeppelin - AccessControlDefaultAdminRules

2023/6/26 Solidity Coding

概述:

这是一个扩展自OpenZeppelin的AccessControl合约,实现了特殊规则来管理DEFAULT_ADMIN_ROLE角色的持有者。该角色是系统中具有特权权限的其他角色的管理者。

该合约实现以下风险缓解措施:

  • 部署后,只有一个账户持有DEFAULT_ADMIN_ROLE,除非它被放弃。
  • 将DEFAULT_ADMIN_ROLE转移给另一个账户需要进行两个步骤。
  • 可以在两个步骤之间强制实施可配置的延迟,具有在接受之前取消的能力。
  • 延迟可以通过调度更改,参见changeDefaultAdminDelay。
  • 不可能使用另一个角色来管理DEFAULT_ADMIN_ROLE。

除此之外,还实现了一些访问函数,以及修改默认管理员和默认管理员延迟的方法。

完整代码:

// 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.
 * * Enforces a 2-step process to transfer the `DEFAULT_ADMIN_ROLE` to another account.
 * * Enforces a configurable delay between the two steps, with the ability to cancel before the transfer is accepted.
 * * The delay can be changed by scheduling, see {changeDefaultAdminDelay}.
 * * 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
 *    ) {}
 * }
 * ```
 *
 * _Available since v4.9._
 */
abstract contract AccessControlDefaultAdminRules is IAccessControlDefaultAdminRules, IERC5313, AccessControl {
    // pending admin pair read/written together frequently
    address private _pendingDefaultAdmin;
    uint48 private _pendingDefaultAdminSchedule; // 0 == unset

    uint48 private _currentDelay;
    address private _currentDefaultAdmin;

    // pending delay pair read/written together frequently
    uint48 private _pendingDelay;
    uint48 private _pendingDelaySchedule; // 0 == unset

    /**
     * @dev Sets the initial values for {defaultAdminDelay} and {defaultAdmin} address.
     */
    constructor(uint48 initialDelay, address initialDefaultAdmin) {
        require(initialDefaultAdmin != address(0), "AccessControl: 0 default admin");
        _currentDelay = initialDelay;
        _grantRole(DEFAULT_ADMIN_ROLE, initialDefaultAdmin);
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControlDefaultAdminRules).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev See {IERC5313-owner}.
     */
    function owner() public view virtual returns (address) {
        return defaultAdmin();
    }

    ///
    /// Override AccessControl role management
    ///

    /**
     * @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-renounceRole}.
     *
     * For the `DEFAULT_ADMIN_ROLE`, it only allows renouncing in two steps by first calling
     * {beginDefaultAdminTransfer} to the `address(0)`, so it's required that the {pendingDefaultAdmin} schedule
     * has also passed when calling this function.
     *
     * After its execution, it will not be possible to call `onlyRole(DEFAULT_ADMIN_ROLE)` functions.
     *
     * NOTE: Renouncing `DEFAULT_ADMIN_ROLE` will leave the contract without a {defaultAdmin},
     * thereby disabling any functionality that is only available for it, 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) {
            (address newDefaultAdmin, uint48 schedule) = pendingDefaultAdmin();
            require(
                newDefaultAdmin == address(0) && _isScheduleSet(schedule) && _hasSchedulePassed(schedule),
                "AccessControl: only can renounce in two delayed steps"
            );
            delete _pendingDefaultAdminSchedule;
        }
        super.renounceRole(role, account);
    }

    /**
     * @dev See {AccessControl-_grantRole}.
     *
     * For `DEFAULT_ADMIN_ROLE`, it only allows granting if there isn't already a {defaultAdmin} or if the
     * role has been previously renounced.
     *
     * 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 {AccessControl-_revokeRole}.
     */
    function _revokeRole(bytes32 role, address account) internal virtual override {
        if (role == DEFAULT_ADMIN_ROLE && account == _currentDefaultAdmin) {
            delete _currentDefaultAdmin;
        }
        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);
    }

    ///
    /// AccessControlDefaultAdminRules accessors
    ///

    /**
     * @inheritdoc IAccessControlDefaultAdminRules
     */
    function defaultAdmin() public view virtual returns (address) {
        return _currentDefaultAdmin;
    }

    /**
     * @inheritdoc IAccessControlDefaultAdminRules
     */
    function pendingDefaultAdmin() public view virtual returns (address newAdmin, uint48 schedule) {
        return (_pendingDefaultAdmin, _pendingDefaultAdminSchedule);
    }

    /**
     * @inheritdoc IAccessControlDefaultAdminRules
     */
    function defaultAdminDelay() public view virtual returns (uint48) {
        uint48 schedule = _pendingDelaySchedule;
        return (_isScheduleSet(schedule) && _hasSchedulePassed(schedule)) ? _pendingDelay : _currentDelay;
    }

    /**
     * @inheritdoc IAccessControlDefaultAdminRules
     */
    function pendingDefaultAdminDelay() public view virtual returns (uint48 newDelay, uint48 schedule) {
        schedule = _pendingDelaySchedule;
        return (_isScheduleSet(schedule) && !_hasSchedulePassed(schedule)) ? (_pendingDelay, schedule) : (0, 0);
    }

    /**
     * @inheritdoc IAccessControlDefaultAdminRules
     */
    function defaultAdminDelayIncreaseWait() public view virtual returns (uint48) {
        return 5 days;
    }

    ///
    /// AccessControlDefaultAdminRules public and internal setters for defaultAdmin/pendingDefaultAdmin
    ///

    /**
     * @inheritdoc IAccessControlDefaultAdminRules
     */
    function beginDefaultAdminTransfer(address newAdmin) public virtual onlyRole(DEFAULT_ADMIN_ROLE) {
        _beginDefaultAdminTransfer(newAdmin);
    }

    /**
     * @dev See {beginDefaultAdminTransfer}.
     *
     * Internal function without access restriction.
     */
    function _beginDefaultAdminTransfer(address newAdmin) internal virtual {
        uint48 newSchedule = SafeCast.toUint48(block.timestamp) + defaultAdminDelay();
        _setPendingDefaultAdmin(newAdmin, newSchedule);
        emit DefaultAdminTransferScheduled(newAdmin, newSchedule);
    }

    /**
     * @inheritdoc IAccessControlDefaultAdminRules
     */
    function cancelDefaultAdminTransfer() public virtual onlyRole(DEFAULT_ADMIN_ROLE) {
        _cancelDefaultAdminTransfer();
    }

    /**
     * @dev See {cancelDefaultAdminTransfer}.
     *
     * Internal function without access restriction.
     */
    function _cancelDefaultAdminTransfer() internal virtual {
        _setPendingDefaultAdmin(address(0), 0);
    }

    /**
     * @inheritdoc IAccessControlDefaultAdminRules
     */
    function acceptDefaultAdminTransfer() public virtual {
        (address newDefaultAdmin, ) = pendingDefaultAdmin();
        require(_msgSender() == newDefaultAdmin, "AccessControl: pending admin must accept");
        _acceptDefaultAdminTransfer();
    }

    /**
     * @dev See {acceptDefaultAdminTransfer}.
     *
     * Internal function without access restriction.
     */
    function _acceptDefaultAdminTransfer() internal virtual {
        (address newAdmin, uint48 schedule) = pendingDefaultAdmin();
        require(_isScheduleSet(schedule) && _hasSchedulePassed(schedule), "AccessControl: transfer delay not passed");
        _revokeRole(DEFAULT_ADMIN_ROLE, defaultAdmin());
        _grantRole(DEFAULT_ADMIN_ROLE, newAdmin);
        delete _pendingDefaultAdmin;
        delete _pendingDefaultAdminSchedule;
    }

    ///
    /// AccessControlDefaultAdminRules public and internal setters for defaultAdminDelay/pendingDefaultAdminDelay
    ///

    /**
     * @inheritdoc IAccessControlDefaultAdminRules
     */
    function changeDefaultAdminDelay(uint48 newDelay) public virtual onlyRole(DEFAULT_ADMIN_ROLE) {
        _changeDefaultAdminDelay(newDelay);
    }

    /**
     * @dev See {changeDefaultAdminDelay}.
     *
     * Internal function without access restriction.
     */
    function _changeDefaultAdminDelay(uint48 newDelay) internal virtual {
        uint48 newSchedule = SafeCast.toUint48(block.timestamp) + _delayChangeWait(newDelay);
        _setPendingDelay(newDelay, newSchedule);
        emit DefaultAdminDelayChangeScheduled(newDelay, newSchedule);
    }

    /**
     * @inheritdoc IAccessControlDefaultAdminRules
     */
    function rollbackDefaultAdminDelay() public virtual onlyRole(DEFAULT_ADMIN_ROLE) {
        _rollbackDefaultAdminDelay();
    }

    /**
     * @dev See {rollbackDefaultAdminDelay}.
     *
     * Internal function without access restriction.
     */
    function _rollbackDefaultAdminDelay() internal virtual {
        _setPendingDelay(0, 0);
    }

    /**
     * @dev Returns the amount of seconds to wait after the `newDelay` will
     * become the new {defaultAdminDelay}.
     *
     * The value returned guarantees that if the delay is reduced, it will go into effect
     * after a wait that honors the previously set delay.
     *
     * See {defaultAdminDelayIncreaseWait}.
     */
    function _delayChangeWait(uint48 newDelay) internal view virtual returns (uint48) {
        uint48 currentDelay = defaultAdminDelay();

        // When increasing the delay, we schedule the delay change to occur after a period of "new delay" has passed, up
        // to a maximum given by defaultAdminDelayIncreaseWait, by default 5 days. For example, if increasing from 1 day
        // to 3 days, the new delay will come into effect after 3 days. If increasing from 1 day to 10 days, the new
        // delay will come into effect after 5 days. The 5 day wait period is intended to be able to fix an error like
        // using milliseconds instead of seconds.
        //
        // When decreasing the delay, we wait the difference between "current delay" and "new delay". This guarantees
        // that an admin transfer cannot be made faster than "current delay" at the time the delay change is scheduled.
        // For example, if decreasing from 10 days to 3 days, the new delay will come into effect after 7 days.
        return
            newDelay > currentDelay
                ? uint48(Math.min(newDelay, defaultAdminDelayIncreaseWait())) // no need to safecast, both inputs are uint48
                : currentDelay - newDelay;
    }

    ///
    /// Private setters
    ///

    /**
     * @dev Setter of the tuple for pending admin and its schedule.
     *
     * May emit a DefaultAdminTransferCanceled event.
     */
    function _setPendingDefaultAdmin(address newAdmin, uint48 newSchedule) private {
        (, uint48 oldSchedule) = pendingDefaultAdmin();

        _pendingDefaultAdmin = newAdmin;
        _pendingDefaultAdminSchedule = newSchedule;

        // An `oldSchedule` from `pendingDefaultAdmin()` is only set if it hasn't been accepted.
        if (_isScheduleSet(oldSchedule)) {
            // Emit for implicit cancellations when another default admin was scheduled.
            emit DefaultAdminTransferCanceled();
        }
    }

    /**
     * @dev Setter of the tuple for pending delay and its schedule.
     *
     * May emit a DefaultAdminDelayChangeCanceled event.
     */
    function _setPendingDelay(uint48 newDelay, uint48 newSchedule) private {
        uint48 oldSchedule = _pendingDelaySchedule;

        if (_isScheduleSet(oldSchedule)) {
            if (_hasSchedulePassed(oldSchedule)) {
                // Materialize a virtual delay
                _currentDelay = _pendingDelay;
            } else {
                // Emit for implicit cancellations when another delay was scheduled.
                emit DefaultAdminDelayChangeCanceled();
            }
        }

        _pendingDelay = newDelay;
        _pendingDelaySchedule = newSchedule;
    }

    ///
    /// Private helpers
    ///

    /**
     * @dev Defines if an `schedule` is considered set. For consistency purposes.
     */
    function _isScheduleSet(uint48 schedule) private pure returns (bool) {
        return schedule != 0;
    }

    /**
     * @dev Defines if an `schedule` is considered passed. For consistency purposes.
     */
    function _hasSchedulePassed(uint48 schedule) private view returns (bool) {
        return schedule < block.timestamp;
    }
}

代码分析:

pragma solidity ^0.8.0;

首先,这个代码的作用是指定 Solidity 编译器的版本,以便编译器可以正确解析和编译合约代码。在这个例子中,指定的版本是 0.8.0,表示合约使用 Solidity 0.8.0 或更高版本进行编译。

import "./AccessControl.sol";
import "./IAccessControlDefaultAdminRules.sol";
import "../utils/math/SafeCast.sol";
import "../interfaces/IERC5313.sol";

这段代码是Solidity合约中的导入语句,它导入了以下四个合约:

  • AccessControl.sol:这是一个标准的Solidity合约,提供了访问控制的基本功能。它允许定义角色和权限,并通过函数调用来管理这些角色和权限。
  • IAccessControlDefaultAdminRules.sol:这是一个Solidity接口合约,定义了访问控制默认管理员规则的标准接口。
  • SafeCast.sol:这是一个库合约,提供了一些安全类型转换函数,可以将一些数据类型转换成更小或更大的类型,同时保持数据完整性和安全性。
  • IERC5313.sol:这也是一个Solidity接口合约,定义了代币合约和访问控制合约之间的标准接口。

这些合约都是来自OpenZeppelin Contracts库,用于扩展Solidity中的基本功能,提供更安全和可靠的代码实现。通过导入这些合约,我们可以在我们的合约中使用这些功能,并减少代码量和重复代码。

abstract contract AccessControlDefaultAdminRules is IAccessControlDefaultAdminRules, IERC5313, AccessControl {
    // pending admin pair read/written together frequently
    address private _pendingDefaultAdmin;
    uint48 private _pendingDefaultAdminSchedule; // 0 == unset

    uint48 private _currentDelay;
    address private _currentDefaultAdmin;

    // pending delay pair read/written together frequently
    uint48 private _pendingDelay;
    uint48 private _pendingDelaySchedule; // 0 == unset

这段代码定义了一个名为 AccessControlDefaultAdminRules 的抽象合约。它继承了三个接口合约:IAccessControlDefaultAdminRulesIERC5313AccessControl

代码中声明了一些私有变量,包括 _pendingDefaultAdmin_pendingDefaultAdminSchedule_currentDelay_currentDefaultAdmin_pendingDelay_pendingDelaySchedule。这些变量用于存储关于待处理的管理员转移和延迟更改的信息。

在代码层面上,这些私有变量被声明为合约的状态变量,因为它们是存储在合约存储空间中的,并且可以在合约的不同函数之间共享和修改。

_pendingDefaultAdmin_pendingDefaultAdminSchedule 变量用于存储待处理的默认管理员转移的目标管理员地址和转移时间戳。_currentDelay_currentDefaultAdmin 变量用于存储当前的默认管理员延迟和默认管理员地址。_pendingDelay_pendingDelaySchedule 变量用于存储待处理的默认管理员延迟更改的目标延迟和更改时间戳。

这些变量被声明为私有是为了限制对它们的直接访问,只能通过合约中定义的公共或内部函数来读取和修改它们的值。

这段代码的作用是为AccessControl合约提供了一组特殊规则,用于管理DEFAULT_ADMIN_ROLE角色的转移和延迟更改。它增强了默认的AccessControl合约,并为DEFAULT_ADMIN_ROLE角色的管理引入了一些风险缓解措施。

constructor(uint48 initialDelay, address initialDefaultAdmin) {
        require(initialDefaultAdmin != address(0), "AccessControl: 0 default admin");
        _currentDelay = initialDelay;
        _grantRole(DEFAULT_ADMIN_ROLE, initialDefaultAdmin);
    }

这段代码是合约的构造函数。它接受两个参数:initialDelay(初始延迟)和initialDefaultAdmin(初始默认管理员地址)。以下是代码的作用和实现:

作用:

  1. 验证initialDefaultAdmin不为零地址(address(0))。
  2. 将初始延迟值存储在_currentDelay变量中。
  3. 将DEFAULT_ADMIN_ROLE角色授予initialDefaultAdmin账户。

代码层面上的实现:

  1. 使用require语句确保initialDefaultAdmin不为零地址。如果为零地址,则会抛出异常。
  2. 将initialDelay的值存储在_currentDelay变量中。
  3. 使用_grantRole函数将DEFAULT_ADMIN_ROLE角色授予initialDefaultAdmin账户。这是通过继承的AccessControl合约的内部函数来完成的,它在AccessControl合约中实现了角色授予的逻辑。
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControlDefaultAdminRules).interfaceId || super.supportsInterface(interfaceId);
    }

这段代码是一个公共视图函数supportsInterface,用于检查合约是否支持特定的接口标识符。

函数接受一个bytes4类型的interfaceId作为参数,并返回一个布尔值。它首先比较interfaceId是否等于IAccessControlDefaultAdminRules接口的接口标识符,如果相等,则返回true。否则,它会调用父合约的supportsInterface函数来进一步检查是否支持该接口。

代码层面上的实现是使用了Solidity的类型转换函数type来获取IAccessControlDefaultAdminRules接口的接口标识符。然后,它与传入的interfaceId进行比较,如果相等,则返回true。如果不相等,则调用父合约的supportsInterface函数进行进一步的检查。这样可以确保合约在接口级别上遵循了指定的标准。

function owner() public view virtual returns (address) {
        return defaultAdmin();
    }

这段代码定义了一个公共的视图函数owner(),它返回默认管理员的地址。

在代码层面上,该函数调用了defaultAdmin()函数来获取默认管理员的地址,并将其作为返回值返回。defaultAdmin()是在该合约中定义的另一个函数,用于返回当前默认管理员的地址。

因此,owner()函数的作用是为了与某些标准或约定的接口兼容,将默认管理员地址作为合约的所有者返回。

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);
    }

这段代码实现了grantRole函数,其作用是授予指定角色给指定账户。

代码层面上的实现如下:

  1. 函数声明为public可访问,并使用了virtual和override关键字来表明它是一个虚函数,并覆盖了AccessControl和IAccessControl接口中的对应函数。
  2. 函数接受两个参数:role(角色的bytes32标识符)和account(接收该角色的账户地址)。
  3. 在函数内部,使用require语句检查role是否为DEFAULT_ADMIN_ROLE,默认管理员角色。如果是默认管理员角色,将抛出异常并显示错误消息"AccessControl: can't directly grant default admin role"。
  4. 如果role不是默认管理员角色,则调用super.grantRole(role, account)来将指定角色授予指定账户。这里的super表示调用父合约AccessControl中的grantRole函数。

该代码实现了授予指定角色给指定账户的功能,并在其中添加了一项检查,防止直接授予默认管理员角色。

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);
    }

这段代码是重写了AccessControl合约中的revokeRole函数,并实现了IAccessControl接口。

该函数的作用是撤销指定角色在给定账户上的权限。在执行撤销之前,它首先检查角色是否为DEFAULT_ADMIN_ROLE,如果是,则会抛出异常,因为不能直接撤销默认管理员角色。

在代码层面上,该函数调用了父合约AccessControl的revokeRole函数,通过super.revokeRole(role, account)实现了撤销角色的功能。通过调用父合约的函数,可以确保继承的AccessControl合约中的权限控制逻辑得以执行。

function renounceRole(bytes32 role, address account) public virtual override(AccessControl, IAccessControl) {
        if (role == DEFAULT_ADMIN_ROLE) {
            (address newDefaultAdmin, uint48 schedule) = pendingDefaultAdmin();
            require(
                newDefaultAdmin == address(0) && _isScheduleSet(schedule) && _hasSchedulePassed(schedule),
                "AccessControl: only can renounce in two delayed steps"
            );
            delete _pendingDefaultAdminSchedule;
        }
        super.renounceRole(role, account);
    }

这段代码实现了renounceRole函数,用于放弃指定角色。

在函数中,首先检查传入的角色是否是DEFAULT_ADMIN_ROLE。如果是DEFAULT_ADMIN_ROLE,则进一步检查是否满足以下条件才能放弃角色:

  • newDefaultAdmin必须为零地址,表示没有新的默认管理员。
  • _pendingDefaultAdminSchedule必须设置为一个非零值,表示已经设置了延迟。
  • _pendingDefaultAdminSchedule表示的时间已经过去,即延迟已经生效。

如果满足以上条件,将删除_pendingDefaultAdminSchedule,表示放弃了角色。然后调用父合约的renounceRole函数,将角色从指定的帐户中移除。

这段代码的实现通过条件检查来确保只有在满足特定条件的情况下才能放弃DEFAULT_ADMIN_ROLE角色。这种两步骤的放弃机制提供了额外的安全性,以确保放弃操作是经过充分考虑和确认的。

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);
    }

该代码段是在 AccessControlDefaultAdminRules 合约中的一个内部函数 _grantRole。它覆盖了父合约 AccessControl 中的 _grantRole 函数。

作用:

  • 当授予角色时,该函数首先检查所授予的角色是否是 DEFAULT_ADMIN_ROLE
  • 如果是 DEFAULT_ADMIN_ROLE,则检查当前是否已经有默认管理员(defaultAdmin())。
  • 如果没有默认管理员,则将 account 设置为当前的默认管理员 _currentDefaultAdmin

代码层面上的实现:

  • 函数接受两个参数:role(角色的字节数组标识符)和 account(要授予角色的地址)。
  • 首先,它使用条件语句检查 role 是否等于 DEFAULT_ADMIN_ROLE
  • 如果等于 DEFAULT_ADMIN_ROLE,则使用 require 断言确保当前没有默认管理员。
  • 如果条件满足,将 account 设置为 _currentDefaultAdmin,即设置为新的默认管理员。
  • 最后,通过调用 super._grantRole(role, account) 将角色授予给指定的账户,即调用父合约 AccessControl 中的 _grantRole 函数,实现角色授予的逻辑。

该代码段的作用是在授予角色时,如果授予的角色是 DEFAULT_ADMIN_ROLE,则确保只能有一个默认管理员,并将 account 设置为新的默认管理员。

function _revokeRole(bytes32 role, address account) internal virtual override {
        if (role == DEFAULT_ADMIN_ROLE && account == _currentDefaultAdmin) {
            delete _currentDefaultAdmin;
        }
        super._revokeRole(role, account);
    }

这段代码是AccessControlDefaultAdminRules合约中的一个内部函数 _revokeRole 的实现。该函数用于撤销指定角色的授权。

函数的作用是判断传入的角色是否为DEFAULT_ADMIN_ROLE,并且传入的账户是否为当前默认管理员账户。如果满足这两个条件,就会删除 _currentDefaultAdmin 变量的值,即撤销默认管理员的身份。然后调用 super._revokeRole(role, account),也就是调用父合约(AccessControl合约)的 _revokeRole 函数,实际执行角色的撤销操作。

在代码层面上,该函数首先检查传入的角色是否为DEFAULT_ADMIN_ROLE,并且账户是否为当前默认管理员账户。如果满足条件,则删除 _currentDefaultAdmin 变量的值,即撤销默认管理员身份。然后调用 super._revokeRole(role, account) 来执行其他角色的撤销操作。这样,该函数确保在撤销默认管理员角色时,会首先删除 _currentDefaultAdmin 的值,以避免出现不再拥有默认管理员的情况。

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);
    }

这段代码是一个内部函数 _setRoleAdmin,用于设置角色的管理员角色。它重写了继承自基类的同名函数。

函数的作用是确保不违反默认管理员规则,并调用基类的 _setRoleAdmin 函数来设置角色的管理员角色。

在代码层面上,函数首先使用 require 断言确保要设置的角色不是 DEFAULT_ADMIN_ROLE,以避免违反默认管理员规则。如果断言失败,函数将抛出一个异常。

然后,函数调用 super._setRoleAdmin(role, adminRole),将角色和管理员角色传递给基类的 _setRoleAdmin 函数,实际进行角色管理员的设置。

通过重写和调用基类函数,这段代码确保在设置角色的管理员角色时遵循特定的规则,防止违反默认管理员规则。

function defaultAdmin() public view virtual returns (address) {
        return _currentDefaultAdmin;
    }

这段代码定义了一个公共的视图函数 defaultAdmin(),它返回 _currentDefaultAdmin 的值,即当前的默认管理员地址。

该函数是用于查询当前的默认管理员地址。在合约中,通过 _currentDefaultAdmin 存储和跟踪默认管理员的地址。通过调用 defaultAdmin() 函数,其他合约或外部调用者可以获取当前的默认管理员地址,以便进行必要的操作或查询。

代码实现上,该函数是一个公共函数,具有 viewvirtual 修饰符。view 修饰符表示该函数不会修改合约状态,只返回数据。virtual 修饰符表示该函数可以被子合约重写(覆盖)。函数内部简单地返回 _currentDefaultAdmin 变量的值。

function pendingDefaultAdmin() public view virtual returns (address newAdmin, uint48 schedule) {
        return (_pendingDefaultAdmin, _pendingDefaultAdminSchedule);
    }

这段代码定义了一个公共的视图函数pendingDefaultAdmin(),它返回一个元组,包含了两个变量:newAdminschedule。它的作用是获取挂起的默认管理员和其调度时间。

在代码层面上的实现,该函数简单地返回了两个私有变量_pendingDefaultAdmin_pendingDefaultAdminSchedule。这两个变量分别用于存储挂起的默认管理员地址和调度时间。

这个函数的作用是让外部调用者可以查看当前的挂起默认管理员的地址和调度时间,以便在需要时进行检查或其他操作。

function defaultAdminDelay() public view virtual returns (uint48) {
        uint48 schedule = _pendingDelaySchedule;
        return (_isScheduleSet(schedule) && _hasSchedulePassed(schedule)) ? _pendingDelay : _currentDelay;
    }

这段代码是一个公共的视图函数defaultAdminDelay(),用于返回默认管理员延迟时间。

函数首先将 _pendingDelaySchedule 的值赋给局部变量 schedule。然后,通过检查 schedule 是否设置并且已经过期,来确定返回的延迟时间。如果 schedule 是设置的并且已经过期,则返回 _pendingDelay;否则,返回 _currentDelay

代码层面上的实现非常简单,它通过组合使用变量的值和一些辅助函数(_isScheduleSet()_hasSchedulePassed())来计算出适当的延迟时间,并将其作为结果返回。

function pendingDefaultAdminDelay() public view virtual returns (uint48 newDelay, uint48 schedule) {
        schedule = _pendingDelaySchedule;
        return (_isScheduleSet(schedule) && !_hasSchedulePassed(schedule)) ? (_pendingDelay, schedule) : (0, 0);
    }

这段代码是一个公共的视图函数,用于获取挂起的默认管理员延迟。该函数返回两个值:newDelay(挂起的延迟时间)和schedule(调度时间)。

在代码实现上,首先将_schedule赋值给schedule变量。然后使用条件表达式检查挂起的延迟调度是否已设置且尚未过期。如果是,则返回挂起的延迟值_pendingDelay和调度时间schedule;否则返回(0, 0)。

这段代码的作用是提供一种方式来查询当前挂起的默认管理员延迟,以便在外部进行相应的处理。通过检查挂起的延迟时间和调度,可以确定是否有待处理的延迟更改。

function defaultAdminDelayIncreaseWait() public view virtual returns (uint48) {
        return 5 days;
    }

这段代码定义了一个名为defaultAdminDelayIncreaseWait的公共视图函数,它返回一个uint48类型的值。

函数的作用是返回默认管理员延迟增加的等待时间。在该合约中,当默认管理员延迟增加时,需要等待一段时间才能生效。该函数指定了这段等待时间,返回的是一个以天为单位的时间间隔(uint48类型)。

代码层面上的实现非常简单,它只是返回一个硬编码的数值,即5天。由于函数声明为视图函数,它不会修改合约状态,因此可以在其他函数中安全地调用该函数来获取默认管理员延迟增加的等待时间。

function beginDefaultAdminTransfer(address newAdmin) public virtual onlyRole(DEFAULT_ADMIN_ROLE) {
        _beginDefaultAdminTransfer(newAdmin);
    }

这段代码是一个公共函数beginDefaultAdminTransfer,用于启动将DEFAULT_ADMIN_ROLE转移给另一个地址的过程。

在代码层面上,该函数首先确保调用者具有DEFAULT_ADMIN_ROLE角色(通过onlyRole(DEFAULT_ADMIN_ROLE)修饰符)。然后,它调用了内部函数_beginDefaultAdminTransfer,并将新的管理员地址作为参数传递给它。

函数_beginDefaultAdminTransfer是一个内部函数,用于实际执行默认管理员转移的逻辑。它设置了一个待定的默认管理员(_pendingDefaultAdmin)以及一个待定的转移时间表(_pendingDefaultAdminSchedule)。通过设置这些值,开始了一个延迟过程,其中在转移被接受之前可以取消。

总体而言,这段代码的作用是启动将DEFAULT_ADMIN_ROLE角色转移到另一个地址的过程。在代码层面上,它使用了访问控制修饰符确保只有具有DEFAULT_ADMIN_ROLE角色的账户可以调用该函数,并通过调用内部函数实现了转移过程的逻辑。

function _beginDefaultAdminTransfer(address newAdmin) internal virtual {
        uint48 newSchedule = SafeCast.toUint48(block.timestamp) + defaultAdminDelay();
        _setPendingDefaultAdmin(newAdmin, newSchedule);
        emit DefaultAdminTransferScheduled(newAdmin, newSchedule);
    }

该代码段定义了一个名为 _beginDefaultAdminTransfer 的内部虚拟函数。它用于启动将 DEFAULT_ADMIN_ROLE 转移给新管理员的过程。

函数接受一个新的管理员地址 newAdmin 作为参数。首先,它使用 block.timestamp 获取当前区块的时间戳,然后使用 defaultAdminDelay() 函数获取默认管理员延迟的值。这个延迟值表示在进行管理员转移的两个步骤之间需要等待的时间。

接下来,通过将当前时间戳和延迟值相加,计算出新管理员转移的计划时间 newSchedule。然后,调用 _setPendingDefaultAdmin 函数来设置新管理员和计划时间的 pending 值。

最后,使用 emit 语句触发一个名为 DefaultAdminTransferScheduled 的事件,将新管理员地址和计划时间作为参数传递。

在代码层面上的实现中,_beginDefaultAdminTransfer 函数首先计算新管理员转移的计划时间,然后将这个值传递给 _setPendingDefaultAdmin 函数进行设置。最后,通过触发事件,通知其他相关方转移的计划时间和新管理员地址。

function cancelDefaultAdminTransfer() public virtual onlyRole(DEFAULT_ADMIN_ROLE) {
        _cancelDefaultAdminTransfer();
    }

这段代码定义了一个名为cancelDefaultAdminTransfer的公共虚拟函数,它具有onlyRole(DEFAULT_ADMIN_ROLE)修饰符。这意味着只有拥有DEFAULT_ADMIN_ROLE角色的账户才能调用该函数。

函数的作用是取消正在进行中的默认管理员转移过程。它通过调用内部函数_cancelDefaultAdminTransfer来实现。

在代码层面上,这段代码的实现非常简单。它只是通过调用内部函数来触发取消默认管理员转移的逻辑。这可以帮助确保在转移过程中发生问题或需要终止转移时,可以取消当前的默认管理员转移。

在取消转移时,函数将调用内部函数_cancelDefaultAdminTransfer,该函数会清除保存的正在进行的转移数据,包括_pendingDefaultAdmin_pendingDefaultAdminSchedule变量,将它们重置为初始值。这样,任何正在进行的默认管理员转移都会被取消,并且不再生效。

该函数提供了一种取消默认管理员转移过程的简便方法,并通过调用内部函数来实现取消逻辑。

function _cancelDefaultAdminTransfer() internal virtual {
        _setPendingDefaultAdmin(address(0), 0);
    }

函数 _cancelDefaultAdminTransfer() 是一个内部虚拟函数,用于取消默认管理员转移的操作。该函数将设置待定的默认管理员地址为零地址,并将待定的默认管理员计划时间设置为零。

这个函数的作用是取消之前调用 beginDefaultAdminTransfer() 启动的默认管理员转移操作。当调用 _cancelDefaultAdminTransfer() 函数时,将清除任何已计划的默认管理员转移,并将合约状态恢复到没有待定管理员的状态。

在代码层面上,该函数调用了 _setPendingDefaultAdmin() 函数,并将默认管理员地址设置为零地址,将待定的默认管理员计划时间设置为零。这样做的效果是清除任何待定的默认管理员转移,使合约恢复到默认管理员保持不变的状态。

function acceptDefaultAdminTransfer() public virtual {
        (address newDefaultAdmin, ) = pendingDefaultAdmin();
        require(_msgSender() == newDefaultAdmin, "AccessControl: pending admin must accept");
        _acceptDefaultAdminTransfer();
    }

这段代码是合约中的一个公共函数acceptDefaultAdminTransfer,用于接受将DEFAULT_ADMIN_ROLE转移到新管理员的请求。

代码的作用是首先获取pendingDefaultAdmin()返回的新管理员地址newDefaultAdmin,然后通过_msgSender()获取调用者地址。接下来,使用require语句验证调用者地址必须等于新管理员地址,否则会抛出异常并中止执行,提示"AccessControl: pending admin must accept"。最后,如果验证通过,调用内部函数_acceptDefaultAdminTransfer()来完成管理员角色的转移。

代码层面上的实现如下:

  1. 调用pendingDefaultAdmin()函数,返回一个包含新管理员地址和调度时间的元组。由于函数返回类型是(address, uint48),所以用逗号分隔接收它们。
  2. 使用_msgSender()获取调用者的地址。
  3. 使用require语句验证调用者地址必须等于新管理员地址,如果不相等,则抛出异常并终止执行。
  4. 如果验证通过,调用内部函数_acceptDefaultAdminTransfer()来完成管理员角色的转移。
function _acceptDefaultAdminTransfer() internal virtual {
        (address newAdmin, uint48 schedule) = pendingDefaultAdmin();
        require(_isScheduleSet(schedule) && _hasSchedulePassed(schedule), "AccessControl: transfer delay not passed");
        _revokeRole(DEFAULT_ADMIN_ROLE, defaultAdmin());
        _grantRole(DEFAULT_ADMIN_ROLE, newAdmin);
        delete _pendingDefaultAdmin;
        delete _pendingDefaultAdminSchedule;
    }

这段代码的作用是接受默认管理员转移。在进行默认管理员角色转移的过程中,首先通过调用beginDefaultAdminTransfer函数设置了新的默认管理员和转移计划。然后,在转移计划达到并且转移延迟已经过去后,可以调用acceptDefaultAdminTransfer函数来接受默认管理员的转移。

具体来说,该函数的功能和实现如下:

  1. 获取pendingDefaultAdmin函数返回的新管理员地址newAdmin和转移计划schedule
  2. 确保转移计划已经设置并且已经过了转移延迟,否则抛出异常。
  3. 调用_revokeRole函数来撤销当前默认管理员的DEFAULT_ADMIN_ROLE角色。
  4. 调用_grantRole函数来授予新的默认管理员DEFAULT_ADMIN_ROLE角色。
  5. 删除_pendingDefaultAdmin_pendingDefaultAdminSchedule,清除挂起的默认管理员和转移计划。

这段代码的作用是在满足转移延迟和转移计划条件的情况下,接受默认管理员角色的转移,并将新的默认管理员设置为角色的持有者。这样做的目的是确保在进行默认管理员角色转移时,必须经过一定的延迟时间和条件的验证,以增加系统的安全性和稳定性。

function changeDefaultAdminDelay(uint48 newDelay) public virtual onlyRole(DEFAULT_ADMIN_ROLE) {
        _changeDefaultAdminDelay(newDelay);
    }

这段代码定义了一个名为changeDefaultAdminDelay的公共函数,它允许仅由DEFAULT_ADMIN_ROLE角色调用。函数接受一个newDelay参数,用于更改默认管理员延迟。

函数内部调用了_changeDefaultAdminDelay函数,实现了实际的延迟更改逻辑。

在代码层面上,以下是函数的实现细节:

  • 函数声明为public,表示它可以被其他合约或外部账户调用。
  • 使用virtual关键字表示该函数可以被子合约覆盖。
  • 使用onlyRole(DEFAULT_ADMIN_ROLE)修饰符,确保只有具有DEFAULT_ADMIN_ROLE角色的账户可以调用该函数。
  • 函数接受一个名为newDelay的参数,用于指定新的默认管理员延迟。
  • 函数内部通过调用_changeDefaultAdminDelay(newDelay)来实现实际的延迟更改逻辑。

此段代码的作用是允许具有DEFAULT_ADMIN_ROLE角色的账户更改默认管理员的延迟时间。这可以通过调用changeDefaultAdminDelay函数并提供新的延迟值来完成。这样的延迟更改可以在两个步骤之间的时间间隔内进行,以确保系统的稳定性和安全性。

function _changeDefaultAdminDelay(uint48 newDelay) internal virtual {
        uint48 newSchedule = SafeCast.toUint48(block.timestamp) + _delayChangeWait(newDelay);
        _setPendingDelay(newDelay, newSchedule);
        emit DefaultAdminDelayChangeScheduled(newDelay, newSchedule);
    }

函数_changeDefaultAdminDelay用于更改默认管理员延迟。

以下是函数的实现细节:

  1. uint48 newSchedule = SafeCast.toUint48(block.timestamp) + _delayChangeWait(newDelay);

    • 将当前块的时间戳与_delayChangeWait函数返回的等待时间相加,得到新的计划时间。
    • SafeCast.toUint48函数用于将结果转换为uint48类型。
  2. _setPendingDelay(newDelay, newSchedule);

    • 调用_setPendingDelay函数,设置新的延迟和计划时间。
    • newDelay是新的延迟值,newSchedule是新的计划时间。
  3. emit DefaultAdminDelayChangeScheduled(newDelay, newSchedule);

    • 触发DefaultAdminDelayChangeScheduled事件,传递新的延迟值和计划时间作为参数。

代码层面上的实现说明如下:

  • 函数参数是一个uint48类型的newDelay,表示要设置的新的默认管理员延迟值。
  • 使用SafeCast.toUint48函数将当前块的时间戳与延迟等待时间相加,得到新的计划时间。
  • 调用_setPendingDelay函数,将新的延迟值和计划时间设置为挂起状态。
  • 通过触发事件DefaultAdminDelayChangeScheduled,将新的延迟值和计划时间通知外部。

该函数的作用是设置新的默认管理员延迟,并通过事件向外部通知延迟变更的计划时间。

function rollbackDefaultAdminDelay() public virtual onlyRole(DEFAULT_ADMIN_ROLE) {
        _rollbackDefaultAdminDelay();
    }

这段代码定义了一个名为 rollbackDefaultAdminDelay 的公共虚拟函数,它具有 onlyRole(DEFAULT_ADMIN_ROLE) 修饰符,只有拥有 DEFAULT_ADMIN_ROLE 角色的账户才能调用该函数。该函数的作用是回滚默认管理员延迟设置。

在函数内部,它调用了一个名为 _rollbackDefaultAdminDelay 的内部虚拟函数。这个内部函数实现了回滚默认管理员延迟的逻辑。

代码层面上的实现如下:

  1. rollbackDefaultAdminDelay 函数的可见性为 public,允许外部调用。
  2. virtual 关键字表示该函数可以在子合约中被重写。
  3. onlyRole(DEFAULT_ADMIN_ROLE) 修饰符要求调用者必须拥有 DEFAULT_ADMIN_ROLE 角色,否则会抛出异常并中止执行。
  4. _rollbackDefaultAdminDelay 函数是一个内部虚拟函数,没有公共可见性修饰符,只能在合约内部或子合约中被调用。
function _rollbackDefaultAdminDelay() internal virtual {
        _setPendingDelay(0, 0);
    }

这段代码的作用是将待定的默认管理员延迟设置回初始状态。具体而言,它将 _pendingDelay_pendingDelaySchedule 变量设置为零,相当于取消了之前设置的待定延迟。

在代码层面上,_rollbackDefaultAdminDelay 是一个内部虚拟函数,用于在合约内部调用。它调用了 _setPendingDelay 函数,并将参数设置为零。这将清除待定的延迟设置,重置默认管理员延迟回初始状态。

通过调用 _rollbackDefaultAdminDelay 函数,可以取消之前设置的待定默认管理员延迟,并使默认管理员的延迟恢复为初始状态。

function _delayChangeWait(uint48 newDelay) internal view virtual returns (uint48) {
        uint48 currentDelay = defaultAdminDelay();
        return
            newDelay > currentDelay
                ? uint48(Math.min(newDelay, defaultAdminDelayIncreaseWait())) // no need to safecast, both inputs are uint48
                : currentDelay - newDelay;
    }

这段代码的作用是计算延迟变更的等待时间。它根据当前的延迟和新的延迟值来确定实际的等待时间。

函数首先获取当前的延迟值,使用defaultAdminDelay()函数来获取。接下来,它根据两种情况来计算等待时间:

  1. 当增加延迟时,函数将延迟变更安排在"新延迟"经过的一段时间后进行,最多不超过defaultAdminDelayIncreaseWait()指定的最大值,默认为5天。例如,如果将延迟从1天增加到3天,那么新的延迟将在3天后生效。如果将延迟从1天增加到10天,那么新的延迟将在5天后生效。这个5天的等待期旨在修复使用毫秒而不是秒的错误。

  2. 当减少延迟时,函数将等待"当前延迟"和"新延迟"之间的差值。这确保在延迟变更被安排时,管理员转移不会比"当前延迟"更快进行。例如,如果将延迟从10天减少到3天,那么新的延迟将在7天后生效。

最后,函数返回实际的等待时间,以uint48的格式返回。

在代码层面上的实现中,函数首先获取当前的延迟值,并根据新的延迟值和当前延迟值的比较来确定如何计算等待时间。如果新延迟大于当前延迟,函数选择较小的值作为实际等待时间,但不超过defaultAdminDelayIncreaseWait()函数返回的最大值。如果新延迟小于当前延迟,函数计算两者之间的差值作为实际等待时间。最后,函数返回计算得到的等待时间。函数使用了Math.min()函数来选择较小的值,因为输入都是uint48类型,所以不需要进行安全转换。

function _setPendingDefaultAdmin(address newAdmin, uint48 newSchedule) private {
        (, uint48 oldSchedule) = pendingDefaultAdmin();

        _pendingDefaultAdmin = newAdmin;
        _pendingDefaultAdminSchedule = newSchedule;

        // An `oldSchedule` from `pendingDefaultAdmin()` is only set if it hasn't been accepted.
        if (_isScheduleSet(oldSchedule)) {
            // Emit for implicit cancellations when another default admin was scheduled.
            emit DefaultAdminTransferCanceled();
        }
    }

这段代码是一个私有函数 _setPendingDefaultAdmin,用于设置待定的默认管理员。

该函数接受两个参数:newAdminnewSchedule,分别表示新的默认管理员地址和计划时间。

首先,函数通过调用 pendingDefaultAdmin() 函数获取当前的待定默认管理员的计划时间 oldSchedule

然后,函数将 newAdminnewSchedule 分配给相应的状态变量 _pendingDefaultAdmin_pendingDefaultAdminSchedule

接下来,代码检查是否存在已设置的旧计划时间 oldSchedule。如果存在,则说明已经安排了另一个默认管理员的计划时间,这可能是由于之前的转移被取消。在这种情况下,函数会发出 DefaultAdminTransferCanceled 事件,以通知取消了默认管理员的转移。

总之,该函数用于设置待定的默认管理员,并在存在旧计划时间时触发取消转移的事件。

在代码层面上,该函数的实现很简单。它通过为相应的状态变量赋值来设置待定的默认管理员和计划时间,并通过条件判断和事件触发来处理旧计划时间的情况。

function _setPendingDelay(uint48 newDelay, uint48 newSchedule) private {
        uint48 oldSchedule = _pendingDelaySchedule;

        if (_isScheduleSet(oldSchedule)) {
            if (_hasSchedulePassed(oldSchedule)) {
                // Materialize a virtual delay
                _currentDelay = _pendingDelay;
            } else {
                // Emit for implicit cancellations when another delay was scheduled.
                emit DefaultAdminDelayChangeCanceled();
            }
        }

        _pendingDelay = newDelay;
        _pendingDelaySchedule = newSchedule;
    }

这段代码的作用是设置待处理的延迟(pending delay)和其调度时间(schedule)。该函数用于在合约内部管理默认管理员延迟的变更。

以下是代码的实现层面解析:

  • 首先,函数接收两个参数:newDelay(新的延迟值)和newSchedule(新的调度时间)。
  • 然后,它声明一个名为oldSchedule的局部变量,用于存储当前待处理的延迟的调度时间。
  • 接下来,它使用_isScheduleSet函数检查旧的调度时间是否已设置。如果设置了旧的调度时间,那么执行以下操作:
    • 使用_hasSchedulePassed函数检查旧的调度时间是否已过期。如果已过期,说明之前预定的延迟变更已生效,那么将当前延迟值(_currentDelay)设置为待处理的延迟值(_pendingDelay)。这是通过将_currentDelay赋值为_pendingDelay来实现的。
    • 如果旧的调度时间未过期,说明已经有另一个延迟变更被预定,那么会触发DefaultAdminDelayChangeCanceled事件。这是通过emit DefaultAdminDelayChangeCanceled()语句来实现的。
  • 最后,函数将_pendingDelay设置为新的延迟值,将_pendingDelaySchedule设置为新的调度时间。

总体而言,该函数的作用是处理默认管理员延迟的变更。它检查旧的调度时间,如果有必要,更新当前的延迟值,并设置新的待处理的延迟和调度时间。

function _isScheduleSet(uint48 schedule) private pure returns (bool) {
        return schedule != 0;
    }

这段代码是一个私有函数_isScheduleSet,它接受一个uint48类型的参数schedule,并返回一个布尔值。

函数的作用是判断给定的schedule是否被设置。在这里,如果schedule的值不等于0,则被认为是被设置了。如果schedule为0,则被认为是未被设置。

代码层面上的实现非常简单。它使用了纯函数修饰符pure,表示该函数不会修改合约状态或读取合约状态的任何值。函数内部只有一行代码,通过比较schedule和0的值来判断schedule是否被设置。如果schedule不等于0,则返回true;否则,返回false

function _hasSchedulePassed(uint48 schedule) private view returns (bool) {
        return schedule < block.timestamp;
    }

这段代码定义了一个名为 _hasSchedulePassed 的私有视图函数,用于判断一个给定的时间戳(schedule)是否已经过去。

函数内部通过比较给定时间戳(schedule)与当前区块的时间戳(block.timestamp)的大小关系来确定是否已经过去。如果给定时间戳小于当前区块的时间戳,则函数返回true,表示时间已经过去。否则,函数返回false,表示时间尚未过去。

这个函数的作用是用于判断在访问控制合约中定义的延迟是否已经过去。通过使用这个函数,可以确保在执行某些操作之前必须等待一定的时间,以确保延迟已经到期。

在代码层面上的实现非常简单,只是一个简单的比较操作。它使用了Solidity提供的内置变量block.timestamp来获取当前区块的时间戳,并将其与给定的时间戳进行比较。如果给定时间戳小于当前区块的时间戳,则返回true;否则返回false。该函数是一个视图函数,不会修改合约状态。