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.
113 lines
4.6 KiB
113 lines
4.6 KiB
// SPDX-License-Identifier: MIT
|
|
// OpenZeppelin Contracts (last updated v5.1.0) (access/manager/AccessManaged.sol)
|
|
|
|
pragma solidity ^0.8.20;
|
|
|
|
import {IAuthority} from "./IAuthority.sol";
|
|
import {AuthorityUtils} from "./AuthorityUtils.sol";
|
|
import {IAccessManager} from "./IAccessManager.sol";
|
|
import {IAccessManaged} from "./IAccessManaged.sol";
|
|
import {Context} from "../../utils/Context.sol";
|
|
|
|
/**
|
|
* @dev This contract module makes available a {restricted} modifier. Functions decorated with this modifier will be
|
|
* permissioned according to an "authority": a contract like {AccessManager} that follows the {IAuthority} interface,
|
|
* implementing a policy that allows certain callers to access certain functions.
|
|
*
|
|
* IMPORTANT: The `restricted` modifier should never be used on `internal` functions, judiciously used in `public`
|
|
* functions, and ideally only used in `external` functions. See {restricted}.
|
|
*/
|
|
abstract contract AccessManaged is Context, IAccessManaged {
|
|
address private _authority;
|
|
|
|
bool private _consumingSchedule;
|
|
|
|
/**
|
|
* @dev Initializes the contract connected to an initial authority.
|
|
*/
|
|
constructor(address initialAuthority) {
|
|
_setAuthority(initialAuthority);
|
|
}
|
|
|
|
/**
|
|
* @dev Restricts access to a function as defined by the connected Authority for this contract and the
|
|
* caller and selector of the function that entered the contract.
|
|
*
|
|
* [IMPORTANT]
|
|
* ====
|
|
* In general, this modifier should only be used on `external` functions. It is okay to use it on `public`
|
|
* functions that are used as external entry points and are not called internally. Unless you know what you're
|
|
* doing, it should never be used on `internal` functions. Failure to follow these rules can have critical security
|
|
* implications! This is because the permissions are determined by the function that entered the contract, i.e. the
|
|
* function at the bottom of the call stack, and not the function where the modifier is visible in the source code.
|
|
* ====
|
|
*
|
|
* [WARNING]
|
|
* ====
|
|
* Avoid adding this modifier to the https://docs.soliditylang.org/en/v0.8.20/contracts.html#receive-ether-function[`receive()`]
|
|
* function or the https://docs.soliditylang.org/en/v0.8.20/contracts.html#fallback-function[`fallback()`]. These
|
|
* functions are the only execution paths where a function selector cannot be unambiguously determined from the calldata
|
|
* since the selector defaults to `0x00000000` in the `receive()` function and similarly in the `fallback()` function
|
|
* if no calldata is provided. (See {_checkCanCall}).
|
|
*
|
|
* The `receive()` function will always panic whereas the `fallback()` may panic depending on the calldata length.
|
|
* ====
|
|
*/
|
|
modifier restricted() {
|
|
_checkCanCall(_msgSender(), _msgData());
|
|
_;
|
|
}
|
|
|
|
/// @inheritdoc IAccessManaged
|
|
function authority() public view virtual returns (address) {
|
|
return _authority;
|
|
}
|
|
|
|
/// @inheritdoc IAccessManaged
|
|
function setAuthority(address newAuthority) public virtual {
|
|
address caller = _msgSender();
|
|
if (caller != authority()) {
|
|
revert AccessManagedUnauthorized(caller);
|
|
}
|
|
if (newAuthority.code.length == 0) {
|
|
revert AccessManagedInvalidAuthority(newAuthority);
|
|
}
|
|
_setAuthority(newAuthority);
|
|
}
|
|
|
|
/// @inheritdoc IAccessManaged
|
|
function isConsumingScheduledOp() public view returns (bytes4) {
|
|
return _consumingSchedule ? this.isConsumingScheduledOp.selector : bytes4(0);
|
|
}
|
|
|
|
/**
|
|
* @dev Transfers control to a new authority. Internal function with no access restriction. Allows bypassing the
|
|
* permissions set by the current authority.
|
|
*/
|
|
function _setAuthority(address newAuthority) internal virtual {
|
|
_authority = newAuthority;
|
|
emit AuthorityUpdated(newAuthority);
|
|
}
|
|
|
|
/**
|
|
* @dev Reverts if the caller is not allowed to call the function identified by a selector. Panics if the calldata
|
|
* is less than 4 bytes long.
|
|
*/
|
|
function _checkCanCall(address caller, bytes calldata data) internal virtual {
|
|
(bool immediate, uint32 delay) = AuthorityUtils.canCallWithDelay(
|
|
authority(),
|
|
caller,
|
|
address(this),
|
|
bytes4(data[0:4])
|
|
);
|
|
if (!immediate) {
|
|
if (delay > 0) {
|
|
_consumingSchedule = true;
|
|
IAccessManager(authority()).consumeScheduledOp(caller, data);
|
|
_consumingSchedule = false;
|
|
} else {
|
|
revert AccessManagedUnauthorized(caller);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|