Skip to content
This repository was archived by the owner on Aug 26, 2024. It is now read-only.

Commit 77d8a13

Browse files
authored
Merge pull request #70 from ionicprotocol/feat/pause-guardian
Feat/pause guardian
2 parents 0cec821 + 190340a commit 77d8a13

File tree

3 files changed

+143
-0
lines changed

3 files changed

+143
-0
lines changed

contracts/GlobalPauser.sol

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity ^0.8.0;
3+
4+
import { IonicComptroller } from "./compound/ComptrollerInterface.sol";
5+
import { ICErc20 } from "./compound/CTokenInterfaces.sol";
6+
import { Ownable2Step } from "openzeppelin-contracts/contracts/access/Ownable2Step.sol";
7+
8+
interface IPoolDirectory {
9+
struct Pool {
10+
string name;
11+
address creator;
12+
address comptroller;
13+
uint256 blockPosted;
14+
uint256 timestampPosted;
15+
}
16+
17+
function getActivePools() external view returns (uint256, Pool[] memory);
18+
}
19+
20+
contract GlobalPauser is Ownable2Step {
21+
IPoolDirectory public poolDirectory;
22+
mapping(address => bool) public pauseGuardian;
23+
24+
modifier onlyPauseGuardian() {
25+
require(pauseGuardian[msg.sender], "!guardian");
26+
_;
27+
}
28+
29+
constructor(address _poolDirectory) Ownable2Step() {
30+
poolDirectory = IPoolDirectory(_poolDirectory);
31+
}
32+
33+
function setPauseGuardian(address _pauseGuardian, bool _isPauseGuardian) external onlyOwner {
34+
pauseGuardian[_pauseGuardian] = _isPauseGuardian;
35+
}
36+
37+
function pauseAll() external onlyPauseGuardian {
38+
(, IPoolDirectory.Pool[] memory pools) = poolDirectory.getActivePools();
39+
for (uint256 i = 0; i < pools.length; i++) {
40+
ICErc20[] memory markets = IonicComptroller(pools[i].comptroller).getAllMarkets();
41+
for (uint256 j = 0; j < markets.length; j++) {
42+
bool isPaused = IonicComptroller(pools[i].comptroller).borrowGuardianPaused(address(markets[j]));
43+
if (!isPaused) {
44+
IonicComptroller(pools[i].comptroller)._setBorrowPaused(markets[j], true);
45+
}
46+
47+
isPaused = IonicComptroller(pools[i].comptroller).mintGuardianPaused(address(markets[j]));
48+
if (!isPaused) {
49+
IonicComptroller(pools[i].comptroller)._setMintPaused(markets[j], true);
50+
}
51+
}
52+
}
53+
}
54+
}

