From db31df6d4e6e8b4103b35dbe38006bc83ed57333 Mon Sep 17 00:00:00 2001 From: danilo neves cruz Date: Thu, 11 Jul 2024 16:14:16 -0300 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20pauser:=20accept=20extra=20pausable?= =?UTF-8?q?=20contracts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gas-snapshot | 11 +++--- contracts/periphery/Pauser.sol | 27 ++++++++++---- test/Pauser.t.sol | 65 ++++++++++++++++++++++++++++------ 3 files changed, 82 insertions(+), 21 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index 1b9f7879..167757c3 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -281,10 +281,13 @@ MarketTest:testWithdrawAtMaturity() (gas: 304303) MarketTest:testWithdrawFromSmartPool() (gas: 279199) MarketTest:testWithdrawShouldUpdateFlexibleBorrowVariables() (gas: 863981) MarketTest:testWithdrawWhenFrozen() (gas: 325961) -PauserTest:testPauserFromRando() (gas: 32148) -PauserTest:testPauserWhenMarketsArePaused() (gas: 186899) -PauserTest:testPauserWhenMarketsAreUnpaused() (gas: 129320) -PauserTest:testPauserWhenOneMarketIsPaused() (gas: 159494) +PauserTest:testPauseProtocolFromRando() (gas: 32843) +PauserTest:testPauseProtocolWhenMarketsArePaused() (gas: 187722) +PauserTest:testPauseProtocolWhenMarketsAreUnpaused() (gas: 130060) +PauserTest:testPauseProtocolWhenOneMarketIsPaused() (gas: 160357) +PauserTest:testPauseProtocolWithExtra() (gas: 263879) +PauserTest:testPauseTargets() (gas: 459231) +PauserTest:testPauseTargetsAlreadyPaused() (gas: 500499) PoolLibTest:testAtomicDepositBorrowRepayWithdraw() (gas: 46018) PoolLibTest:testBackupBorrow() (gas: 33676) PoolLibTest:testEarningsAccrual() (gas: 38999) diff --git a/contracts/periphery/Pauser.sol b/contracts/periphery/Pauser.sol index daa3c87e..967d3ceb 100644 --- a/contracts/periphery/Pauser.sol +++ b/contracts/periphery/Pauser.sol @@ -11,15 +11,28 @@ contract Pauser is Ownable { auditor = auditor_; } - function pause() external onlyOwner { + function pause(IPausable[] calldata targets) external onlyOwner { + bool success = false; + for (uint256 i = 0; i < targets.length; ++i) success = _pause(targets[i]) || success; + assert(success); + } + + function pauseProtocol(IPausable[] calldata extra) external onlyOwner { Market[] memory markets = auditor.allMarkets(); bool success = false; - for (uint256 i = 0; i < markets.length; ++i) { - if (!markets[i].paused()) { - success = true; - markets[i].pause(); - } - } + for (uint256 i = 0; i < markets.length; ++i) success = _pause(IPausable(address(markets[i]))) || success; + for (uint256 i = 0; i < extra.length; ++i) success = _pause(extra[i]) || success; assert(success); } + + function _pause(IPausable pausable) internal returns (bool) { + if (pausable.paused()) return false; + pausable.pause(); + return true; + } +} + +interface IPausable { + function paused() external view returns (bool); + function pause() external; } diff --git a/test/Pauser.t.sol b/test/Pauser.t.sol index a617b9fc..595e5d26 100644 --- a/test/Pauser.t.sol +++ b/test/Pauser.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.0; +pragma solidity ^0.8.0; // solhint-disable-line one-contract-per-file import { Test, stdError } from "forge-std/Test.sol"; import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; @@ -8,7 +8,7 @@ import { Auditor } from "../contracts/Auditor.sol"; import { Market, InterestRateModel } from "../contracts/Market.sol"; import { MockInterestRateModel } from "../contracts/mocks/MockInterestRateModel.sol"; import { MockPriceFeed } from "../contracts/mocks/MockPriceFeed.sol"; -import { Pauser, Ownable } from "../contracts/periphery/Pauser.sol"; +import { Pauser, Ownable, IPausable } from "../contracts/periphery/Pauser.sol"; contract PauserTest is Test { Auditor internal auditor; @@ -64,33 +64,78 @@ contract PauserTest is Test { vm.label(BOB, "bob"); } - function testPauserWhenMarketsAreUnpaused() external { - pauser.pause(); + function testPauseProtocolWhenMarketsAreUnpaused() external { + pauser.pauseProtocol(new IPausable[](0)); assertTrue(marketA.paused()); assertTrue(marketB.paused()); } - function testPauserWhenOneMarketIsPaused() external { + function testPauseProtocolWhenOneMarketIsPaused() external { marketA.pause(); - pauser.pause(); + pauser.pauseProtocol(new IPausable[](0)); assertTrue(marketA.paused()); assertTrue(marketB.paused()); } - function testPauserWhenMarketsArePaused() external { + function testPauseProtocolWhenMarketsArePaused() external { marketA.pause(); marketB.pause(); vm.expectRevert(stdError.assertionError); - pauser.pause(); + pauser.pauseProtocol(new IPausable[](0)); } - function testPauserFromRando() external { + function testPauseProtocolFromRando() external { vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, BOB)); vm.prank(BOB); - pauser.pause(); + pauser.pauseProtocol(new IPausable[](0)); + } + + function testPauseProtocolWithExtra() external { + IPausable[] memory extra = new IPausable[](1); + extra[0] = new Pausable(); + + pauser.pauseProtocol(extra); + + assertTrue(marketA.paused()); + assertTrue(marketB.paused()); + assertTrue(extra[0].paused()); + } + + function testPauseTargets() external { + IPausable[] memory targets = new IPausable[](3); + for (uint256 i = 0; i < targets.length; ++i) targets[i] = new Pausable(); + + pauser.pause(targets); + + assertFalse(marketA.paused()); + assertFalse(marketB.paused()); + for (uint256 i = 0; i < targets.length; ++i) assertTrue(targets[i].paused()); + } + + function testPauseTargetsAlreadyPaused() external { + IPausable[] memory targets = new IPausable[](3); + for (uint256 i = 0; i < targets.length; ++i) { + targets[i] = new Pausable(); + targets[i].pause(); + } + + vm.expectRevert(stdError.assertionError); + pauser.pause(targets); + } +} + +contract Pausable is IPausable { + bool internal paused_; + + function paused() external view override returns (bool) { + return paused_; + } + + function pause() external override { + paused_ = true; } }