AccessManager源码//SPDX-License-Identifier:MIT//OpenZeppelinContracts(lastupdatedv5.1.0)(access/manager/AccessManager.sol)pragmasolidity^
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (access/manager/AccessManager.sol)
pragma solidity ^0.8.20;
import {IAccessManager} from "./IAccessManager.sol";
import {IAccessManaged} from "./IAccessManaged.sol";
import {Address} from "../../utils/Address.sol";
import {Context} from "../../utils/Context.sol";
import {Multicall} from "../../utils/Multicall.sol";
import {Math} from "../../utils/math/Math.sol";
import {Time} from "../../utils/types/Time.sol";
contract AccessManager is Context, Multicall, IAccessManager {
using Time for *;
/**
* 设置某个目标合约地址的访问控制
* allowedRoles: 每个 selector(函数选择器)映射到一个 roleId,只有拥有该 roleId 的用户可访问该函数
* adminDelay: 管理员延迟,表示管理员对该目标合约的操作延迟
* closed: 是否关闭该目标合约的访问控制
*/
struct TargetConfig {
mapping(bytes4 selector => uint64 roleId) allowedRoles;
Time.Delay adminDelay;
bool closed;
}
/**
* 某个账户在某个角色中的访问情况(被授予的情况)
* since: 该账户自何时起拥有该权限(since == 0 表示未被授权; since > now 表示已授权但尚未生效)
* delay: 该账户执行操作的延迟时间
*/
struct Access {
uint48 since;
Time.Delay delay;
}
/**
* 存储每个角色相关权限设定的结构体
* members: 每个用户的访问权限
* admin: 该角色的管理员,拥有授予或撤销权限的能力
* guardian: 该角色的监护人,拥有取消操作的能力
* grantDelay: 用户被授予该角色后的延迟时间
*/
struct Role {
mapping(address user => Access access) members;
uint64 admin;
uint64 guardian;
Time.Delay grantDelay;
}
/**
* 一个预定操作(比如延迟授权、延迟执行)的时间安排
* timepoint: 该操作可以被执行的时间戳
* nonce: 操作的唯一标识符,用于允许第三方合约识别该操作
*/
struct Schedule {
uint48 timepoint;
uint32 nonce;
}
// 定义了一个最高权限角色常量 ADMIN_ROLE, 是系统保留的角色,类似“超级管理员”
// 系统中默认每个函数都只能由 ADMIN_ROLE 调用,除非设置了新的权限策略
uint64 public constant ADMIN_ROLE = type(uint64).min; // 0
// 定义一个公开角色,所有地址天然拥有的公开角色
uint64 public constant PUBLIC_ROLE = type(uint64).max; // 2**64 - 1
// 每个目标合约地址(target)拥有一组权限配置
mapping(address target => TargetConfig mode) private _targets;
// 每个 roleId 对应一组角色管理信息
mapping(uint64 roleId => Role) private _roles;
// 每个操作 ID(如延迟调用)对应一个时间调度
mapping(bytes32 operationId => Schedule) private _schedules;
/**
* 当前正在执行的 operation 的 ID,用于防止重入攻击或嵌套调用
* 标记当前正在执行的受管操作的 operationId,用于在执行过程中允许目标合约通过 AccessManager.onlyAuthorized() 检查是否“正在被 AccessManager 安全代理调用”。
*/
bytes32 private _executionId;
/**
* 函数修饰器:只允许“经过授权”的调用者才能调用函数
*/
modifier onlyAuthorized() {
_checkAuthorized();
_;
}
/**
* 合约部署时,自动调用
* @param initialAdmin
*/
constructor(address initialAdmin) {
// 禁止将零地址设为管理员
if (initialAdmin == address(0)) {
revert AccessManagerInvalidInitialAdmin(address(0));
}
// 授予初始管理员角色(直接生效,无延迟)
// 即:部署合约后,初始管理员可以立即执行所有管理操作(如分配角色、设置目标限制等),无等待
_grantRole(ADMIN_ROLE, initialAdmin, 0, 0);
}
/**
* 判断某个 caller 是否能调用某个合约(target)的某个函数(由 selector 表示),并返回:
* ① immediate: 是否可以立即执行;
* ② delay: 若不能立即执行,需要延迟多少时间。
*/
function canCall(
address caller,
address target,
bytes4 selector
) public view virtual returns (bool immediate, uint32 delay) {
// 判断目标合约是否已“关闭”
if (isTargetClosed(target)) {
// 如果是关闭状态,任何人都不能调用,直接返回 (false, 0)
return (false, 0);
// 判断调用者是否为 AccessManager 自身
} else if (caller == address(this)) {
/**
* 如果调用者是 AccessManager 本身,那代表这是通过内部的 execute() 方法进行的受控调用。
* 此时,execute() 已经预先检查过权限了,因此:
* _isExecuting(target, selector) 是一个确认该调用是在受控范围内执行的检查。
* 如果为 true 表示可以执行,返回 (true, 0);否则为 (false, 0)。
*/
return (_isExecuting(target, selector), 0);
} else {
uint64 roleId = getTargetFunctionRole(target, selector); // 获取调用该函数所需的角色 ID 【绑定关系: 目标合约 + 函数 -> roleId】
(bool isMember, uint32 currentDelay) = hasRole(roleId, caller); // 检查当前调用者是否是该 roleId 的成员
return isMember ? (currentDelay == 0, currentDelay) : (false, 0);
}
}
// 返回角色有效期
function expiration() public view virtual returns (uint32) {
return 1 weeks; // 604800 秒
}
/**
* 返回系统允许的最小“冷静期”延迟
* ※ 用途:这个冷静期可能被用在设置执行延迟或权限延迟变更的操作中,确保关键权限操作不能立刻生效,从而留给治理或管理员时间反应。
* ※ 意义:安全保障机制,比如某人试图快速提权,系统会强制延迟执行
*/
function minSetback() public view virtual returns (uint32) {
return 5 days;
}
/**
* 查询某个目标合约是否被“关闭”
* 含义:如果某个目标合约被关闭,则表示不允许再通过 AccessManager 管理调用(即 canCall 将拒绝所有请求)。
* 实际用途:管理员可以永久冻结某个目标合约的所有受控权限,达到“废止权限控制”的效果
* 合约仍然可以被调用,但不会经过 AccessManager 的权限检查
*/
function isTargetClosed(address target) public view virtual returns (bool) {
return _targets[target].closed;
}
/**
* 返回某个目标合约(target)上某个函数(用 selector 标识)所需要的角色 ID
* 关键理解:一个函数只能被具有对应 roleId(角色) 的账户调用
*/
function getTargetFunctionRole(
address target,
bytes4 selector
) public view virtual returns (uint64) {
return _targets[target].allowedRoles[selector];
}
/**
* 获取指定目标合约(target)的“管理员延迟”(admin delay)
*/
function getTargetAdminDelay(
address target
) public view virtual returns (uint32) {
return _targets[target].adminDelay.get();
}
/**
* 获取某个角色的管理员角色
*/
function getRoleAdmin(uint64 roleId) public view virtual returns (uint64) {
return _roles[roleId].admin;
}
/**
* 获取 roleId 的 guardian(监护人)角色
*/
function getRoleGuardian(
uint64 roleId
) public view virtual returns (uint64) {
return _roles[roleId].guardian;
}
/**
* 获取 roleId 的授权延迟(grantDelay)
*/
function getRoleGrantDelay(
uint64 roleId
) public view virtual returns (uint32) {
return _roles[roleId].grantDelay.get();
}
/**
* 返回某个 account 拥有某个 roleId 的详细权限信息,包括授权时间、当前延迟、待定延迟和延迟生效时间
*/
function getAccess(
uint64 roleId,
address account
)
public
view
virtual
returns (
uint48 since,
uint32 currentDelay,
uint32 pendingDelay,
uint48 effect
)
{
// access 是某个用户对某个角色的访问记录,信息包含:
// ① since:用户拥有该角色的起始时间(UNIX 时间戳)。
// ② delay:延迟对象(自定义类型),用来管理执行调用时的 delay 策略
Access storage access = _roles[roleId].members[account];
since = access.since;
(currentDelay, pendingDelay, effect) = access.delay.getFull();
return (since, currentDelay, pendingDelay, effect);
}
/**
* 判断某个账户是否拥有某个角色,并返回当前生效的执行延迟
*/
function hasRole(
uint64 roleId,
address account
) public view virtual returns (bool isMember, uint32 executionDelay) {
if (roleId == PUBLIC_ROLE) {
return (true, 0);
} else {
(uint48 hasRoleSince, uint32 currentDelay, , ) = getAccess(
roleId,
account
);
return (
hasRoleSince != 0 && hasRoleSince <= Time.timestamp(),
currentDelay
);
}
}
/**
* 为指定角色设置一个 label(用于展示、标识),不影响权限逻辑,仅用于界面友好性
*/
function labelRole(
uint64 roleId,
string calldata label
) public virtual onlyAuthorized {
if (roleId == ADMIN_ROLE || roleId == PUBLIC_ROLE) {
revert AccessManagerLockedRole(roleId);
}
emit RoleLabel(roleId, label);
}
/**
* 授予 account 一个指定的 roleId,并设定该角色下调用目标函数时的 executionDelay
* 底层调用_grantRole 函数
* ① getRoleGrantDelay 获取该角色设定的“授予延迟”,用于控制何时该账户正式拥有角色权限。
* ② executionDelay 是未来实际执行操作时所使用的 delay,表示角色调用敏感函数是否必须等待
*/
function grantRole(
uint64 roleId,
address account,
uint32 executionDelay
) public virtual onlyAuthorized {
_grantRole(roleId, account, getRoleGrantDelay(roleId), executionDelay);
}
/**
* 撤销 account 对某 roleId 的访问权
*/
function revokeRole(
uint64 roleId,
address account
) public virtual onlyAuthorized {
_revokeRole(roleId, account);
}
/**
* 调用者自己放弃对某个 roleId 的角色权限
*/
function renounceRole(
uint64 roleId,
address callerConfirmation
) public virtual {
// 用户主动“确认”自己正在撤销角色权限,即:是我自己想要放弃这个角色
if (callerConfirmation != _msgSender()) {
revert AccessManagerBadConfirmation();
}
_revokeRole(roleId, callerConfirmation);
}
/**
* 为某个 roleId 设置 管理员角色,也就是说,只有这个 admin 角色的人才能授权/撤销此 roleId 的权限
*/
function setRoleAdmin(
uint64 roleId,
uint64 admin
) public virtual onlyAuthorized {
_setRoleAdmin(roleId, admin);
}
/**
* 为 roleId 设置 Guardian(守护者)角色
* guardian 的职责是在某些紧急或重要情况下冻结、延迟或否决对该角色的修改
*/
function setRoleGuardian(
uint64 roleId,
uint64 guardian
) public virtual onlyAuthorized {
_setRoleGuardian(roleId, guardian);
}
/**
* 设置某个角色被授予时的延迟(授予延迟 grantDelay),即授予该角色时,要过多长时间才会真正生效
* 实现 延迟授权机制:一旦授权发起,不会立刻生效,必须等待设定的时间
*/
function setGrantDelay(
uint64 roleId,
uint32 newDelay
) public virtual onlyAuthorized {
_setGrantDelay(roleId, newDelay);
}
/**
* 授予角色
* 向 account 授予 roleId 角色,并设定
* ① grantDelay: 从现在开始,要等待多久才能正式生效;
* ② executionDelay: 授予角色生效后,该账号调用受保护函数时所需的等待时间
* 并返回该账号是否是第一次授权
*/
function _grantRole(
uint64 roleId,
address account,
uint32 grantDelay,
uint32 executionDelay
) internal virtual returns (bool) {
// 禁止对 PUBLIC_ROLE 授权
if (roleId == PUBLIC_ROLE) {
revert AccessManagerLockedRole(roleId);
}
// 判断该用户是否是新成员(即从未被授予过该角色)
// since == 0: 表示 account 没有被授予过该角色,是新成员
bool newMember = _roles[roleId].members[account].since == 0;
// 声明记录角色正式“生效”的时间戳
uint48 since;
// 新成员处理
if (newMember) {
since = Time.timestamp() + grantDelay; // 设置生效时间为:当前区块时间 + 授权延迟
// 用 Access 结构记录该成员的状态
_roles[roleId].members[account] = Access({
since: since,
delay: executionDelay.toDelay()
});
} else {
// 老成员处理(权限调整)
// 对已存在的成员,只更新 executionDelay,不会重置整个状态
// 若想“重置”,可手动执行 revoke + grant。
(_roles[roleId].members[account].delay, since) = _roles[roleId]
.members[account]
.delay
.withUpdate(executionDelay, 0);
}
// 发出授权事件
emit RoleGranted(roleId, account, executionDelay, since, newMember);
return newMember;
}
/**
* 撤销角色
* 从 account 身上撤销某个角色(即清除掉其在 _roles 中的数据)
*/
function _revokeRole(
uint64 roleId,
address account
) internal virtual returns (bool) {
// 禁止对 PUBLIC_ROLE 撤销角色
if (roleId == PUBLIC_ROLE) {
revert AccessManagerLockedRole(roleId);
}
// 该用户从未被授予过该角色,不需要撤销,直接返回 false
if (_roles[roleId].members[account].since == 0) {
return false;
}
// 删除 account 在该角色下的所有信息,彻底移除
delete _roles[roleId].members[account];
// 发出事件表示撤销成功
emit RoleRevoked(roleId, account);
return true;
}
/**
* 为某个角色设置管理员角色,只有管理员拥有授予/撤销该角色权限的能力。
*/
function _setRoleAdmin(uint64 roleId, uint64 admin) internal virtual {
// 禁止对 ADMIN_ROLE 和 PUBLIC_ROLE 设置管理员
if (roleId == ADMIN_ROLE || roleId == PUBLIC_ROLE) {
revert AccessManagerLockedRole(roleId);
}
// 设置 roleId 的管理员
_roles[roleId].admin = admin;
emit RoleAdminChanged(roleId, admin);
}
/**
* 为某个角色设置一个“监护人”角色,其成员可对 executionDelay 等关键参数进行“快速回退操作”
* 监护角色的设计是为了更高安全性的 多签监管或延迟变更确认。
*/
function _setRoleGuardian(uint64 roleId, uint64 guardian) internal virtual {
if (roleId == ADMIN_ROLE || roleId == PUBLIC_ROLE) {
revert AccessManagerLockedRole(roleId);
}
_roles[roleId].guardian = guardian;
emit RoleGuardianChanged(roleId, guardian);
}
/**
* 设定某角色从“授权”到“正式生效”的延迟时间
* 用于阻止攻击者瞬间自我授权
*/
function _setGrantDelay(uint64 roleId, uint32 newDelay) internal virtual {
if (roleId == PUBLIC_ROLE) {
revert AccessManagerLockedRole(roleId);
}
uint48 effect;
(_roles[roleId].grantDelay, effect) = _roles[roleId]
.grantDelay
.withUpdate(newDelay, minSetback()); // 这里的 minSetback() 是为了防止攻击者瞬间自我授权
emit RoleGrantDelayChanged(roleId, newDelay, effect);
}
/**
* 给一个目标合约(target)的多个函数(selectors[])统一设置需要的角色 roleId
*/
function setTargetFunctionRole(
address target,
bytes4[] calldata selectors,
uint64 roleId
) public virtual onlyAuthorized {
for (uint256 i = 0; i < selectors.length; ++i) {
_setTargetFunctionRole(target, selectors[i], roleId);
}
}
/**
* 给一个目标合约(target)的一个函数(selector)设置需要的角色 roleId
* 实际更新 _targets 映射中某个 target 合约的某个函数 selector 所需的角色权限。
* 发出事件 TargetFunctionRoleUpdated,便于外部监听
*/
function _setTargetFunctionRole(
address target,
bytes4 selector,
uint64 roleId
) internal virtual {
_targets[target].allowedRoles[selector] = roleId;
emit TargetFunctionRoleUpdated(target, selector, roleId);
}
/**
* 为目标合约 target 设置“管理员操作延迟”(admin delay)
* 含义:对该目标合约进行权限修改类操作时,必须等这么长时间之后才可生效
*/
function setTargetAdminDelay(
address target,
uint32 newDelay
) public virtual onlyAuthorized {
_setTargetAdminDelay(target, newDelay);
}
function _setTargetAdminDelay(
address target,
uint32 newDelay
) internal virtual {
uint48 effect;
(_targets[target].adminDelay, effect) = _targets[target]
.adminDelay
.withUpdate(newDelay, minSetback());
emit TargetAdminDelayUpdated(target, newDelay, effect);
}
/**
* 设置目标合约是否关闭
*/
function setTargetClosed(
address target,
bool closed
) public virtual onlyAuthorized {
_setTargetClosed(target, closed);
}
function _setTargetClosed(address target, bool closed) internal virtual {
_targets[target].closed = closed;
emit TargetClosed(target, closed);
}
/**
* 获取某个操作的调度时间
*/
function getSchedule(bytes32 id) public view virtual returns (uint48) {
uint48 timepoint = _schedules[id].timepoint;
return _isExpired(timepoint) ? 0 : timepoint; // 若已经过期:返回 0(表示无效或已过期)
}
/**
* 查询执行次数(版本号)
*/
function getNonce(bytes32 id) public view virtual returns (uint32) {
return _schedules[id].nonce;
}
/**
* 判断当前是否正通过 execute() 函数对 target.selector 发起了受控调用
* AccessManager 会在 execute() 时设置 _executionId = _hashExecutionId(target, selector),然后在 call 执行后再还原它。因此:
* 如果当前 _executionId 等于传入目标函数的哈希,说明这是一次通过 AccessManager 调度执行的函数调用。
* 用于 canCall() 中分支判断是否绕过权限验证(即,已由 execute() 统一验证权限)
*/
function _isExecuting(
address target,
bytes4 selector
) private view returns (bool) {
return _executionId == _hashExecutionId(target, selector);
}
/**
* 判断某个 timepoint 是否已经过期
*/
function _isExpired(uint48 timepoint) private view returns (bool) {
// expiration() 返回调度任务的有效期,默认为 1 weeks
// 若当前时间(Time.timestamp())超过 调度时间(timepoint) + expiration(),则该操作视为 过期
return timepoint + expiration() <= Time.timestamp();
}
/**
* 提取调用数据(calldata)的函数选择器(selector)
*/
function _checkSelector(bytes calldata data) private pure returns (bytes4) {
return bytes4(data[0:4]);
}
/**
* 生成一个当前被执行函数调用的唯一标识符
*/
function _hashExecutionId(
address target,
bytes4 selector
) private pure returns (bytes32) {
return keccak256(abi.encode(target, selector));
}
/**
* 检查操作是否已调度
* 保一个操作不会在未过期的情况下被重复调度(避免重复添加定时操作)
*/
function _checkNotScheduled(bytes32 operationId) private view {
uint48 prevTimepoint = _schedules[operationId].timepoint;
if (prevTimepoint != 0 && !_isExpired(prevTimepoint)) {
// 未过期
revert AccessManagerAlreadyScheduled(operationId);
}
}
/**
* 判断某调用是否允许执行的辅助函数
* 为 schedule() 和 execute() 提供统一的权限判断入口
* 单独处理内部函数权限 _canCallSelf
*/
function _canCallExtended(
address caller,
address target,
bytes calldata data
) private view returns (bool immediate, uint32 delay) {
// 调用目标是 AccessManager 本身, _canCallSelf() 进行特殊权限判断
if (target == address(this)) {
return _canCallSelf(caller, data);
} else {
return
data.length < 4
? (false, 0)
: canCall(caller, target, _checkSelector(data));
}
}
/**
* 判断调用者是否有权限执行 AccessManager 自身的某个函数
*/
function _canCallSelf(
address caller,
bytes calldata data
) private view returns (bool immediate, uint32 delay) {
// 无法提取 selector,说明不是有效的函数调用,直接拒绝
if (data.length < 4) {
return (false, 0);
}
// 调用者是 AccessManager 自己
if (caller == address(this)) {
return (_isExecuting(address(this), _checkSelector(data)), 0);
}
// 获取函数的 Admin 权限
(
bool adminRestricted,
uint64 roleId,
uint32 operationDelay
) = _getAdminRestrictions(data);
// 当前调用的函数不是管理函数且AccessManager已关闭,则拒绝调用
if (!adminRestricted && isTargetClosed(address(this))) {
return (false, 0);
}
// 获取调用者是否有权限
// 通过 hasRole() 函数检查 caller 是否拥有 roleId 角色
// 该函数会返回两个值:
// ① inRole:是否拥有该角色
// ② executionDelay:该角色的执行延迟
(bool inRole, uint32 executionDelay) = hasRole(roleId, caller);
if (!inRole) {
return (false, 0);
}
// 计算最终的延迟时间 (函数级延迟(operationDelay)和 角色级延迟(executionDelay) 取最大值)
delay = uint32(Math.max(operationDelay, executionDelay));
return (delay == 0, delay);
}
/**
* 分析某个函数调用的管理权限要求(即是否为管理员操作)和其延迟要求
*/
function _getAdminRestrictions(
bytes calldata data
)
private
view
returns (
bool adminRestricted,
uint64 roleAdminId,
uint32 executionDelay
)
{
// 无法提取 selector,说明不是有效的函数调用,直接拒绝
if (data.length < 4) {
return (false, 0, 0);
}
// 提取函数选择器
bytes4 selector = _checkSelector(data);
// 当前的调用函数是 labelRole、setRoleAdmin、setRoleGuardian、setGrantDelay、setTargetAdminDelay,只能由 ADMIN_ROLE 调用,且不需要额外的delay
if (
selector == this.labelRole.selector ||
selector == this.setRoleAdmin.selector ||
selector == this.setRoleGuardian.selector ||
selector == this.setGrantDelay.selector ||
selector == this.setTargetAdminDelay.selector
) {
return (true, ADMIN_ROLE, 0);
}
// 当前调用函数是 updateAuthority、setTargetClosed、setTargetFunctionRole,只能由目标合约(target)的 ADMIN_ROLE 调用
if (
selector == this.updateAuthority.selector ||
selector == this.setTargetClosed.selector ||
selector == this.setTargetFunctionRole.selector
) {
// data[0x04:0x24] 是函数第一个参数的位置.
address target = abi.decode(data[0x04:0x24], (address));
uint32 delay = getTargetAdminDelay(target);
return (true, ADMIN_ROLE, delay);
}
// 当前调用函数是 grantRole、revokeRole,只能由 rodeId 的 admin 调用
if (
selector == this.grantRole.selector ||
selector == this.revokeRole.selector
) {
uint64 roleId = abi.decode(data[0x04:0x24], (uint64));
return (true, getRoleAdmin(roleId), 0);
}
// 其他
return (false, getTargetFunctionRole(address(this), selector), 0);
}
/**
* 延迟执行机制的实现
* 实现:授权用户对某个函数调用进行“排队调度(schedule)”的功能
* @param target 目标合约地址
* @param data 目标合约函数调用数据(包含 selector + 参数)
* @param when 请求执行的时间戳
* @return operationId 该操作的唯一标识符
* @return nonce 该操作的 nonce (同一个 operationId 被多次调度时用于区分)
*
*/
function schedule(
address target,
bytes calldata data,
uint48 when
) public virtual returns (bytes32 operationId, uint32 nonce) {
address caller = _msgSender(); // 发起当前调用请求的账户
// 获取该调用的延迟限制(检查此 caller 对目标合约(target)中某个函数(data)的权限配置,返回该调用所需的延迟 setback)
// setback == 0,代表调用者没有调度该操作的权限(或权限立即生效)
(, uint32 setback) = _canCallExtended(caller, target, data);
uint48 minWhen = Time.timestamp() + setback;
// 检查调用是否合法
// 若 setback == 0:不允许调度(比如该函数必须立即执行或完全不允许)
// 若 when < minWhen:调度时间早于所需延迟,禁止执行
if (setback == 0 || (when > 0 && when < minWhen)) {
revert AccessManagerUnauthorizedCall(
caller,
target,
_checkSelector(data)
);
}
// 修正when
when = uint48(Math.max(when, minWhen)); // cast is safe: both inputs are uint48
// 调用者 + 目标 + 函数数据 打包哈希,生成此操作的唯一标识符
operationId = hashOperation(caller, target, data);
// 检查该操作是否已经被调度过 (防止相同操作被重复调度)
_checkNotScheduled(operationId);
// 计算新的 nonce 并记录调度信息
unchecked {
nonce = _schedules[operationId].nonce + 1;
}
// 更新调度信息
_schedules[operationId].timepoint = when;
_schedules[operationId].nonce = nonce;
emit OperationScheduled(operationId, nonce, when, caller, target, data);
}
/**
* 实际执行调度或立即授权的函数调用 (核心执行入口)
* @param target
* @param data
*/
function execute(
address target,
bytes calldata data
) public payable virtual returns (uint32) {
address caller = _msgSender();
// 获取该调用的延迟限制
// 检查此 caller 对目标合约(target)中某个函数(data)的权限配置,
// 返回该调用所需的延迟 setback, 是否立即执行 immediate
(bool immediate, uint32 setback) = _canCallExtended(
caller,
target,
data
);
// 检查调用是否合法
// setback == 0,代表调用者没有调度该操作的权限(或权限立即生效)
// immediate == false,代表调用者没有立即执行的权限
if (!immediate && setback == 0) {
revert AccessManagerUnauthorizedCall(
caller,
target,
_checkSelector(data)
);
}
// 调用者 + 目标 + 函数数据 打包哈希,生成此操作的唯一标识符
bytes32 operationId = hashOperation(caller, target, data);
uint32 nonce;
// 只要设置了 delay,或者之前已经 schedule 过,就需要“消耗掉”一次调度
if (setback != 0 || getSchedule(operationId) != 0) {
nonce = _consumeScheduledOp(operationId);
}
//
bytes32 executionIdBefore = _executionId;
_executionId = _hashExecutionId(target, _checkSelector(data));
// 真实调用目标函数
Address.functionCallWithValue(target, data, msg.value);
// 恢复 _executionId 状态
_executionId = executionIdBefore;
return nonce;
}
/**
* 取消一个已经被调度(scheduled)但尚未执行的操作
*/
function cancel(
address caller,
address target,
bytes calldata data
) public virtual returns (uint32) {
address msgsender = _msgSender(); // 发起当前调用请求的账户
bytes4 selector = _checkSelector(data); // 提取函数选择器
// 计算操作的唯一标识符
bytes32 operationId = hashOperation(caller, target, data);
if (_schedules[operationId].timepoint == 0) {
// 操作未被调度
revert AccessManagerNotScheduled(operationId);
} else if (caller != msgsender) {
// 操作的发起者不是当前调用者,那就只有 管理员 或 该操作角色的监护人 可以取消操作
(bool isAdmin, ) = hasRole(ADMIN_ROLE, msgsender);
(bool isGuardian, ) = hasRole(
getRoleGuardian(getTargetFunctionRole(target, selector)),
msgsender
);
if (!isAdmin && !isGuardian) {
revert AccessManagerUnauthorizedCancel(
msgsender,
caller,
target,
selector
);
}
}
delete _schedules[operationId].timepoint; // 删除调度记录:调用取消时只删除调度时间点,保留 nonce
uint32 nonce = _schedules[operationId].nonce;
emit OperationCanceled(operationId, nonce);
return nonce;
}
/**
* 用于“消费”之前已经调度好(schedule)的操作
*/
function consumeScheduledOp(
address caller,
bytes calldata data
) public virtual {
address target = _msgSender(); // 发起当前调用请求的账户
// target 必须实现 IAccessManaged 接口,并且其 isConsumingScheduledOp() 函数必须返回 IAccessManaged.isConsumingScheduledOp.selector。
// 否则认为 target 并非在“调度执行流程”中,直接拒绝消费,避免恶意绕过调度机制。
if (
IAccessManaged(target).isConsumingScheduledOp() !=
IAccessManaged.isConsumingScheduledOp.selector
) {
revert AccessManagerUnauthorizedConsume(target);
}
_consumeScheduledOp(hashOperation(caller, target, data));
}
function _consumeScheduledOp(
bytes32 operationId
) internal virtual returns (uint32) {
uint48 timepoint = _schedules[operationId].timepoint; // 操作的调度时间
uint32 nonce = _schedules[operationId].nonce; // 操作的版本号
if (timepoint == 0) {
// 该操作未被调度,直接抛出异常
revert AccessManagerNotScheduled(operationId);
} else if (timepoint > Time.timestamp()) {
// 调度时间还未到达,直接抛出异常
revert AccessManagerNotReady(operationId);
} else if (_isExpired(timepoint)) {
// 调度时间已过期,直接抛出异常
revert AccessManagerExpired(operationId);
}
delete _schedules[operationId].timepoint; // 正常消费成功后,清除调度信息(timepoint),但 保留 nonce(避免重放攻击或重复执行)
emit OperationExecuted(operationId, nonce);
return nonce;
}
/**
* 计算某个操作的哈希值
* @param caller 调用者地址
* @param target 目标合约地址
* @param data 目标合约函数调用数据(包含 selector + 参数)
*/
function hashOperation(
address caller,
address target,
bytes calldata data
) public view virtual returns (bytes32) {
return keccak256(abi.encode(caller, target, data));
}
function updateAuthority(
address target,
address newAuthority
) public virtual onlyAuthorized {
IAccessManaged(target).setAuthority(newAuthority);
}
/**
*
*/
function _checkAuthorized() private {
address caller = _msgSender(); // 发起当前调用请求的账户
// 判断 caller 是否对当前合约发起的这个调用(通过 msgData 区分方法)
(bool immediate, uint32 delay) = _canCallSelf(caller, _msgData());
if (!immediate) {
// 不立即执行
if (delay == 0) {
// delay == 0:说明完全没有授权,也不允许延迟执行
(, uint64 requiredRole, ) = _getAdminRestrictions(_msgData());
revert AccessManagerUnauthorizedAccount(caller, requiredRole); // 抛出错误:调用者缺少某个权限角色
} else {
// 调用者可以延迟执行该操作,且之前可能已经通过 schedule() 调度过操作
_consumeScheduledOp(
hashOperation(caller, address(this), _msgData())
);
}
}
}
}
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!