Skip to content

Commit

Permalink
✨ pauser: implement multi-pauser
Browse files Browse the repository at this point in the history
  • Loading branch information
cruzdanilo committed Jul 11, 2024
1 parent 5a2440f commit 2732d80
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/famous-students-carry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@exactly/protocol": patch
---

✨ pauser: implement multi-pauser
4 changes: 4 additions & 0 deletions .gas-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,10 @@ 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)
PoolLibTest:testAtomicDepositBorrowRepayWithdraw() (gas: 46018)
PoolLibTest:testBackupBorrow() (gas: 33676)
PoolLibTest:testEarningsAccrual() (gas: 38999)
Expand Down
25 changes: 25 additions & 0 deletions contracts/periphery/Pauser.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.0;

import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { Auditor, Market } from "../Auditor.sol";

contract Pauser is Ownable {
Auditor public immutable auditor;

constructor(Auditor auditor_, address owner_) Ownable(owner_) {
auditor = auditor_;
}

function pause() 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();
}
}
assert(success);
}
}
96 changes: 96 additions & 0 deletions test/Pauser.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;

import { Test, stdError } from "forge-std/Test.sol";
import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import { MockERC20 } from "solmate/src/test/utils/mocks/MockERC20.sol";
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";

contract PauserTest is Test {
Auditor internal auditor;
Market internal marketA;
Market internal marketB;
Pauser internal pauser;

address internal constant BOB = address(0xb0b);

function setUp() external {
auditor = Auditor(address(new ERC1967Proxy(address(new Auditor(18)), "")));
auditor.initialize(Auditor.LiquidationIncentive(0.09e18, 0.01e18));
vm.label(address(auditor), "Auditor");

pauser = new Pauser(auditor, address(this));

MockInterestRateModel irm = new MockInterestRateModel(0.1e18);

marketA = Market(address(new ERC1967Proxy(address(new Market(new MockERC20("A", "A", 18), auditor)), "")));
marketA.initialize(
"A",
3,
1e18,
InterestRateModel(address(irm)),
0.02e18 / uint256(1 days),
1e17,
0,
0.0046e18,
0.42e18
);
marketA.grantRole(marketA.PAUSER_ROLE(), address(this));
marketA.grantRole(marketA.PAUSER_ROLE(), address(pauser));
auditor.enableMarket(marketA, new MockPriceFeed(18, 1e18), 0.8e18);
vm.label(address(marketA), "MarketA");

marketB = Market(address(new ERC1967Proxy(address(new Market(new MockERC20("B", "B", 18), auditor)), "")));
marketB.initialize(
"B",
3,
1e18,
InterestRateModel(address(irm)),
0.02e18 / uint256(1 days),
1e17,
0,
0.0046e18,
0.42e18
);
marketB.grantRole(marketB.PAUSER_ROLE(), address(this));
marketB.grantRole(marketB.PAUSER_ROLE(), address(pauser));
auditor.enableMarket(marketB, new MockPriceFeed(18, 1e18), 0.8e18);
vm.label(address(marketB), "MarketB");

vm.label(BOB, "bob");
}

function testPauserWhenMarketsAreUnpaused() external {
pauser.pause();

assertTrue(marketA.paused());
assertTrue(marketB.paused());
}

function testPauserWhenOneMarketIsPaused() external {
marketA.pause();

pauser.pause();

assertTrue(marketA.paused());
assertTrue(marketB.paused());
}

function testPauserWhenMarketsArePaused() external {
marketA.pause();
marketB.pause();

vm.expectRevert(stdError.assertionError);
pauser.pause();
}

function testPauserFromRando() external {
vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, BOB));
vm.prank(BOB);
pauser.pause();
}
}

0 comments on commit 2732d80

Please sign in to comment.