• Michael.W基于Foundry精读Openzeppelin第36期——Ownable2Step.sol


    0. 版本

    [openzeppelin]:v4.8.3,[forge-std]:v1.5.6

    0.1 Ownable2Step.sol

    Github: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.8.3/contracts/access/Ownable2Step.sol

    Ownable2Step库是Ownable库的拓展版本。其提供的访问权限机制同Ownable完全一致,只是owner的更换机制从由原owner直接指定(一次交互)变成原owner指定 + 新owner确认(两次交互)。Ownable2Step库具有Ownable库所有的功能函数。

    1. 目标合约

    继承Ownable2Step成为一个可调用合约:

    Github: https://github.com/RevelationOfTuring/foundry-openzeppelin-contracts/blob/master/src/access/MockOwnable2Step.sol

    // SPDX-License-Identifier: UNLICENSED
    pragma solidity ^0.8.0;
    
    import "openzeppelin-contracts/contracts/access/Ownable2Step.sol";
    
    contract MockOwnable2Step is Ownable2Step {
        uint public i;
    
        function transferOwnershipInternal(address newOwner) external {
            _transferOwnership(newOwner);
        }
    
        function setI(uint value) external onlyOwner {
            i = value;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    全部foundry测试合约:

    Github: https://github.com/RevelationOfTuring/foundry-openzeppelin-contracts/blob/master/test/access/Ownable2Step.t.sol

    2. 代码精读

    2.1 pendingOwner() && transferOwnership(address newOwner) && _transferOwnership(address newOwner)
    • pendingOwner():返回当前合约处于待确认状态的owner地址;
    • transferOwnership(address newOwner):合约当前owner指定新的owner(步骤一),该操作会覆盖之前设置的_pendingOwner。注: 该函数重写了Ownerable库的transferOwnership函数;
    • _transferOwnership(address newOwner):转移本合约owner身份给一个新的地址。注:该函数重写了Ownerable库的_transferOwnership函数且不具有对访问权限的限制;
    	// 处于待确认状态的owner地址
        address private _pendingOwner;
    
        event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
    
        function pendingOwner() public view virtual returns (address) {
        	// 返回状态变量_pendingOwner
            return _pendingOwner;
        }
        
        function transferOwnership(address newOwner) public virtual override onlyOwner {
            // 新owner地址处于待确认状态,写入状态变量_pendingOwner
            _pendingOwner = newOwner;
            // 抛出event
            emit OwnershipTransferStarted(owner(), newOwner);
        }
        
        function _transferOwnership(address newOwner) internal virtual override {
            // 清空状态变量_pendingOwner
            delete _pendingOwner;
            // 调用Ownerable.transferOwnership()进行owner身份的转移
            super._transferOwnership(newOwner);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    foundry代码验证

    contract Ownable2StepTest is Test {
        MockOwnable2Step private _testing;
    
        function setUp() external {
            _testing = new MockOwnable2Step();
        }
    
        event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
        event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    
        function test_TransferOwnership() external {
            // test for public function: transferOwnership
            assertEq(address(0), _testing.pendingOwner());
            // case 1: pass
            vm.expectEmit(true, true, false, false, address(_testing));
            emit OwnershipTransferStarted(address(this), address(1024));
            _testing.transferOwnership(address(1024));
            assertEq(address(1024), _testing.pendingOwner());
    
            // test for internal function: _transferOwnership
            // case 1: pass with clearing pending owner and new owner transferred
            vm.expectEmit(true, true, false, false, address(_testing));
            emit OwnershipTransferred(address(this), address(2048));
            _testing.transferOwnershipInternal(address(2048));
            // new owner transferred
            assertEq(address(2048), _testing.owner());
            // clear the pending owner
            assertEq(address(0), _testing.pendingOwner());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    2.2 acceptOwnership()

    新owner确认owner身份的转移(步骤二)。

        function acceptOwnership() external {
            address sender = _msgSender();
            // 确认本次调用者为处于待确认状态的owner地址,否则revert
            require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
            // 将owner身份转移给本次调用者(即处于待确认状态的owner地址)
            _transferOwnership(sender);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    foundry代码验证

    contract Ownable2StepTest is Test {
        MockOwnable2Step private _testing;
    
        function setUp() external {
            _testing = new MockOwnable2Step();
        }
    
        event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    
        function test_AcceptOwnership() external {
            // case 1: pass
            _testing.transferOwnership(address(1024));
            assertEq(address(1024), _testing.pendingOwner());
            assertEq(address(this), _testing.owner());
            vm.prank(address(1024));
            vm.expectEmit(true, true, false, false, address(_testing));
            emit OwnershipTransferred(address(this), address(1024));
            _testing.acceptOwnership();
            // clear the pending owner
            assertEq(address(0), _testing.pendingOwner());
            // new owner transferred
            assertEq(address(1024), _testing.owner());
    
            // case 2: revert if _msgSender() is not pending owner
            // current pending owner is address(0)
            vm.expectRevert("Ownable2Step: caller is not the new owner");
            vm.prank(address(1));
            _testing.acceptOwnership();
        }
        
        function test_OnlyOwner() external {
            assertEq(address(this), _testing.owner());
    
            // test for modifier: onlyOwner
            // case 1: pass the check of modifier
            assertEq(0, _testing.i());
            _testing.setI(1024);
            assertEq(1024, _testing.i());
            // case 2: revert if the msgSender() is not owner
            vm.prank(address(1024));
            vm.expectRevert("Ownable: caller is not the owner");
            _testing.setI(1024);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    ps:
    本人热爱图灵,热爱中本聪,热爱V神。
    以下是我个人的公众号,如果有技术问题可以关注我的公众号来跟我交流。
    同时我也会在这个公众号上每周更新我的原创文章,喜欢的小伙伴或者老伙计可以支持一下!
    如果需要转发,麻烦注明作者。十分感谢!

    在这里插入图片描述

    公众号名称:后现代泼痞浪漫主义奠基人

  • 相关阅读:
    Golang内存对齐
    《Get your hands dirty on clean architecture》读书笔记
    深圳SMT贴片行业MES系统解决方案~MES系统服务商~先达智控
    【学懂数据结构】算法及其复杂度分析
    MybatisPlus高级特性
    openVPN
    将VS工程转为pro工程及VS安装Qt插件后没有create basic .pro file菜单问题解决
    对抗生成网络GAN系列——EGBAD原理及缺陷检测实战
    【建议背诵】软考高项考试案例简答题汇总~(7)
    计算机设计大赛 深度学习手势识别算法实现 - opencv python
  • 原文地址:https://blog.csdn.net/michael_wgy_/article/details/133147035