Skip to content
This repository was archived by the owner on Mar 14, 2025. It is now read-only.

Commit a0dfd3a

Browse files
committed
add ownable2step (#14989)
1 parent 4b0c72e commit a0dfd3a

File tree

12 files changed

+221
-33
lines changed

12 files changed

+221
-33
lines changed

contracts/foundry.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ test = 'src/v0.8/transmission/test'
9595
optimizer_runs = 1_000_000
9696
src = 'src/v0.8/shared'
9797
test = 'src/v0.8/shared/test'
98-
solc_version = '0.8.19'
98+
solc_version = '0.8.24'
9999

100100

101101
# See more config options https://github.com/foundry-rs/foundry/tree/master/config

contracts/gas-snapshots/shared.gas-snapshot

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
AuthorizedCallers_applyAuthorizedCallerUpdates:test_AddAndRemove_Success() (gas: 125205)
2-
AuthorizedCallers_applyAuthorizedCallerUpdates:test_OnlyAdd_Success() (gas: 133100)
3-
AuthorizedCallers_applyAuthorizedCallerUpdates:test_OnlyCallableByOwner_Revert() (gas: 12350)
4-
AuthorizedCallers_applyAuthorizedCallerUpdates:test_OnlyRemove_Success() (gas: 45064)
5-
AuthorizedCallers_applyAuthorizedCallerUpdates:test_RemoveThenAdd_Success() (gas: 57241)
6-
AuthorizedCallers_applyAuthorizedCallerUpdates:test_SkipRemove_Success() (gas: 32121)
7-
AuthorizedCallers_applyAuthorizedCallerUpdates:test_ZeroAddressNotAllowed_Revert() (gas: 64473)
8-
AuthorizedCallers_constructor:test_ZeroAddressNotAllowed_Revert() (gas: 64473)
9-
AuthorizedCallers_constructor:test_constructor_Success() (gas: 720513)
1+
AuthorizedCallers_applyAuthorizedCallerUpdates:test_AddAndRemove_Success() (gas: 125022)
2+
AuthorizedCallers_applyAuthorizedCallerUpdates:test_OnlyAdd_Success() (gas: 132980)
3+
AuthorizedCallers_applyAuthorizedCallerUpdates:test_OnlyCallableByOwner_Revert() (gas: 12356)
4+
AuthorizedCallers_applyAuthorizedCallerUpdates:test_OnlyRemove_Success() (gas: 45007)
5+
AuthorizedCallers_applyAuthorizedCallerUpdates:test_RemoveThenAdd_Success() (gas: 57121)
6+
AuthorizedCallers_applyAuthorizedCallerUpdates:test_SkipRemove_Success() (gas: 32064)
7+
AuthorizedCallers_applyAuthorizedCallerUpdates:test_ZeroAddressNotAllowed_Revert() (gas: 64440)
8+
AuthorizedCallers_constructor:test_ZeroAddressNotAllowed_Revert() (gas: 64440)
9+
AuthorizedCallers_constructor:test_constructor_Success() (gas: 704809)
1010
BurnMintERC677_approve:testApproveSuccess() (gas: 55512)
1111
BurnMintERC677_approve:testInvalidAddressReverts() (gas: 10663)
12-
BurnMintERC677_burn:testBasicBurnSuccess() (gas: 173939)
12+
BurnMintERC677_burn:testBasicBurnSuccess() (gas: 172100)
1313
BurnMintERC677_burn:testBurnFromZeroAddressReverts() (gas: 47201)
1414
BurnMintERC677_burn:testExceedsBalanceReverts() (gas: 21841)
1515
BurnMintERC677_burn:testSenderNotBurnerReverts() (gas: 13359)
@@ -21,7 +21,7 @@ BurnMintERC677_burnFromAlias:testBurnFromSuccess() (gas: 57949)
2121
BurnMintERC677_burnFromAlias:testExceedsBalanceReverts() (gas: 35880)
2222
BurnMintERC677_burnFromAlias:testInsufficientAllowanceReverts() (gas: 21869)
2323
BurnMintERC677_burnFromAlias:testSenderNotBurnerReverts() (gas: 13379)
24-
BurnMintERC677_constructor:testConstructorSuccess() (gas: 1672809)
24+
BurnMintERC677_constructor:testConstructorSuccess() (gas: 1672812)
2525
BurnMintERC677_decreaseApproval:testDecreaseApprovalSuccess() (gas: 31069)
2626
BurnMintERC677_grantMintAndBurnRoles:testGrantMintAndBurnRolesSuccess() (gas: 121324)
2727
BurnMintERC677_grantRole:testGrantBurnAccessSuccess() (gas: 53460)
@@ -34,14 +34,14 @@ BurnMintERC677_mint:testSenderNotMinterReverts() (gas: 11195)
3434
BurnMintERC677_supportsInterface:testConstructorSuccess() (gas: 12476)
3535
BurnMintERC677_transfer:testInvalidAddressReverts() (gas: 10639)
3636
BurnMintERC677_transfer:testTransferSuccess() (gas: 42299)
37-
CallWithExactGas__callWithExactGas:test_CallWithExactGasReceiverErrorSuccess() (gas: 67209)
37+
CallWithExactGas__callWithExactGas:test_CallWithExactGasReceiverErrorSuccess() (gas: 65949)
3838
CallWithExactGas__callWithExactGas:test_CallWithExactGasSafeReturnDataExactGas() (gas: 18324)
3939
CallWithExactGas__callWithExactGas:test_NoContractReverts() (gas: 11559)
4040
CallWithExactGas__callWithExactGas:test_NoGasForCallExactCheckReverts() (gas: 15788)
4141
CallWithExactGas__callWithExactGas:test_NotEnoughGasForCallReverts() (gas: 16241)
4242
CallWithExactGas__callWithExactGas:test_callWithExactGasSuccess(bytes,bytes4) (runs: 256, μ: 15766, ~: 15719)
4343
CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_CallWithExactGasEvenIfTargetIsNoContractExactGasSuccess() (gas: 20116)
44-
CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_CallWithExactGasEvenIfTargetIsNoContractReceiverErrorSuccess() (gas: 67721)
44+
CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_CallWithExactGasEvenIfTargetIsNoContractReceiverErrorSuccess() (gas: 66461)
4545
CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_CallWithExactGasEvenIfTargetIsNoContractSuccess(bytes,bytes4) (runs: 256, μ: 16276, ~: 16229)
4646
CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_NoContractSuccess() (gas: 12962)
4747
CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_NoGasForCallExactCheckReturnFalseSuccess() (gas: 13005)
@@ -75,20 +75,28 @@ EnumerableMapAddresses_tryGet:testBytes32TryGetSuccess() (gas: 94622)
7575
EnumerableMapAddresses_tryGet:testBytesTryGetSuccess() (gas: 96279)
7676
EnumerableMapAddresses_tryGet:testTryGetSuccess() (gas: 94893)
7777
OpStackBurnMintERC677_constructor:testConstructorSuccess() (gas: 1743649)
78-
OpStackBurnMintERC677_interfaceCompatibility:testBurnCompatibility() (gas: 298649)
78+
OpStackBurnMintERC677_interfaceCompatibility:testBurnCompatibility() (gas: 291393)
7979
OpStackBurnMintERC677_interfaceCompatibility:testMintCompatibility() (gas: 137957)
8080
OpStackBurnMintERC677_interfaceCompatibility:testStaticFunctionsCompatibility() (gas: 13781)
8181
OpStackBurnMintERC677_supportsInterface:testConstructorSuccess() (gas: 12752)
82-
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_EmptySubset_Reverts() (gas: 5460)
83-
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_EmptySuperset_Reverts() (gas: 4661)
84-
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_HasDuplicates_Reverts() (gas: 8265)
85-
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_NotASubset_Reverts() (gas: 12487)
86-
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_SingleElementSubset() (gas: 4489)
82+
Ownable2Step_acceptOwnership:test_acceptOwnership_MustBeProposedOwner_reverts() (gas: 10360)
83+
Ownable2Step_acceptOwnership:test_acceptOwnership_success() (gas: 31088)
84+
Ownable2Step_constructor:test_constructor_OwnerCannotBeZero_reverts() (gas: 35858)
85+
Ownable2Step_constructor:test_constructor_success() (gas: 10428)
86+
Ownable2Step_onlyOwner:test_onlyOwner_OnlyCallableByOwner_reverts() (gas: 10754)
87+
Ownable2Step_onlyOwner:test_onlyOwner_success() (gas: 7506)
88+
Ownable2Step_transferOwnership:test_transferOwnership_CannotTransferToSelf_reverts() (gas: 10501)
89+
Ownable2Step_transferOwnership:test_transferOwnership_success() (gas: 30140)
90+
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_EmptySubset_Reverts() (gas: 5208)
91+
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_EmptySuperset_Reverts() (gas: 4535)
92+
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_HasDuplicates_Reverts() (gas: 7761)
93+
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_NotASubset_Reverts() (gas: 11668)
94+
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_SingleElementSubset() (gas: 3922)
8795
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_SingleElementSubsetAndSuperset_Equal() (gas: 1464)
8896
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_SingleElementSubsetAndSuperset_NotEqual_Reverts() (gas: 6172)
89-
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_SubsetEqualsSuperset_NoRevert() (gas: 8867)
90-
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_SubsetLargerThanSuperset_Reverts() (gas: 16544)
91-
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_SupersetHasDuplicates_Reverts() (gas: 9420)
92-
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_UnsortedSubset_Reverts() (gas: 7380)
93-
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_UnsortedSuperset_Reverts() (gas: 9600)
94-
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_ValidSubset_Success() (gas: 6490)
97+
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_SubsetEqualsSuperset_NoRevert() (gas: 7859)
98+
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_SubsetLargerThanSuperset_Reverts() (gas: 15410)
99+
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_SupersetHasDuplicates_Reverts() (gas: 8790)
100+
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_UnsortedSubset_Reverts() (gas: 7128)
101+
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_UnsortedSuperset_Reverts() (gas: 8970)
102+
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_ValidSubset_Success() (gas: 5671)

contracts/src/v0.8/shared/access/AuthorizedCallers.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// SPDX-License-Identifier: BUSL-1.1
2-
pragma solidity ^0.8.0;
2+
pragma solidity ^0.8.4;
33

44
import {OwnerIsCreator} from "./OwnerIsCreator.sol";
55
import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableSet.sol";
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.4;
3+
4+
import {IOwnable} from "../interfaces/IOwnable.sol";
5+
6+
/// @notice A minimal contract that implements 2-step ownership transfer and nothing more. It's made to be minimal
7+
/// to reduce the impact of the bytecode size on any contract that inherits from it.
8+
contract Ownable2Step is IOwnable {
9+
/// @notice The pending owner is the address to which ownership may be transferred.
10+
address private s_pendingOwner;
11+
/// @notice The owner is the current owner of the contract.
12+
/// @dev The owner is the second storage variable so any implementing contract could pack other state with it
13+
/// instead of the much less used s_pendingOwner.
14+
address private s_owner;
15+
16+
error OwnerCannotBeZero();
17+
error MustBeProposedOwner();
18+
error CannotTransferToSelf();
19+
error OnlyCallableByOwner();
20+
21+
event OwnershipTransferRequested(address indexed from, address indexed to);
22+
event OwnershipTransferred(address indexed from, address indexed to);
23+
24+
constructor(address newOwner, address pendingOwner) {
25+
if (newOwner == address(0)) {
26+
revert OwnerCannotBeZero();
27+
}
28+
29+
s_owner = newOwner;
30+
if (pendingOwner != address(0)) {
31+
_transferOwnership(pendingOwner);
32+
}
33+
}
34+
35+
/// @notice Get the current owner
36+
function owner() public view override returns (address) {
37+
return s_owner;
38+
}
39+
40+
/// @notice Allows an owner to begin transferring ownership to a new address. The new owner needs to call
41+
/// `acceptOwnership` to accept the transfer before any permissions are changed.
42+
/// @param to The address to which ownership will be transferred.
43+
function transferOwnership(address to) public override onlyOwner {
44+
_transferOwnership(to);
45+
}
46+
47+
/// @notice validate, transfer ownership, and emit relevant events
48+
/// @param to The address to which ownership will be transferred.
49+
function _transferOwnership(address to) private {
50+
if (to == msg.sender) {
51+
revert CannotTransferToSelf();
52+
}
53+
54+
s_pendingOwner = to;
55+
56+
emit OwnershipTransferRequested(s_owner, to);
57+
}
58+
59+
/// @notice Allows an ownership transfer to be completed by the recipient.
60+
function acceptOwnership() external override {
61+
if (msg.sender != s_pendingOwner) {
62+
revert MustBeProposedOwner();
63+
}
64+
65+
address oldOwner = s_owner;
66+
s_owner = msg.sender;
67+
s_pendingOwner = address(0);
68+
69+
emit OwnershipTransferred(oldOwner, msg.sender);
70+
}
71+
72+
/// @notice validate access
73+
function _validateOwnership() internal view {
74+
if (msg.sender != s_owner) {
75+
revert OnlyCallableByOwner();
76+
}
77+
}
78+
79+
/// @notice Reverts if called by anyone other than the contract owner.
80+
modifier onlyOwner() {
81+
_validateOwnership();
82+
_;
83+
}
84+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.4;
3+
4+
import {Ownable2Step} from "./Ownable2Step.sol";
5+
6+
/// @notice Sets the msg.sender to be the owner of the contract and does not set a pending owner.
7+
contract Ownable2StepMsgSender is Ownable2Step {
8+
constructor() Ownable2Step(msg.sender, address(0)) {}
9+
}

contracts/src/v0.8/shared/test/BaseTest.t.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// SPDX-License-Identifier: MIT
2-
pragma solidity 0.8.19;
2+
pragma solidity 0.8.24;
33

44
import "forge-std/Test.sol";
55

contracts/src/v0.8/shared/test/access/AuthorizedCallers.t.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// SPDX-License-Identifier: MIT
2-
pragma solidity 0.8.19;
2+
pragma solidity 0.8.24;
33

44
import {AuthorizedCallers} from "../../access/AuthorizedCallers.sol";
55
import {BaseTest} from "../BaseTest.t.sol";
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.24;
3+
4+
import {BaseTest} from "../BaseTest.t.sol";
5+
import {Ownable2Step} from "../../access/Ownable2Step.sol";
6+
7+
contract Ownable2Step_setup is BaseTest {
8+
Ownable2StepHelper internal s_ownable2Step;
9+
10+
function setUp() public override {
11+
super.setUp();
12+
s_ownable2Step = new Ownable2StepHelper(OWNER, address(0));
13+
}
14+
}
15+
16+
contract Ownable2Step_constructor is Ownable2Step_setup {
17+
function test_constructor_success() public view {
18+
assertEq(OWNER, s_ownable2Step.owner());
19+
}
20+
21+
function test_constructor_OwnerCannotBeZero_reverts() public {
22+
vm.expectRevert(Ownable2Step.OwnerCannotBeZero.selector);
23+
new Ownable2Step(address(0), address(0));
24+
}
25+
}
26+
27+
contract Ownable2Step_transferOwnership is Ownable2Step_setup {
28+
function test_transferOwnership_success() public {
29+
vm.expectEmit();
30+
emit Ownable2Step.OwnershipTransferRequested(OWNER, STRANGER);
31+
32+
s_ownable2Step.transferOwnership(STRANGER);
33+
34+
assertTrue(STRANGER != s_ownable2Step.owner());
35+
36+
vm.startPrank(STRANGER);
37+
s_ownable2Step.acceptOwnership();
38+
}
39+
40+
function test_transferOwnership_CannotTransferToSelf_reverts() public {
41+
vm.expectRevert(Ownable2Step.CannotTransferToSelf.selector);
42+
s_ownable2Step.transferOwnership(OWNER);
43+
}
44+
}
45+
46+
contract Ownable2Step_acceptOwnership is Ownable2Step_setup {
47+
function test_acceptOwnership_success() public {
48+
s_ownable2Step.transferOwnership(STRANGER);
49+
50+
assertTrue(STRANGER != s_ownable2Step.owner());
51+
52+
vm.startPrank(STRANGER);
53+
54+
vm.expectEmit();
55+
emit Ownable2Step.OwnershipTransferred(OWNER, STRANGER);
56+
57+
s_ownable2Step.acceptOwnership();
58+
59+
assertEq(STRANGER, s_ownable2Step.owner());
60+
}
61+
62+
function test_acceptOwnership_MustBeProposedOwner_reverts() public {
63+
vm.expectRevert(Ownable2Step.MustBeProposedOwner.selector);
64+
s_ownable2Step.acceptOwnership();
65+
}
66+
}
67+
68+
contract Ownable2StepHelper is Ownable2Step {
69+
constructor(address newOwner, address pendingOwner) Ownable2Step(newOwner, pendingOwner) {}
70+
71+
function validateOwnership() external view {
72+
_validateOwnership();
73+
}
74+
}
75+
76+
contract Ownable2Step_onlyOwner is Ownable2Step_setup {
77+
function test_onlyOwner_success() public view {
78+
s_ownable2Step.validateOwnership();
79+
}
80+
81+
function test_onlyOwner_OnlyCallableByOwner_reverts() public {
82+
vm.stopPrank();
83+
84+
vm.expectRevert(Ownable2Step.OnlyCallableByOwner.selector);
85+
s_ownable2Step.validateOwnership();
86+
}
87+
}

contracts/src/v0.8/shared/test/call/CallWithExactGas.t.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// SPDX-License-Identifier: MIT
2-
pragma solidity 0.8.19;
2+
pragma solidity 0.8.24;
33

44
import {CallWithExactGas} from "../../call/CallWithExactGas.sol";
55
import {CallWithExactGasHelper} from "./CallWithExactGasHelper.sol";

contracts/src/v0.8/shared/test/call/CallWithExactGasHelper.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// SPDX-License-Identifier: MIT
2-
pragma solidity 0.8.19;
2+
pragma solidity ^0.8.4;
33

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

0 commit comments

Comments
 (0)