Michael.W基于Foundry精读Openzeppelin第36期——Ownable2Step.sol
- 0. 版本
- 0.1 Ownable2Step.sol
- 1. 目标合约
- 2. 代码精读
- 2.1 pendingOwner() && transferOwnership(address newOwner) && _transferOwnership(address newOwner)
- 2.2 acceptOwnership()
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;
}
}
全部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);
}
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());
}
}
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);
}
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);
}
}
ps:
本人热爱图灵,热爱中本聪,热爱V神。
以下是我个人的公众号,如果有技术问题可以关注我的公众号来跟我交流。
同时我也会在这个公众号上每周更新我的原创文章,喜欢的小伙伴或者老伙计可以支持一下!
如果需要转发,麻烦注明作者。十分感谢!
公众号名称:后现代泼痞浪漫主义奠基人