Skip to content

Commit

Permalink
Audit/hexens 2nd round part2.2 (#209)
Browse files Browse the repository at this point in the history
* optimization: [hexen-s8] added uncheck for binHelper#getSharesAndEffectiveAmountsIn

* refactor: make vault extends Ownable2Step instead of Ownable in case ownableship is transferred by mistake

* refactor: [hexsen-s3] update PoolManagerOwner to support 2 step poolManager ownership transfer

* optimization: added events when start, finish ownership transfer
  • Loading branch information
chefburger authored Nov 8, 2024
1 parent e4e4498 commit b186a69
Show file tree
Hide file tree
Showing 43 changed files with 230 additions and 47 deletions.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
142368
142478
2 changes: 1 addition & 1 deletion .forge-snapshots/BinMintBurnFeeHookTest#test_Burn.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
170035
170145
2 changes: 1 addition & 1 deletion .forge-snapshots/BinMintBurnFeeHookTest#test_Mint.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
410226
410336
Original file line number Diff line number Diff line change
@@ -1 +1 @@
133857
133892
Original file line number Diff line number Diff line change
@@ -1 +1 @@
142673
142717
Original file line number Diff line number Diff line change
@@ -1 +1 @@
289648
289683
2 changes: 1 addition & 1 deletion .forge-snapshots/BinPoolManagerTest#testGasBurnOneBin.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
127029
127065
2 changes: 1 addition & 1 deletion .forge-snapshots/BinPoolManagerTest#testGasDonate.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
118603
118691
Original file line number Diff line number Diff line change
@@ -1 +1 @@
968387
968475
Original file line number Diff line number Diff line change
@@ -1 +1 @@
327699
327787
Original file line number Diff line number Diff line change
@@ -1 +1 @@
337423
337511
Original file line number Diff line number Diff line change
@@ -1 +1 @@
139974
140062
Original file line number Diff line number Diff line change
@@ -1 +1 @@
173032
173098
Original file line number Diff line number Diff line change
@@ -1 +1 @@
179060
179126
Original file line number Diff line number Diff line change
@@ -1 +1 @@
133063
133129
Original file line number Diff line number Diff line change
@@ -1 +1 @@
304484
304550
Original file line number Diff line number Diff line change
@@ -1 +1 @@
149600
149710
2 changes: 1 addition & 1 deletion .forge-snapshots/CLMintBurnFeeHookTest#test_Burn.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
170881
170991
2 changes: 1 addition & 1 deletion .forge-snapshots/CLMintBurnFeeHookTest#test_Mint.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
421255
421365
Original file line number Diff line number Diff line change
@@ -1 +1 @@
347480
347568
Original file line number Diff line number Diff line change
@@ -1 +1 @@
162941
163029
Original file line number Diff line number Diff line change
@@ -1 +1 @@
238442
238486
2 changes: 1 addition & 1 deletion .forge-snapshots/CLPoolManagerTest#donateBothTokens.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
163218
163306
2 changes: 1 addition & 1 deletion .forge-snapshots/CLPoolManagerTest#gasDonateOneToken.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
108268
108334
Original file line number Diff line number Diff line change
@@ -1 +1 @@
112784
112828
Original file line number Diff line number Diff line change
@@ -1 +1 @@
130830
130896
Original file line number Diff line number Diff line change
@@ -1 +1 @@
163213
163301
Original file line number Diff line number Diff line change
@@ -1 +1 @@
148610
148676
2 changes: 1 addition & 1 deletion .forge-snapshots/CLPoolManagerTest#swap_simple.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
71289
71333
Original file line number Diff line number Diff line change
@@ -1 +1 @@
143194
143282
2 changes: 1 addition & 1 deletion .forge-snapshots/CLPoolManagerTest#swap_withHooks.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
87479
87523
2 changes: 1 addition & 1 deletion .forge-snapshots/CLPoolManagerTest#swap_withNative.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
71292
71336
2 changes: 1 addition & 1 deletion .forge-snapshots/VaultBytecodeSize.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
8131
8388
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2876
2898
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1880
1902
4 changes: 2 additions & 2 deletions src/Vault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Copyright (C) 2024 PancakeSwap
pragma solidity 0.8.26;

import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {Ownable, Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol";
import {IVault, IVaultToken} from "./interfaces/IVault.sol";
import {SettlementGuard} from "./libraries/SettlementGuard.sol";
import {Currency, CurrencyLibrary} from "./types/Currency.sol";
Expand All @@ -12,7 +12,7 @@ import {SafeCast} from "./libraries/SafeCast.sol";
import {VaultReserve} from "./libraries/VaultReserve.sol";
import {VaultToken} from "./VaultToken.sol";

contract Vault is IVault, VaultToken, Ownable {
contract Vault is IVault, VaultToken, Ownable2Step {
using SafeCast for *;
using CurrencyLibrary for Currency;

Expand Down
36 changes: 36 additions & 0 deletions src/base/PoolManagerOwnable2Step.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (C) 2024 PancakeSwap
pragma solidity 0.8.26;

import {IPoolManagerOwner} from "../interfaces/IPoolManagerOwner.sol";

/**
* @notice dev This contract implements "Ownable2Step styled" poolManager ownership transfer
* functionality. Namely an extra acceptance step is added to the ownership transfer process.
* This is done to prevent accidental ownership transfer to a wrong address.
*/
abstract contract PoolManagerOwnable2Step is IPoolManagerOwner {
error NotPendingPoolManagerOwner();

event PoolManagerOwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
event PoolManagerOwnershipTransferred(address indexed previousOwner, address indexed newOwner);

address private _pendingPoolManagerOwner;

modifier onlyPendingPoolManagerOwner() {
if (_pendingPoolManagerOwner != msg.sender) {
revert NotPendingPoolManagerOwner();
}

_;
}

function _setPendingPoolManagerOwner(address newPoolManagerOwner) internal {
_pendingPoolManagerOwner = newPoolManagerOwner;
}

/// @inheritdoc IPoolManagerOwner
function pendingPoolManagerOwner() public view override returns (address) {
return _pendingPoolManagerOwner;
}
}
12 changes: 10 additions & 2 deletions src/interfaces/IPoolManagerOwner.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ interface IPoolManagerOwner {

/// @notice transfer the ownership of pool manager to the new owner
/// @dev used when a new PoolManagerOwner contract is created and we transfer pool manager owner to new contract
/// @param newOwner the address of the new owner
function transferPoolManagerOwnership(address newOwner) external;
/// @param newPoolManagerOwner the address of the new owner
function transferPoolManagerOwnership(address newPoolManagerOwner) external;

/// @notice accept the ownership of pool manager, only callable by the
/// pending pool manager owner set by latest transferPoolManagerOwnership
function acceptPoolManagerOwnership() external;

/// @notice get the current pending pool manager owner
/// @return the address of the pending pool manager owner
function pendingPoolManagerOwner() external view returns (address);
}
15 changes: 12 additions & 3 deletions src/pool-bin/BinPoolManagerOwner.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pragma solidity 0.8.26;

import {IProtocolFeeController} from "../interfaces/IProtocolFeeController.sol";
import {PausableRole} from "../base/PausableRole.sol";
import {PoolManagerOwnable2Step} from "../base/PoolManagerOwnable2Step.sol";
import {IBinPoolManager} from "./interfaces/IBinPoolManager.sol";
import {IPoolManagerOwner} from "../interfaces/IPoolManagerOwner.sol";

Expand All @@ -20,7 +21,7 @@ interface IBinPoolManagerWithPauseOwnable is IBinPoolManager {
* A seperate owner contract is used to handle some functionality so as to reduce the contract size
* of PoolManager. This allow a higher optimizer run, reducing the gas cost for other poolManager functions
*/
contract BinPoolManagerOwner is IPoolManagerOwner, PausableRole {
contract BinPoolManagerOwner is IPoolManagerOwner, PoolManagerOwnable2Step, PausableRole {
/// @notice Error thrown when owner set min share too small
error MinShareTooSmall(uint256 minShare);

Expand All @@ -46,8 +47,16 @@ contract BinPoolManagerOwner is IPoolManagerOwner, PausableRole {
}

/// @inheritdoc IPoolManagerOwner
function transferPoolManagerOwnership(address newOwner) external override onlyOwner {
poolManager.transferOwnership(newOwner);
function transferPoolManagerOwnership(address newPoolManagerOwner) external override onlyOwner {
_setPendingPoolManagerOwner(newPoolManagerOwner);
emit PoolManagerOwnershipTransferStarted(address(this), newPoolManagerOwner);
}

/// @inheritdoc IPoolManagerOwner
function acceptPoolManagerOwnership() external override onlyPendingPoolManagerOwner {
_setPendingPoolManagerOwner(address(0));
poolManager.transferOwnership(msg.sender);
emit PoolManagerOwnershipTransferred(address(this), msg.sender);
}

/// @notice Set max bin steps for binPoolManager, see IBinPoolManager for more documentation about this function
Expand Down
16 changes: 13 additions & 3 deletions src/pool-cl/CLPoolManagerOwner.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pragma solidity 0.8.26;

import {IProtocolFeeController} from "../interfaces/IProtocolFeeController.sol";
import {PausableRole} from "../base/PausableRole.sol";
import {PoolManagerOwnable2Step} from "../base/PoolManagerOwnable2Step.sol";
import {ICLPoolManager} from "./interfaces/ICLPoolManager.sol";
import {IPoolManagerOwner} from "../interfaces/IPoolManagerOwner.sol";

Expand All @@ -20,7 +21,7 @@ interface ICLPoolManagerWithPauseOwnable is ICLPoolManager {
* A seperate owner contract is used to handle some functionality so as to reduce the contract size
* of PoolManager. This allow a higher optimizer run, reducing the gas cost for other poolManager functions.
*/
contract CLPoolManagerOwner is IPoolManagerOwner, PausableRole {
contract CLPoolManagerOwner is IPoolManagerOwner, PoolManagerOwnable2Step, PausableRole {
ICLPoolManagerWithPauseOwnable public immutable poolManager;

constructor(ICLPoolManagerWithPauseOwnable _poolManager) {
Expand All @@ -43,7 +44,16 @@ contract CLPoolManagerOwner is IPoolManagerOwner, PausableRole {
}

/// @inheritdoc IPoolManagerOwner
function transferPoolManagerOwnership(address newOwner) external override onlyOwner {
poolManager.transferOwnership(newOwner);
function transferPoolManagerOwnership(address newPoolManagerOwner) external override onlyOwner {
_setPendingPoolManagerOwner(newPoolManagerOwner);
emit PoolManagerOwnershipTransferStarted(address(this), newPoolManagerOwner);
}

/// @inheritdoc IPoolManagerOwner
function acceptPoolManagerOwnership() external override onlyPendingPoolManagerOwner {
_setPendingPoolManagerOwner(address(0));
poolManager.transferOwnership(msg.sender);

emit PoolManagerOwnershipTransferred(address(this), msg.sender);
}
}
48 changes: 47 additions & 1 deletion test/pool-bin/BinPoolManagerOwner.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {IVault} from "../../src/interfaces/IVault.sol";
import {Vault} from "../../src/Vault.sol";
import {BinPoolManager} from "../../src/pool-bin/BinPoolManager.sol";
import {BinPoolManagerOwner, IBinPoolManagerWithPauseOwnable} from "../../src/pool-bin/BinPoolManagerOwner.sol";
import {PoolManagerOwnable2Step} from "../../src/base/PoolManagerOwnable2Step.sol";
import {Pausable} from "../../src/base/Pausable.sol";
import {PausableRole} from "../../src/base/PausableRole.sol";

Expand Down Expand Up @@ -110,8 +111,19 @@ contract BinPoolManagerOwnerTest is Test {
// before:
assertEq(poolManager.owner(), address(binPoolManagerOwner));

// after:
// pending:
// it's still the original owner if new owner not accept yet
vm.expectEmit(true, true, true, true);
emit PoolManagerOwnable2Step.PoolManagerOwnershipTransferStarted(address(binPoolManagerOwner), alice);
binPoolManagerOwner.transferPoolManagerOwnership(alice);
assertEq(poolManager.owner(), address(binPoolManagerOwner));
assertEq(binPoolManagerOwner.pendingPoolManagerOwner(), alice);

// after:
vm.expectEmit(true, true, true, true);
emit PoolManagerOwnable2Step.PoolManagerOwnershipTransferred(address(binPoolManagerOwner), alice);
vm.prank(alice);
binPoolManagerOwner.acceptPoolManagerOwnership();
assertEq(poolManager.owner(), alice);
}

Expand All @@ -122,6 +134,40 @@ contract BinPoolManagerOwnerTest is Test {
binPoolManagerOwner.transferPoolManagerOwnership(alice);
}

function test_TransferPoolManagerOwnership_NotPendingPoolManagerOwner() public {
binPoolManagerOwner.transferPoolManagerOwnership(alice);

// if it's not from alice then revert
vm.expectRevert(PoolManagerOwnable2Step.NotPendingPoolManagerOwner.selector);
binPoolManagerOwner.acceptPoolManagerOwnership();
}

function test_TransferPoolManagerOwnership_OverridePendingOwner() public {
// before:
assertEq(poolManager.owner(), address(binPoolManagerOwner));

// pending:
// it's still the original owner if new owner not accept yet
binPoolManagerOwner.transferPoolManagerOwnership(alice);
assertEq(poolManager.owner(), address(binPoolManagerOwner));
assertEq(binPoolManagerOwner.pendingPoolManagerOwner(), alice);

// override pending owner
binPoolManagerOwner.transferPoolManagerOwnership(makeAddr("bob"));
assertEq(poolManager.owner(), address(binPoolManagerOwner));
assertEq(binPoolManagerOwner.pendingPoolManagerOwner(), makeAddr("bob"));

// alice no longer the valid pending owner
vm.expectRevert(PoolManagerOwnable2Step.NotPendingPoolManagerOwner.selector);
vm.prank(alice);
binPoolManagerOwner.acceptPoolManagerOwnership();

// bob is the new owner
vm.prank(makeAddr("bob"));
binPoolManagerOwner.acceptPoolManagerOwnership();
assertEq(poolManager.owner(), makeAddr("bob"));
}

function test_SetMaxBinStep_OnlyOwner() public {
// before
assertEq(poolManager.maxBinStep(), 100);
Expand Down
Loading

0 comments on commit b186a69

Please sign in to comment.