Skip to content

Commit

Permalink
add ownable2step (#14989)
Browse files Browse the repository at this point in the history
  • Loading branch information
RensR committed Nov 28, 2024
1 parent 4b0c72e commit a0dfd3a
Show file tree
Hide file tree
Showing 12 changed files with 221 additions and 33 deletions.
2 changes: 1 addition & 1 deletion contracts/foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ test = 'src/v0.8/transmission/test'
optimizer_runs = 1_000_000
src = 'src/v0.8/shared'
test = 'src/v0.8/shared/test'
solc_version = '0.8.19'
solc_version = '0.8.24'


# See more config options https://github.com/foundry-rs/foundry/tree/master/config
58 changes: 33 additions & 25 deletions contracts/gas-snapshots/shared.gas-snapshot
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
AuthorizedCallers_applyAuthorizedCallerUpdates:test_AddAndRemove_Success() (gas: 125205)
AuthorizedCallers_applyAuthorizedCallerUpdates:test_OnlyAdd_Success() (gas: 133100)
AuthorizedCallers_applyAuthorizedCallerUpdates:test_OnlyCallableByOwner_Revert() (gas: 12350)
AuthorizedCallers_applyAuthorizedCallerUpdates:test_OnlyRemove_Success() (gas: 45064)
AuthorizedCallers_applyAuthorizedCallerUpdates:test_RemoveThenAdd_Success() (gas: 57241)
AuthorizedCallers_applyAuthorizedCallerUpdates:test_SkipRemove_Success() (gas: 32121)
AuthorizedCallers_applyAuthorizedCallerUpdates:test_ZeroAddressNotAllowed_Revert() (gas: 64473)
AuthorizedCallers_constructor:test_ZeroAddressNotAllowed_Revert() (gas: 64473)
AuthorizedCallers_constructor:test_constructor_Success() (gas: 720513)
AuthorizedCallers_applyAuthorizedCallerUpdates:test_AddAndRemove_Success() (gas: 125022)
AuthorizedCallers_applyAuthorizedCallerUpdates:test_OnlyAdd_Success() (gas: 132980)
AuthorizedCallers_applyAuthorizedCallerUpdates:test_OnlyCallableByOwner_Revert() (gas: 12356)
AuthorizedCallers_applyAuthorizedCallerUpdates:test_OnlyRemove_Success() (gas: 45007)
AuthorizedCallers_applyAuthorizedCallerUpdates:test_RemoveThenAdd_Success() (gas: 57121)
AuthorizedCallers_applyAuthorizedCallerUpdates:test_SkipRemove_Success() (gas: 32064)
AuthorizedCallers_applyAuthorizedCallerUpdates:test_ZeroAddressNotAllowed_Revert() (gas: 64440)
AuthorizedCallers_constructor:test_ZeroAddressNotAllowed_Revert() (gas: 64440)
AuthorizedCallers_constructor:test_constructor_Success() (gas: 704809)
BurnMintERC677_approve:testApproveSuccess() (gas: 55512)
BurnMintERC677_approve:testInvalidAddressReverts() (gas: 10663)
BurnMintERC677_burn:testBasicBurnSuccess() (gas: 173939)
BurnMintERC677_burn:testBasicBurnSuccess() (gas: 172100)
BurnMintERC677_burn:testBurnFromZeroAddressReverts() (gas: 47201)
BurnMintERC677_burn:testExceedsBalanceReverts() (gas: 21841)
BurnMintERC677_burn:testSenderNotBurnerReverts() (gas: 13359)
Expand All @@ -21,7 +21,7 @@ BurnMintERC677_burnFromAlias:testBurnFromSuccess() (gas: 57949)
BurnMintERC677_burnFromAlias:testExceedsBalanceReverts() (gas: 35880)
BurnMintERC677_burnFromAlias:testInsufficientAllowanceReverts() (gas: 21869)
BurnMintERC677_burnFromAlias:testSenderNotBurnerReverts() (gas: 13379)
BurnMintERC677_constructor:testConstructorSuccess() (gas: 1672809)
BurnMintERC677_constructor:testConstructorSuccess() (gas: 1672812)
BurnMintERC677_decreaseApproval:testDecreaseApprovalSuccess() (gas: 31069)
BurnMintERC677_grantMintAndBurnRoles:testGrantMintAndBurnRolesSuccess() (gas: 121324)
BurnMintERC677_grantRole:testGrantBurnAccessSuccess() (gas: 53460)
Expand All @@ -34,14 +34,14 @@ BurnMintERC677_mint:testSenderNotMinterReverts() (gas: 11195)
BurnMintERC677_supportsInterface:testConstructorSuccess() (gas: 12476)
BurnMintERC677_transfer:testInvalidAddressReverts() (gas: 10639)
BurnMintERC677_transfer:testTransferSuccess() (gas: 42299)
CallWithExactGas__callWithExactGas:test_CallWithExactGasReceiverErrorSuccess() (gas: 67209)
CallWithExactGas__callWithExactGas:test_CallWithExactGasReceiverErrorSuccess() (gas: 65949)
CallWithExactGas__callWithExactGas:test_CallWithExactGasSafeReturnDataExactGas() (gas: 18324)
CallWithExactGas__callWithExactGas:test_NoContractReverts() (gas: 11559)
CallWithExactGas__callWithExactGas:test_NoGasForCallExactCheckReverts() (gas: 15788)
CallWithExactGas__callWithExactGas:test_NotEnoughGasForCallReverts() (gas: 16241)
CallWithExactGas__callWithExactGas:test_callWithExactGasSuccess(bytes,bytes4) (runs: 256, μ: 15766, ~: 15719)
CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_CallWithExactGasEvenIfTargetIsNoContractExactGasSuccess() (gas: 20116)
CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_CallWithExactGasEvenIfTargetIsNoContractReceiverErrorSuccess() (gas: 67721)
CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_CallWithExactGasEvenIfTargetIsNoContractReceiverErrorSuccess() (gas: 66461)
CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_CallWithExactGasEvenIfTargetIsNoContractSuccess(bytes,bytes4) (runs: 256, μ: 16276, ~: 16229)
CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_NoContractSuccess() (gas: 12962)
CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_NoGasForCallExactCheckReturnFalseSuccess() (gas: 13005)
Expand Down Expand Up @@ -75,20 +75,28 @@ EnumerableMapAddresses_tryGet:testBytes32TryGetSuccess() (gas: 94622)
EnumerableMapAddresses_tryGet:testBytesTryGetSuccess() (gas: 96279)
EnumerableMapAddresses_tryGet:testTryGetSuccess() (gas: 94893)
OpStackBurnMintERC677_constructor:testConstructorSuccess() (gas: 1743649)
OpStackBurnMintERC677_interfaceCompatibility:testBurnCompatibility() (gas: 298649)
OpStackBurnMintERC677_interfaceCompatibility:testBurnCompatibility() (gas: 291393)
OpStackBurnMintERC677_interfaceCompatibility:testMintCompatibility() (gas: 137957)
OpStackBurnMintERC677_interfaceCompatibility:testStaticFunctionsCompatibility() (gas: 13781)
OpStackBurnMintERC677_supportsInterface:testConstructorSuccess() (gas: 12752)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_EmptySubset_Reverts() (gas: 5460)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_EmptySuperset_Reverts() (gas: 4661)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_HasDuplicates_Reverts() (gas: 8265)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_NotASubset_Reverts() (gas: 12487)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_SingleElementSubset() (gas: 4489)
Ownable2Step_acceptOwnership:test_acceptOwnership_MustBeProposedOwner_reverts() (gas: 10360)
Ownable2Step_acceptOwnership:test_acceptOwnership_success() (gas: 31088)
Ownable2Step_constructor:test_constructor_OwnerCannotBeZero_reverts() (gas: 35858)
Ownable2Step_constructor:test_constructor_success() (gas: 10428)
Ownable2Step_onlyOwner:test_onlyOwner_OnlyCallableByOwner_reverts() (gas: 10754)
Ownable2Step_onlyOwner:test_onlyOwner_success() (gas: 7506)
Ownable2Step_transferOwnership:test_transferOwnership_CannotTransferToSelf_reverts() (gas: 10501)
Ownable2Step_transferOwnership:test_transferOwnership_success() (gas: 30140)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_EmptySubset_Reverts() (gas: 5208)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_EmptySuperset_Reverts() (gas: 4535)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_HasDuplicates_Reverts() (gas: 7761)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_NotASubset_Reverts() (gas: 11668)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_SingleElementSubset() (gas: 3922)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_SingleElementSubsetAndSuperset_Equal() (gas: 1464)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_SingleElementSubsetAndSuperset_NotEqual_Reverts() (gas: 6172)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_SubsetEqualsSuperset_NoRevert() (gas: 8867)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_SubsetLargerThanSuperset_Reverts() (gas: 16544)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_SupersetHasDuplicates_Reverts() (gas: 9420)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_UnsortedSubset_Reverts() (gas: 7380)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_UnsortedSuperset_Reverts() (gas: 9600)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_ValidSubset_Success() (gas: 6490)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_SubsetEqualsSuperset_NoRevert() (gas: 7859)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_SubsetLargerThanSuperset_Reverts() (gas: 15410)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_SupersetHasDuplicates_Reverts() (gas: 8790)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_UnsortedSubset_Reverts() (gas: 7128)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_UnsortedSuperset_Reverts() (gas: 8970)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_ValidSubset_Success() (gas: 5671)
2 changes: 1 addition & 1 deletion contracts/src/v0.8/shared/access/AuthorizedCallers.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
pragma solidity ^0.8.4;

import {OwnerIsCreator} from "./OwnerIsCreator.sol";
import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableSet.sol";
Expand Down
84 changes: 84 additions & 0 deletions contracts/src/v0.8/shared/access/Ownable2Step.sol
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();
_;
}
}
9 changes: 9 additions & 0 deletions contracts/src/v0.8/shared/access/Ownable2StepMsgSender.sol
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)) {}
}
2 changes: 1 addition & 1 deletion contracts/src/v0.8/shared/test/BaseTest.t.sol
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";

Expand Down
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 {AuthorizedCallers} from "../../access/AuthorizedCallers.sol";
import {BaseTest} from "../BaseTest.t.sol";
Expand Down
87 changes: 87 additions & 0 deletions contracts/src/v0.8/shared/test/access/Ownable2Step.t.sol
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();
}
}
2 changes: 1 addition & 1 deletion contracts/src/v0.8/shared/test/call/CallWithExactGas.t.sol
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 {CallWithExactGas} from "../../call/CallWithExactGas.sol";
import {CallWithExactGasHelper} from "./CallWithExactGasHelper.sol";
Expand Down
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.4;

import {CallWithExactGas} from "../../call/CallWithExactGas.sol";

Expand Down
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 {BaseTest} from "../BaseTest.t.sol";
import {EnumerableMapAddresses} from "../../enumerable/EnumerableMapAddresses.sol";
Expand Down
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 {IBurnMintERC20} from "../../../token/ERC20/IBurnMintERC20.sol";
import {IERC677} from "../../../token/ERC677/IERC677.sol";
Expand Down

0 comments on commit a0dfd3a

Please sign in to comment.