contracts/test/GlobalPauser.t.sol

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity >=0.8.0;
3+
4+
import { ERC20 } from "solmate/tokens/ERC20.sol";
5+
import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
6+
7+
import "./config/BaseTest.t.sol";
8+
import { IonicComptroller } from "../compound/ComptrollerInterface.sol";
9+
import { IComptroller } from "../external/compound/IComptroller.sol";
10+
import { GlobalPauser } from "../GlobalPauser.sol";
11+
import { PoolDirectory } from "../PoolDirectory.sol";
12+
import { ICErc20 } from "../compound/CTokenInterfaces.sol";
13+
14+
import "forge-std/console.sol";
15+
16+
contract GlobalPauserTest is BaseTest {
17+
address public poolDirectory = 0x39C353Cf9041CcF467A04d0e78B63d961E81458a;
18+
address public pauseGuardian = 0xD9677b0eeafdCe6BF322d9774Bb65B1f42cF0404;
19+
address public multisig = 0x8Fba84867Ba458E7c6E2c024D2DE3d0b5C3ea1C2;
20+
GlobalPauser public pauser; // = GlobalPauser(0xe646D8Be18e545244C5E79F121202f75FA3880c8);
21+
22+
function afterForkSetUp() internal override {
23+
super.afterForkSetUp();
24+
pauser = new GlobalPauser(poolDirectory);
25+
pauser.setPauseGuardian(pauseGuardian, true);
26+
(, PoolDirectory.Pool[] memory pools) = PoolDirectory(poolDirectory).getActivePools();
27+
for (uint256 i = 0; i < pools.length; i++) {
28+
vm.prank(IonicComptroller(pools[i].comptroller).admin());
29+
IonicComptroller(pools[i].comptroller)._setPauseGuardian(address(pauser));
30+
}
31+
}
32+
33+
function testPauseNotGuardian(address sender) public debuggingOnly forkAtBlock(MODE_MAINNET, 9269895) {
34+
vm.assume(sender != pauseGuardian);
35+
vm.expectRevert(bytes("!guardian"));
36+
pauser.pauseAll();
37+
}
38+
39+
function testPauseAllMode() public debuggingOnly forkAtBlock(MODE_MAINNET, 9269895) {
40+
(, PoolDirectory.Pool[] memory pools) = PoolDirectory(poolDirectory).getActivePools();
41+
for (uint256 i = 0; i < pools.length; i++) {
42+
ICErc20[] memory markets = IonicComptroller(pools[i].comptroller).getAllMarkets();
43+
for (uint256 j = 0; j < markets.length; j++) {
44+
bool isPaused = IonicComptroller(pools[i].comptroller).borrowGuardianPaused(address(markets[j]));
45+
assertEq(isPaused, false);
46+
isPaused = IonicComptroller(pools[i].comptroller).mintGuardianPaused(address(markets[j]));
47+
assertEq(isPaused, false);
48+
}
49+
}
50+
vm.prank(pauseGuardian);
51+
pauser.pauseAll();
52+
for (uint256 i = 0; i < pools.length; i++) {
53+
ICErc20[] memory markets = IonicComptroller(pools[i].comptroller).getAllMarkets();
54+
for (uint256 j = 0; j < markets.length; j++) {
55+
bool isPaused = IonicComptroller(pools[i].comptroller).borrowGuardianPaused(address(markets[j]));
56+
assertEq(isPaused, true);
57+
isPaused = IonicComptroller(pools[i].comptroller).mintGuardianPaused(address(markets[j]));
58+
assertEq(isPaused, true);
59+
}
60+
}
61+
}
62+
63+
function testPauseAllBase() public debuggingOnly forkAtBlock(BASE_MAINNET, 15970403) {
64+
address _poolDirectory = 0xE1A3006be645a80F206311d9f18C866c204bA02f;
65+
pauser = GlobalPauser(0x48F0F46F56C2Ca5def59fd673fF69495b7272Eb0);
66+
(, PoolDirectory.Pool[] memory pools) = PoolDirectory(_poolDirectory).getActivePools();
67+
for (uint256 i = 0; i < pools.length; i++) {
68+
ICErc20[] memory markets = IonicComptroller(pools[i].comptroller).getAllMarkets();
69+
for (uint256 j = 0; j < markets.length; j++) {
70+
bool isPaused = IonicComptroller(pools[i].comptroller).borrowGuardianPaused(address(markets[j]));
71+
assertEq(isPaused, false);
72+
isPaused = IonicComptroller(pools[i].comptroller).mintGuardianPaused(address(markets[j]));
73+
assertEq(isPaused, false);
74+
}
75+
}
76+
vm.prank(pauseGuardian);
77+
pauser.pauseAll();
78+
for (uint256 i = 0; i < pools.length; i++) {
79+
ICErc20[] memory markets = IonicComptroller(pools[i].comptroller).getAllMarkets();
80+
for (uint256 j = 0; j < markets.length; j++) {
81+
bool isPaused = IonicComptroller(pools[i].comptroller).borrowGuardianPaused(address(markets[j]));
82+
assertEq(isPaused, true);
83+
isPaused = IonicComptroller(pools[i].comptroller).mintGuardianPaused(address(markets[j]));
84+
assertEq(isPaused, true);
85+
}
86+
}
87+
}
88+
}

contracts/test/config/BaseTest.t.sol

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ abstract contract BaseTest is Test {
2121
uint128 constant LINEA_MAINNET = 59144;
2222
uint128 constant ZKEVM_MAINNET = 1101;
2323
uint128 constant MODE_MAINNET = 34443;
24+
uint128 constant BASE_MAINNET = 8453;
2425

2526
// taken from ERC1967Upgrade
2627
bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;

0 commit comments

Comments
 (0)