Skip to content

Commit b60833e

Browse files
authored
Merge pull request #1623 from keep-network/panic
Panic button per operator contract with a possibility of being disabled
2 parents d7dd6f7 + 59a7f0e commit b60833e

3 files changed

Lines changed: 351 additions & 101 deletions

File tree

solidity/contracts/Registry.sol

Lines changed: 121 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,34 @@ pragma solidity 0.5.17;
66
* @dev Governance owned registry of approved contracts and roles.
77
*/
88
contract Registry {
9+
enum ContractStatus {New, Approved, Disabled}
910

10-
enum ContractStatus { New, Approved, Disabled }
11-
12-
// Governance role is to enable recovery from key compromise by rekeying other roles.
11+
// Governance role is to enable recovery from key compromise by rekeying
12+
// other roles. Also, it can disable operator contract panic buttons
13+
// permanently.
1314
address internal governance;
1415

1516
// Registry Keeper maintains approved operator contracts. Each operator
1617
// contract must be approved before it can be authorized by a staker or
1718
// used by a service contract.
1819
address internal registryKeeper;
1920

20-
// The Panic Button can disable malicious or malfunctioning contracts
21-
// that have been previously approved by the Registry Keeper.
22-
address internal panicButton;
21+
// Each operator contract has a Panic Button which can disable malicious
22+
// or malfunctioning contract that have been previously approved by the
23+
// Registry Keeper.
24+
//
25+
// New operator contract added to the registry has a default panic button
26+
// value assigned (defaultPanicButton). Panic button for each operator
27+
// contract can be later updated by Governance to individual value.
28+
//
29+
// It is possible to disable panic button for individual contract by
30+
// setting the panic button to zero address. In such case, operator contract
31+
// can not be disabled and is permanently approved in the registry.
32+
mapping(address => address) public panicButtons;
33+
34+
// Default panic button for each new operator contract added to the
35+
// registry. Can be later updated for each contract.
36+
address internal defaultPanicButton;
2337

2438
// Each service contract has a Operator Contract Upgrader whose purpose
2539
// is to manage operator contracts for that specific service contract.
@@ -35,8 +49,16 @@ contract Registry {
3549

3650
event GovernanceUpdated();
3751
event RegistryKeeperUpdated();
38-
event PanicButtonUpdated();
39-
event OperatorContractUpgraderUpdated(address serviceContract, address upgrader);
52+
event DefaultPanicButtonUpdated();
53+
event OperatorContractPanicButtonDisabled(address operatorContract);
54+
event OperatorContractPanicButtonUpdated(
55+
address operatorContract,
56+
address panicButton
57+
);
58+
event OperatorContractUpgraderUpdated(
59+
address serviceContract,
60+
address upgrader
61+
);
4062

4163
modifier onlyGovernance() {
4264
require(governance == msg.sender, "Not authorized");
@@ -48,15 +70,33 @@ contract Registry {
4870
_;
4971
}
5072

51-
modifier onlyPanicButton() {
73+
modifier onlyPanicButton(address _operatorContract) {
74+
address panicButton = panicButtons[_operatorContract];
75+
require(panicButton != address(0), "Panic button disabled");
5276
require(panicButton == msg.sender, "Not authorized");
5377
_;
5478
}
5579

80+
modifier onlyForNewContract(address _operatorContract) {
81+
require(
82+
isNewOperatorContract(_operatorContract),
83+
"Not a new operator contract"
84+
);
85+
_;
86+
}
87+
88+
modifier onlyForApprovedContract(address _operatorContract) {
89+
require(
90+
isApprovedOperatorContract(_operatorContract),
91+
"Not an approved operator contract"
92+
);
93+
_;
94+
}
95+
5696
constructor() public {
5797
governance = msg.sender;
5898
registryKeeper = msg.sender;
59-
panicButton = msg.sender;
99+
defaultPanicButton = msg.sender;
60100
}
61101

62102
function setGovernance(address _governance) public onlyGovernance {
@@ -69,45 +109,98 @@ contract Registry {
69109
emit RegistryKeeperUpdated();
70110
}
71111

72-
function setPanicButton(address _panicButton) public onlyGovernance {
73-
panicButton = _panicButton;
74-
emit PanicButtonUpdated();
112+
function setDefaultPanicButton(address _panicButton) public onlyGovernance {
113+
defaultPanicButton = _panicButton;
114+
emit DefaultPanicButtonUpdated();
75115
}
76116

77-
function setOperatorContractUpgrader(address _serviceContract, address _operatorContractUpgrader) public onlyGovernance {
78-
operatorContractUpgraders[_serviceContract] = _operatorContractUpgrader;
79-
emit OperatorContractUpgraderUpdated(_serviceContract, _operatorContractUpgrader);
117+
function setOperatorContractPanicButton(
118+
address _operatorContract,
119+
address _panicButton
120+
) public onlyForApprovedContract(_operatorContract) onlyGovernance {
121+
require(
122+
panicButtons[_operatorContract] != address(0),
123+
"Disabled panic button cannot be updated"
124+
);
125+
require(
126+
_panicButton != address(0),
127+
"Panic button must be non-zero address"
128+
);
129+
130+
panicButtons[_operatorContract] = _panicButton;
131+
132+
emit OperatorContractPanicButtonUpdated(
133+
_operatorContract,
134+
_panicButton
135+
);
80136
}
81137

82-
function approveOperatorContract(address operatorContract) public onlyRegistryKeeper {
138+
function disableOperatorContractPanicButton(address _operatorContract)
139+
public
140+
onlyForApprovedContract(_operatorContract)
141+
onlyGovernance
142+
{
83143
require(
84-
isNewOperatorContract(operatorContract),
85-
"Only new operator contracts can be approved"
144+
panicButtons[_operatorContract] != address(0),
145+
"Panic button already disabled"
86146
);
87147

88-
operatorContracts[operatorContract] = ContractStatus.Approved;
89-
emit OperatorContractApproved(operatorContract);
148+
panicButtons[_operatorContract] = address(0);
149+
150+
emit OperatorContractPanicButtonDisabled(_operatorContract);
90151
}
91152

92-
function disableOperatorContract(address operatorContract) public onlyPanicButton {
93-
require(
94-
isApprovedOperatorContract(operatorContract),
95-
"Only approved operator contracts can be disabled"
153+
function setOperatorContractUpgrader(
154+
address _serviceContract,
155+
address _operatorContractUpgrader
156+
) public onlyGovernance {
157+
operatorContractUpgraders[_serviceContract] = _operatorContractUpgrader;
158+
emit OperatorContractUpgraderUpdated(
159+
_serviceContract,
160+
_operatorContractUpgrader
96161
);
162+
}
163+
164+
function approveOperatorContract(address operatorContract)
165+
public
166+
onlyForNewContract(operatorContract)
167+
onlyRegistryKeeper
168+
{
169+
operatorContracts[operatorContract] = ContractStatus.Approved;
170+
panicButtons[operatorContract] = defaultPanicButton;
171+
emit OperatorContractApproved(operatorContract);
172+
}
97173

174+
function disableOperatorContract(address operatorContract)
175+
public
176+
onlyForApprovedContract(operatorContract)
177+
onlyPanicButton(operatorContract)
178+
{
98179
operatorContracts[operatorContract] = ContractStatus.Disabled;
99180
emit OperatorContractDisabled(operatorContract);
100181
}
101182

102-
function isNewOperatorContract(address operatorContract) public view returns (bool) {
183+
function isNewOperatorContract(address operatorContract)
184+
public
185+
view
186+
returns (bool)
187+
{
103188
return operatorContracts[operatorContract] == ContractStatus.New;
104189
}
105190

106-
function isApprovedOperatorContract(address operatorContract) public view returns (bool) {
191+
function isApprovedOperatorContract(address operatorContract)
192+
public
193+
view
194+
returns (bool)
195+
{
107196
return operatorContracts[operatorContract] == ContractStatus.Approved;
108197
}
109198

110-
function operatorContractUpgraderFor(address _serviceContract) public view returns (address) {
199+
function operatorContractUpgraderFor(address _serviceContract)
200+
public
201+
view
202+
returns (address)
203+
{
111204
return operatorContractUpgraders[_serviceContract];
112205
}
113206
}

solidity/contracts/stubs/RegistryStub.sol

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ pragma solidity 0.5.17;
22

33
import "../Registry.sol";
44

5-
contract RegistryStub is Registry {
65

6+
contract RegistryStub is Registry {
77
function getGovernance() public view returns (address) {
88
return governance;
99
}
@@ -12,7 +12,15 @@ contract RegistryStub is Registry {
1212
return registryKeeper;
1313
}
1414

15-
function getPanicButton() public view returns (address) {
16-
return panicButton;
15+
function getDefaultPanicButton() public view returns (address) {
16+
return defaultPanicButton;
17+
}
18+
19+
function getPanicButtonForContract(address operatorContract)
20+
public
21+
view
22+
returns (address)
23+
{
24+
return panicButtons[operatorContract];
1725
}
1826
}

0 commit comments

Comments
 (0)