-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
221 additions
and
33 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.4; | ||
|
||
import {IOwnable} from "../interfaces/IOwnable.sol"; | ||
|
||
/// @notice A minimal contract that implements 2-step ownership transfer and nothing more. It's made to be minimal | ||
/// to reduce the impact of the bytecode size on any contract that inherits from it. | ||
contract Ownable2Step is IOwnable { | ||
/// @notice The pending owner is the address to which ownership may be transferred. | ||
address private s_pendingOwner; | ||
/// @notice The owner is the current owner of the contract. | ||
/// @dev The owner is the second storage variable so any implementing contract could pack other state with it | ||
/// instead of the much less used s_pendingOwner. | ||
address private s_owner; | ||
|
||
error OwnerCannotBeZero(); | ||
error MustBeProposedOwner(); | ||
error CannotTransferToSelf(); | ||
error OnlyCallableByOwner(); | ||
|
||
event OwnershipTransferRequested(address indexed from, address indexed to); | ||
event OwnershipTransferred(address indexed from, address indexed to); | ||
|
||
constructor(address newOwner, address pendingOwner) { | ||
if (newOwner == address(0)) { | ||
revert OwnerCannotBeZero(); | ||
} | ||
|
||
s_owner = newOwner; | ||
if (pendingOwner != address(0)) { | ||
_transferOwnership(pendingOwner); | ||
} | ||
} | ||
|
||
/// @notice Get the current owner | ||
function owner() public view override returns (address) { | ||
return s_owner; | ||
} | ||
|
||
/// @notice Allows an owner to begin transferring ownership to a new address. The new owner needs to call | ||
/// `acceptOwnership` to accept the transfer before any permissions are changed. | ||
/// @param to The address to which ownership will be transferred. | ||
function transferOwnership(address to) public override onlyOwner { | ||
_transferOwnership(to); | ||
} | ||
|
||
/// @notice validate, transfer ownership, and emit relevant events | ||
/// @param to The address to which ownership will be transferred. | ||
function _transferOwnership(address to) private { | ||
if (to == msg.sender) { | ||
revert CannotTransferToSelf(); | ||
} | ||
|
||
s_pendingOwner = to; | ||
|
||
emit OwnershipTransferRequested(s_owner, to); | ||
} | ||
|
||
/// @notice Allows an ownership transfer to be completed by the recipient. | ||
function acceptOwnership() external override { | ||
if (msg.sender != s_pendingOwner) { | ||
revert MustBeProposedOwner(); | ||
} | ||
|
||
address oldOwner = s_owner; | ||
s_owner = msg.sender; | ||
s_pendingOwner = address(0); | ||
|
||
emit OwnershipTransferred(oldOwner, msg.sender); | ||
} | ||
|
||
/// @notice validate access | ||
function _validateOwnership() internal view { | ||
if (msg.sender != s_owner) { | ||
revert OnlyCallableByOwner(); | ||
} | ||
} | ||
|
||
/// @notice Reverts if called by anyone other than the contract owner. | ||
modifier onlyOwner() { | ||
_validateOwnership(); | ||
_; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.4; | ||
|
||
import {Ownable2Step} from "./Ownable2Step.sol"; | ||
|
||
/// @notice Sets the msg.sender to be the owner of the contract and does not set a pending owner. | ||
contract Ownable2StepMsgSender is Ownable2Step { | ||
constructor() Ownable2Step(msg.sender, address(0)) {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.19; | ||
pragma solidity 0.8.24; | ||
|
||
import "forge-std/Test.sol"; | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.24; | ||
|
||
import {BaseTest} from "../BaseTest.t.sol"; | ||
import {Ownable2Step} from "../../access/Ownable2Step.sol"; | ||
|
||
contract Ownable2Step_setup is BaseTest { | ||
Ownable2StepHelper internal s_ownable2Step; | ||
|
||
function setUp() public override { | ||
super.setUp(); | ||
s_ownable2Step = new Ownable2StepHelper(OWNER, address(0)); | ||
} | ||
} | ||
|
||
contract Ownable2Step_constructor is Ownable2Step_setup { | ||
function test_constructor_success() public view { | ||
assertEq(OWNER, s_ownable2Step.owner()); | ||
} | ||
|
||
function test_constructor_OwnerCannotBeZero_reverts() public { | ||
vm.expectRevert(Ownable2Step.OwnerCannotBeZero.selector); | ||
new Ownable2Step(address(0), address(0)); | ||
} | ||
} | ||
|
||
contract Ownable2Step_transferOwnership is Ownable2Step_setup { | ||
function test_transferOwnership_success() public { | ||
vm.expectEmit(); | ||
emit Ownable2Step.OwnershipTransferRequested(OWNER, STRANGER); | ||
|
||
s_ownable2Step.transferOwnership(STRANGER); | ||
|
||
assertTrue(STRANGER != s_ownable2Step.owner()); | ||
|
||
vm.startPrank(STRANGER); | ||
s_ownable2Step.acceptOwnership(); | ||
} | ||
|
||
function test_transferOwnership_CannotTransferToSelf_reverts() public { | ||
vm.expectRevert(Ownable2Step.CannotTransferToSelf.selector); | ||
s_ownable2Step.transferOwnership(OWNER); | ||
} | ||
} | ||
|
||
contract Ownable2Step_acceptOwnership is Ownable2Step_setup { | ||
function test_acceptOwnership_success() public { | ||
s_ownable2Step.transferOwnership(STRANGER); | ||
|
||
assertTrue(STRANGER != s_ownable2Step.owner()); | ||
|
||
vm.startPrank(STRANGER); | ||
|
||
vm.expectEmit(); | ||
emit Ownable2Step.OwnershipTransferred(OWNER, STRANGER); | ||
|
||
s_ownable2Step.acceptOwnership(); | ||
|
||
assertEq(STRANGER, s_ownable2Step.owner()); | ||
} | ||
|
||
function test_acceptOwnership_MustBeProposedOwner_reverts() public { | ||
vm.expectRevert(Ownable2Step.MustBeProposedOwner.selector); | ||
s_ownable2Step.acceptOwnership(); | ||
} | ||
} | ||
|
||
contract Ownable2StepHelper is Ownable2Step { | ||
constructor(address newOwner, address pendingOwner) Ownable2Step(newOwner, pendingOwner) {} | ||
|
||
function validateOwnership() external view { | ||
_validateOwnership(); | ||
} | ||
} | ||
|
||
contract Ownable2Step_onlyOwner is Ownable2Step_setup { | ||
function test_onlyOwner_success() public view { | ||
s_ownable2Step.validateOwnership(); | ||
} | ||
|
||
function test_onlyOwner_OnlyCallableByOwner_reverts() public { | ||
vm.stopPrank(); | ||
|
||
vm.expectRevert(Ownable2Step.OnlyCallableByOwner.selector); | ||
s_ownable2Step.validateOwnership(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
contracts/src/v0.8/shared/test/enumerable/EnumerableMapAddresses.t.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
contracts/src/v0.8/shared/test/token/ERC677/BurnMintERC677.t.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters