Solidity修饰器:第一部分

本文介绍了Solidity中常用的几种modifier,包括onlyOwnernonReentrantonlyRolewhenNotPausedwhenPaused。这些modifier分别用于限制函数访问权限(仅合约拥有者、防止重入攻击、基于角色)以及在合约暂停或未暂停时执行函数。

Solidity 修饰器 : 第一部分

1. 修饰器 : onlyOwner

onlyOwner 修饰器确保函数只能由合约的所有者调用。这对于只能由合约创建者或指定所有者访问的函数来说是一种常见的模式。

示例代码

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

contract MyContract is Ownable {
    function privilegedFunction() public onlyOwner {
        // 只有所有者可以执行的代码
    }
}

解释

  • Ownable: 这是一个 OpenZeppelin 合约,提供了所有权机制。
  • onlyOwner: 此修饰器将函数访问限制为仅合约的所有者。
  • privilegedFunction: 一个受 onlyOwner 保护的函数,确保只有所有者可以调用它。

实现细节

modifier onlyOwner() {
    require(owner() == msg.sender, "Ownable: caller is not the owner");
    _;
}
  • modifier onlyOwner(): 检查调用者 ( msg.sender) 是否为合约所有者。
  • require(owner() == msg.sender, "Ownable: caller is not the owner"): 验证调用者是否为所有者。如果不是,则拒绝函数调用。
  • _;: 应用修饰器的函数体占位符。

2. 修饰器 : nonReentrant

nonReentrant 修饰器通过确保函数在仍在执行时不能再次被调用来防止重入攻击。重入是一种安全漏洞,其中合约进行外部调用,并且外部合约可以回调到原始函数中。

示例代码

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";

contract MyContract is ReentrancyGuard {
    mapping(address => uint256) public balances;

    function withdraw(uint256 amount) public nonReentrant {
        require(balances[msg.sender] >= amount, "Insufficient balance");
        balances[msg.sender] -= amount;
        payable(msg.sender).transfer(amount);
    }
}

解释

  • ReentrancyGuard: 这是一个 OpenZeppelin 合约,用于帮助防止重入攻击。
  • nonReentrant: 应用于 withdraw 函数以防止重入。
  • withdraw: 由于 nonReentrant,此函数一次只能执行一次。

实现细节

modifier nonReentrant() {
    require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
    _status = _ENTERED;
    _;
    _status = _NOT_ENTERED;
}
  • modifier nonReentrant(): 确保该函数不在执行过程中。
  • require(_status != _ENTERED, "ReentrancyGuard: reentrant call"): 检查该函数当前是否正在执行。
  • _status = _ENTERED: 将状态设置为已进入,防止重入。
  • _;: 应用修饰器的函数体占位符。
  • _status = _NOT_ENTERED: 在函数执行后将状态重置为未进入。

3. 修饰器 : onlyRole

onlyRole 修饰器根据合约中定义的角色限制对函数的访问。角色用于权限管理,允许不同级别的访问。

示例代码

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

contract MyContract is AccessControl {
    bytes32 public constant MY_ROLE = keccak256("MY_ROLE");

    constructor() {
        _grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
        _grantRole(MY_ROLE, msg.sender);
    }

    function restrictedFunction() public onlyRole(MY_ROLE) {
        // 只有具有 MY_ROLE 帐户才能执行的代码
    }
}

解释

  • AccessControl: 一个 OpenZeppelin 合约,提供基于角色的访问控制。
  • onlyRole(MY_ROLE): 将 restrictedFunction 限制为具有 MY_ROLE 的用户。
  • restrictedFunction: 只能由具有 MY_ROLE 的用户调用的函数。

实现细节


abstract contract AccessControl is Context, IAccessControl, ERC165 {
    struct RoleData {
        mapping(address => bool) members;
        bytes32 adminRole;
    }

    mapping(bytes32 => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    modifier onlyRole(bytes32 role) {
        _checkRole(role, _msgSender());
        _;
    }

    function hasRole(bytes32 role, address account) public view override returns (bool) {
        return _roles[role].members[account];
    }

    function _checkRole(bytes32 role, address account) internal view {
        require(hasRole(role, account), string(abi.encodePacked("AccessControl: account ", Strings.toHexString(account), " is missing role ", Strings.toHexString(uint256(role), 32))));
    }

    function _grantRole(bytes32 role, address account) internal {
        if (!hasRole(role, account)) {
            _roles[role].members[account] = true;
            emit RoleGranted(role, account, _msgSender());
        }
    }

}
  • modifier onlyRole(bytes32 role): 确保调用者具有指定的角色。
  • _checkRole(role, msg.sender): 验证调用者是否具有该角色。
  • require(hasRole(role, account), "AccessControl: account is missing role"): 检查角色成员资格。

4. 修饰器 : whenNotPaused 和 whenPaused

whenNotPaused 修饰器将函数的执行限制在合约未暂停时。

whenPaused 修饰器将函数的执行限制在合约已暂停时。

示例代码

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/security/Pausable.sol";

contract MyContract is Pausable {
    function normalFunction() public whenNotPaused {
        // 仅当合约未暂停时才运行的代码
    }

    function emergencyFunction() public whenPaused {
        // 仅当合约暂停时才运行的代码
    }

    function pauseContract() public onlyOwner {
        _pause();
    }

    function unpauseContract() public onlyOwner {
        _unpause();
    }
}

解释

  • Pausable: 一个 OpenZeppelin 合约,用于暂停和取消暂停合约函数。
  • whenNotPaused: 应用于 normalFunction 以确保它仅在合约未暂停时运行。
  • normalFunction: 一个受 whenNotPaused 限制的函数。
  • whenPaused: 应用于 emergencyFunction 以确保它仅在合约暂停时运行。
  • emergencyFunction: 一个受 whenPaused 限制的函数。

实现细节


abstract contract Pausable is Context {
    event Paused(address account);
    event Unpaused(address account);

    bool private _paused;

    constructor() {
        _paused = false;
    }

    modifier whenNotPaused() {
        require(!_paused, "Pausable: paused");
        _;
    }

    modifier whenPaused() {
        require(_paused, "Pausable: not paused");
        _;
    }

    function paused() public view returns (bool) {
        return _paused;
    }

    function _pause() internal virtual {
        _paused = true;
        emit Paused(_msgSender());
    }

    function _unpause() internal virtual {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}
  • modifier whenNotPaused(): 确保合约未暂停。
  • require(!_paused, "Pausable: paused"): 检查合约是否未暂停。
  • modifier whenPaused(): 确保合约已暂停。
  • require(_paused, "Pausable: not paused"): 检查合约是否已暂停。

总结

  • onlyOwner: 使用 Ownable 限制对合约所有者的访问。
  • nonReentrant: 使用 ReentrancyGuard 防止重入攻击。
  • onlyRole: 使用 AccessControl 强制执行基于角色的访问控制。
  • whenNotPaused: 仅当使用 Pausable 合约未暂停时才允许函数执行。
  • whenPaused: 仅当使用 Pausable 合约已暂停时才允许函数执行。
  • 原文链接: coinsbench.com/solidity-...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
CoinsBench
CoinsBench
https://coinsbench.com/