Skip to content

Commit 2b61d7a

Browse files
authored
Merge pull request #105 from NFTX-project/fail-safe
create FailSafe
2 parents a8bd777 + 4808d93 commit 2b61d7a

File tree

2 files changed

+156
-0
lines changed

2 files changed

+156
-0
lines changed

src/FailSafe.sol

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity =0.8.15;
3+
4+
// inheriting
5+
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
6+
7+
interface IPausable {
8+
function pause(uint256 lockId) external;
9+
}
10+
11+
/**
12+
* @title Fail Safe
13+
* @author @apoorvlathey
14+
*
15+
* @notice Pause all operations at once. This contract must be set as guardian.
16+
*/
17+
contract FailSafe is Ownable {
18+
struct Contract {
19+
address addr;
20+
uint256 lastLockId;
21+
}
22+
23+
Contract[] public contracts;
24+
25+
constructor(Contract[] memory _contracts) {
26+
setContracts(_contracts);
27+
}
28+
29+
function pauseAll() external onlyOwner {
30+
uint256 len = contracts.length;
31+
for (uint256 i; i < len; ) {
32+
Contract storage c = contracts[i];
33+
34+
for (uint256 j; j <= c.lastLockId; ) {
35+
IPausable(c.addr).pause(j);
36+
37+
unchecked {
38+
++j;
39+
}
40+
}
41+
42+
unchecked {
43+
++i;
44+
}
45+
}
46+
}
47+
48+
function setContracts(Contract[] memory _contracts) public onlyOwner {
49+
delete contracts;
50+
51+
uint256 len = _contracts.length;
52+
for (uint256 i; i < len; ) {
53+
contracts.push(_contracts[i]);
54+
55+
unchecked {
56+
++i;
57+
}
58+
}
59+
}
60+
}

test/FailSafe.t.sol

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity =0.8.15;
3+
4+
import {console} from "forge-std/Test.sol";
5+
import {TickHelpers} from "@src/lib/TickHelpers.sol";
6+
7+
import {FailSafe} from "@src/FailSafe.sol";
8+
import {Pausable} from "@src/custom/Pausable.sol";
9+
10+
import {TestBase} from "@test/TestBase.sol";
11+
12+
contract FailSafeTests is TestBase {
13+
FailSafe failsafe;
14+
15+
uint256 constant INVENTORY_LOCK_ID_DEPOSIT = 0;
16+
uint256 constant INVENTORY_LOCK_ID_DEPOSIT_WITH_NFT = 1;
17+
uint256 constant INVENTORY_LOCK_ID_WITHDRAW = 2;
18+
uint256 constant INVENTORY_LOCK_ID_COLLECT_WETH_FEES = 3;
19+
uint256 constant INVENTORY_LOCK_ID_INCREASE_POSITION = 4;
20+
21+
uint256 constant VAULT_FACTORY_LOCK_ID_CREATE_VAULT = 0;
22+
23+
uint256 constant FEE_DISTRIBUTOR_LOCK_ID_DISTRIBUTE = 0;
24+
uint256 constant FEE_DISTRIBUTOR_LOCK_ID_DISTRIBUTE_VTOKENS = 1;
25+
26+
uint256 constant NFTX_ROUTER_LOCK_ID_ADDLIQ = 0;
27+
uint256 constant NFTX_ROUTER_LOCK_ID_INCREASELIQ = 1;
28+
uint256 constant NFTX_ROUTER_LOCK_ID_REMOVELIQ = 2;
29+
uint256 constant NFTX_ROUTER_LOCK_ID_SELLNFTS = 3;
30+
uint256 constant NFTX_ROUTER_LOCK_ID_BUYNFTS = 4;
31+
32+
function setUp() public override {
33+
super.setUp();
34+
35+
FailSafe.Contract[] memory contracts = new FailSafe.Contract[](4);
36+
contracts[0] = FailSafe.Contract({
37+
addr: address(inventoryStaking),
38+
lastLockId: 4
39+
});
40+
contracts[1] = FailSafe.Contract({
41+
addr: address(vaultFactory),
42+
lastLockId: 0
43+
});
44+
contracts[2] = FailSafe.Contract({
45+
addr: address(feeDistributor),
46+
lastLockId: 1
47+
});
48+
contracts[3] = FailSafe.Contract({
49+
addr: address(nftxRouter),
50+
lastLockId: 4
51+
});
52+
53+
failsafe = new FailSafe(contracts);
54+
55+
// add the failsafe as guardian
56+
for (uint256 i; i < contracts.length; i++) {
57+
Pausable(contracts[i].addr).setIsGuardian(address(failsafe), true);
58+
}
59+
}
60+
61+
function test_FailSafe_pauseAll_RevertsForNonOwner() external {
62+
hoax(makeAddr("nonOwner"));
63+
vm.expectRevert("Ownable: caller is not the owner");
64+
failsafe.pauseAll();
65+
}
66+
67+
function test_FailSafe_pauseAll_Success() external {
68+
failsafe.pauseAll();
69+
70+
// check if all operations are paused
71+
assertTrue(inventoryStaking.isPaused(INVENTORY_LOCK_ID_DEPOSIT));
72+
assertTrue(
73+
inventoryStaking.isPaused(INVENTORY_LOCK_ID_DEPOSIT_WITH_NFT)
74+
);
75+
assertTrue(inventoryStaking.isPaused(INVENTORY_LOCK_ID_WITHDRAW));
76+
assertTrue(
77+
inventoryStaking.isPaused(INVENTORY_LOCK_ID_COLLECT_WETH_FEES)
78+
);
79+
assertTrue(
80+
inventoryStaking.isPaused(INVENTORY_LOCK_ID_INCREASE_POSITION)
81+
);
82+
83+
assertTrue(vaultFactory.isPaused(VAULT_FACTORY_LOCK_ID_CREATE_VAULT));
84+
85+
assertTrue(feeDistributor.isPaused(FEE_DISTRIBUTOR_LOCK_ID_DISTRIBUTE));
86+
assertTrue(
87+
feeDistributor.isPaused(FEE_DISTRIBUTOR_LOCK_ID_DISTRIBUTE_VTOKENS)
88+
);
89+
90+
assertTrue(nftxRouter.isPaused(NFTX_ROUTER_LOCK_ID_ADDLIQ));
91+
assertTrue(nftxRouter.isPaused(NFTX_ROUTER_LOCK_ID_INCREASELIQ));
92+
assertTrue(nftxRouter.isPaused(NFTX_ROUTER_LOCK_ID_REMOVELIQ));
93+
assertTrue(nftxRouter.isPaused(NFTX_ROUTER_LOCK_ID_SELLNFTS));
94+
assertTrue(nftxRouter.isPaused(NFTX_ROUTER_LOCK_ID_BUYNFTS));
95+
}
96+
}

0 commit comments

Comments
 (0)