Skip to content

Commit

Permalink
✨ pauser: accept extra pausable contracts
Browse files Browse the repository at this point in the history
  • Loading branch information
cruzdanilo committed Jul 11, 2024
1 parent 6695431 commit db31df6
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 21 deletions.
11 changes: 7 additions & 4 deletions .gas-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
27 changes: 20 additions & 7 deletions contracts/periphery/Pauser.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
65 changes: 55 additions & 10 deletions test/Pauser.t.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.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";
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}
}

0 comments on commit db31df6

Please sign in to comment.