Skip to content

Commit e2a34ef

Browse files
committed
FailSafe: add guardians
1 parent 7c66adf commit e2a34ef

File tree

3 files changed

+89
-5
lines changed

3 files changed

+89
-5
lines changed

deploy/scripts/TransferOwnership.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
1515
"DefaultProxyAdmin",
1616
"MarketplaceUniversalRouterZap",
1717
"MigratorZap",
18-
"FailSafe",
1918
"NFTXFeeDistributorV3",
2019
"NFTXInventoryStakingV3Upgradeable",
2120
"NFTXRouter",

src/FailSafe.sol

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,36 @@ interface IPausable {
1515
* @notice Pause all operations at once. This contract must be set as guardian.
1616
*/
1717
contract FailSafe is Ownable {
18+
// types
1819
struct Contract {
1920
address addr;
2021
uint256 lastLockId;
2122
}
2223

24+
// storage
2325
Contract[] public contracts;
26+
mapping(address => bool) public isGuardian;
27+
28+
// events
29+
event SetIsGuardian(address addr, bool isGuardian);
30+
31+
// errors
32+
error NotGuardian();
2433

2534
constructor(Contract[] memory _contracts) {
2635
setContracts(_contracts);
36+
isGuardian[msg.sender] = true;
37+
}
38+
39+
// modifiers
40+
modifier onlyGuardian() {
41+
if (!isGuardian[msg.sender]) revert NotGuardian();
42+
_;
2743
}
2844

29-
function pauseAll() external onlyOwner {
45+
// external functions
46+
// onlyGuardian
47+
function pauseAll() external onlyGuardian {
3048
uint256 len = contracts.length;
3149
for (uint256 i; i < len; ) {
3250
Contract storage c = contracts[i];
@@ -45,6 +63,7 @@ contract FailSafe is Ownable {
4563
}
4664
}
4765

66+
// onlyOwner
4867
function setContracts(Contract[] memory _contracts) public onlyOwner {
4968
delete contracts;
5069

@@ -57,4 +76,9 @@ contract FailSafe is Ownable {
5776
}
5877
}
5978
}
79+
80+
function setIsGuardian(address addr, bool _isGuardian) external onlyOwner {
81+
isGuardian[addr] = _isGuardian;
82+
emit SetIsGuardian(addr, _isGuardian);
83+
}
6084
}

test/FailSafe.t.sol

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,19 @@ contract FailSafeTests is TestBase {
5858
}
5959
}
6060

61-
function test_FailSafe_pauseAll_RevertsForNonOwner() external {
62-
hoax(makeAddr("nonOwner"));
63-
vm.expectRevert("Ownable: caller is not the owner");
61+
// FailSafe#pauseAll
62+
63+
function test_FailSafe_pauseAll_RevertsForNonGuardian() external {
64+
hoax(makeAddr("nonGuardian"));
65+
vm.expectRevert(FailSafe.NotGuardian.selector);
6466
failsafe.pauseAll();
6567
}
6668

6769
function test_FailSafe_pauseAll_Success() external {
70+
address newGuardian = makeAddr("newGuardian");
71+
failsafe.setIsGuardian(newGuardian, true);
72+
startHoax(newGuardian);
73+
6874
failsafe.pauseAll();
6975

7076
// check if all operations are paused
@@ -93,4 +99,59 @@ contract FailSafeTests is TestBase {
9399
assertTrue(nftxRouter.isPaused(NFTX_ROUTER_LOCK_ID_SELLNFTS));
94100
assertTrue(nftxRouter.isPaused(NFTX_ROUTER_LOCK_ID_BUYNFTS));
95101
}
102+
103+
// FailSafe#setContracts
104+
105+
function test_FailSafe_setContracts_RevertsForNonOwner() external {
106+
hoax(makeAddr("nonOwner"));
107+
vm.expectRevert(OWNABLE_NOT_OWNER_ERROR);
108+
failsafe.setContracts(new FailSafe.Contract[](0));
109+
}
110+
111+
function test_FailSafe_setContracts_Success() external {
112+
FailSafe.Contract[] memory contracts = new FailSafe.Contract[](5);
113+
contracts[0] = FailSafe.Contract({
114+
addr: address(inventoryStaking),
115+
lastLockId: 4
116+
});
117+
contracts[1] = FailSafe.Contract({
118+
addr: address(vaultFactory),
119+
lastLockId: 0
120+
});
121+
contracts[2] = FailSafe.Contract({
122+
addr: address(feeDistributor),
123+
lastLockId: 1
124+
});
125+
contracts[3] = FailSafe.Contract({
126+
addr: address(nftxRouter),
127+
lastLockId: 4
128+
});
129+
contracts[4] = FailSafe.Contract({
130+
addr: makeAddr("newContract"),
131+
lastLockId: 5
132+
});
133+
134+
failsafe.setContracts(contracts);
135+
136+
// check if the contracts are set
137+
for (uint256 i; i < contracts.length; i++) {
138+
(address addr, uint256 lastLockId) = failsafe.contracts(i);
139+
assertEq(addr, contracts[i].addr);
140+
assertEq(lastLockId, contracts[i].lastLockId);
141+
}
142+
}
143+
144+
// FailSafe#setIsGuardian
145+
function test_FailSafe_setIsGuardian_RevertsForNonOwner() external {
146+
hoax(makeAddr("nonOwner"));
147+
vm.expectRevert(OWNABLE_NOT_OWNER_ERROR);
148+
failsafe.setIsGuardian(makeAddr("addr"), true);
149+
}
150+
151+
function test_FailSafe_setIsGuardian_Success() external {
152+
address newGuardian = makeAddr("newGuardian");
153+
failsafe.setIsGuardian(newGuardian, true);
154+
155+
assertTrue(failsafe.isGuardian(newGuardian));
156+
}
96157
}

0 commit comments

Comments
 (0)