Skip to content

Commit d23363d

Browse files
committed
kill-switch: integrate with aragonOS components
1 parent a9b74dc commit d23363d

23 files changed

+316
-202
lines changed

contracts/apps/AragonApp.sol

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import "../evmscript/EVMScriptRunner.sol";
2020
// are included so that they are automatically usable by subclassing contracts
2121
contract AragonApp is AppStorage, Autopetrified, VaultRecoverable, ReentrancyGuard, EVMScriptRunner, ACLSyntaxSugar {
2222
string private constant ERROR_AUTH_FAILED = "APP_AUTH_FAILED";
23+
string private constant ERROR_CONTRACT_CALL_NOT_ALLOWED = "APP_CONTRACT_CALL_NOT_ALLOWED";
2324

2425
modifier auth(bytes32 _role) {
2526
require(canPerform(msg.sender, _role, new uint256[](0)), ERROR_AUTH_FAILED);
@@ -31,6 +32,12 @@ contract AragonApp is AppStorage, Autopetrified, VaultRecoverable, ReentrancyGua
3132
_;
3233
}
3334

35+
modifier killSwitched {
36+
bool _shouldDenyCall = kernel().killSwitch().shouldDenyCallingContract(_baseApp());
37+
require(!_shouldDenyCall, ERROR_CONTRACT_CALL_NOT_ALLOWED);
38+
_;
39+
}
40+
3441
/**
3542
* @dev Check whether an action can be performed by a sender for a particular role on this app
3643
* @param _sender Sender of the call
@@ -65,4 +72,12 @@ contract AragonApp is AppStorage, Autopetrified, VaultRecoverable, ReentrancyGua
6572
// Funds recovery via a vault is only available when used with a kernel
6673
return kernel().getRecoveryVault(); // if kernel is not set, it will revert
6774
}
75+
76+
/**
77+
* @dev Get the address of the base implementation for the current app
78+
* @return Address of the base implementation
79+
*/
80+
function _baseApp() internal view returns (address) {
81+
return kernel().getApp(KERNEL_APP_BASES_NAMESPACE, appId());
82+
}
6883
}

contracts/factory/DAOFactory.sol

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ pragma solidity 0.4.24;
33
import "../kernel/IKernel.sol";
44
import "../kernel/Kernel.sol";
55
import "../kernel/KernelProxy.sol";
6+
import "../kill_switch/IKillSwitch.sol";
7+
import "../kill_switch/IIssuesRegistry.sol";
68

79
import "../acl/IACL.sol";
810
import "../acl/ACL.sol";
@@ -13,6 +15,7 @@ import "./EVMScriptRegistryFactory.sol";
1315
contract DAOFactory {
1416
IKernel public baseKernel;
1517
IACL public baseACL;
18+
IKillSwitch public baseKillSwitch;
1619
EVMScriptRegistryFactory public regFactory;
1720

1821
event DeployDAO(address dao);
@@ -24,14 +27,22 @@ contract DAOFactory {
2427
* @param _baseACL Base ACL
2528
* @param _regFactory EVMScriptRegistry factory
2629
*/
27-
constructor(IKernel _baseKernel, IACL _baseACL, EVMScriptRegistryFactory _regFactory) public {
30+
constructor(
31+
IKernel _baseKernel,
32+
IACL _baseACL,
33+
IKillSwitch _baseKillSwitch,
34+
EVMScriptRegistryFactory _regFactory
35+
)
36+
public
37+
{
2838
// No need to init as it cannot be killed by devops199
2939
if (address(_regFactory) != address(0)) {
3040
regFactory = _regFactory;
3141
}
3242

3343
baseKernel = _baseKernel;
3444
baseACL = _baseACL;
45+
baseKillSwitch = _baseKillSwitch;
3546
}
3647

3748
/**
@@ -40,7 +51,7 @@ contract DAOFactory {
4051
* @return Newly created DAO
4152
*/
4253
function newDAO(address _root) public returns (Kernel) {
43-
Kernel dao = Kernel(new KernelProxy(baseKernel));
54+
Kernel dao = _newDAO();
4455

4556
if (address(regFactory) == address(0)) {
4657
dao.initialize(baseACL, _root);
@@ -49,6 +60,30 @@ contract DAOFactory {
4960
_setupNewDaoPermissions(_root, dao);
5061
}
5162

63+
return dao;
64+
}
65+
66+
/**
67+
* @notice Create a new DAO with `_root` set as the initial admin and `_issuesRegistry` as the source of truth for kill-switch purpose
68+
* @param _root Address that will be granted control to setup DAO permissions
69+
* @param _issuesRegistry Address of the registry of issues that will be used in case of critical situations by the kill switch
70+
* @return Newly created DAO
71+
*/
72+
function newDAOWithKillSwitch(address _root, IIssuesRegistry _issuesRegistry) public returns (Kernel) {
73+
Kernel dao = _newDAO();
74+
75+
if (address(regFactory) == address(0)) {
76+
dao.initializeWithKillSwitch(baseACL, _root, baseKillSwitch, _issuesRegistry);
77+
} else {
78+
dao.initializeWithKillSwitch(baseACL, address(this), baseKillSwitch, _issuesRegistry);
79+
_setupNewDaoPermissions(_root, Kernel(dao));
80+
}
81+
82+
return dao;
83+
}
84+
85+
function _newDAO() internal returns (Kernel) {
86+
Kernel dao = Kernel(new KernelProxy(baseKernel));
5287
emit DeployDAO(address(dao));
5388
return dao;
5489
}

contracts/kernel/IKernel.sol

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
pragma solidity ^0.4.24;
66

77
import "../acl/IACL.sol";
8+
import "../kill_switch/IKillSwitch.sol";
89
import "../common/IVaultRecoverable.sol";
910

1011

@@ -16,6 +17,7 @@ interface IKernelEvents {
1617
// This should be an interface, but interfaces can't inherit yet :(
1718
contract IKernel is IKernelEvents, IVaultRecoverable {
1819
function acl() public view returns (IACL);
20+
function killSwitch() public view returns (IKillSwitch);
1921
function hasPermission(address who, address where, bytes32 what, bytes how) public view returns (bool);
2022

2123
function setApp(bytes32 namespace, bytes32 appId, address app) public;

contracts/kernel/Kernel.sol

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import "../common/IsContract.sol";
1010
import "../common/Petrifiable.sol";
1111
import "../common/VaultRecoverable.sol";
1212
import "../factory/AppProxyFactory.sol";
13+
import "../kill_switch/IKillSwitch.sol";
14+
import "../kill_switch/IIssuesRegistry.sol";
1315
import "../lib/misc/ERCProxy.sol";
1416

1517

@@ -54,6 +56,27 @@ contract Kernel is IKernel, KernelStorage, KernelAppIds, KernelNamespaceConstant
5456
recoveryVaultAppId = KERNEL_DEFAULT_VAULT_APP_ID;
5557
}
5658

59+
/**
60+
* @dev Initialize can only be called once. It saves the block number in which it was initialized.
61+
* @notice Initialize this kernel instance, its ACL setting `_permissionsCreator` as the entity that can create other permissions, and a KillSwitch instance setting `_issuesRegistry
62+
* @param _baseAcl Address of base ACL app
63+
* @param _permissionsCreator Entity that will be given permission over createPermission
64+
* @param _baseKillSwitch Address of base KillSwitch app
65+
* @param _issuesRegistry Issues registry that will act as the default source of truth to provide info about applications issues
66+
*/
67+
function initializeWithKillSwitch(IACL _baseAcl, address _permissionsCreator, IKillSwitch _baseKillSwitch, IIssuesRegistry _issuesRegistry)
68+
public onlyInit
69+
{
70+
// Set and create ACL app
71+
initialize(_baseAcl, _permissionsCreator);
72+
73+
// Set and create KillSwitch app
74+
_setApp(KERNEL_APP_BASES_NAMESPACE, KERNEL_DEFAULT_KILL_SWITCH_APP_ID, _baseKillSwitch);
75+
IKillSwitch killSwitch = IKillSwitch(newAppProxy(this, KERNEL_DEFAULT_KILL_SWITCH_APP_ID));
76+
killSwitch.initialize(_issuesRegistry);
77+
_setApp(KERNEL_APP_ADDR_NAMESPACE, KERNEL_DEFAULT_KILL_SWITCH_APP_ID, killSwitch);
78+
}
79+
5780
/**
5881
* @dev Create a new instance of an app linked to this kernel
5982
* @notice Create a new upgradeable instance of `_appId` app linked to the Kernel, setting its code to `_appBase`
@@ -169,6 +192,7 @@ contract Kernel is IKernel, KernelStorage, KernelAppIds, KernelNamespaceConstant
169192
function APP_ADDR_NAMESPACE() external pure returns (bytes32) { return KERNEL_APP_ADDR_NAMESPACE; }
170193
function KERNEL_APP_ID() external pure returns (bytes32) { return KERNEL_CORE_APP_ID; }
171194
function DEFAULT_ACL_APP_ID() external pure returns (bytes32) { return KERNEL_DEFAULT_ACL_APP_ID; }
195+
function DEFAULT_KILL_SWITCH_APP_ID() external pure returns (bytes32) { return KERNEL_DEFAULT_KILL_SWITCH_APP_ID; }
172196
/* solium-enable function-order, mixedcase */
173197

174198
/**
@@ -197,6 +221,14 @@ contract Kernel is IKernel, KernelStorage, KernelAppIds, KernelNamespaceConstant
197221
return IACL(getApp(KERNEL_APP_ADDR_NAMESPACE, KERNEL_DEFAULT_ACL_APP_ID));
198222
}
199223

224+
/**
225+
* @dev Get the installed KillSwitch app
226+
* @return KillSwitch app
227+
*/
228+
function killSwitch() public view returns (IKillSwitch) {
229+
return IKillSwitch(getApp(KERNEL_APP_ADDR_NAMESPACE, KERNEL_DEFAULT_KILL_SWITCH_APP_ID));
230+
}
231+
200232
/**
201233
* @dev Function called by apps to check ACL on kernel or to check permission status
202234
* @param _who Sender of the original call

contracts/kernel/KernelConstants.sol

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@ contract KernelAppIds {
1010
bytes32 internal constant KERNEL_CORE_APP_ID = apmNamehash("kernel");
1111
bytes32 internal constant KERNEL_DEFAULT_ACL_APP_ID = apmNamehash("acl");
1212
bytes32 internal constant KERNEL_DEFAULT_VAULT_APP_ID = apmNamehash("vault");
13+
bytes32 internal constant KERNEL_DEFAULT_KILL_SWITCH_APP_ID = apmNamehash("killSwitch");
1314
*/
1415
bytes32 internal constant KERNEL_CORE_APP_ID = 0x3b4bf6bf3ad5000ecf0f989d5befde585c6860fea3e574a4fab4c49d1c177d9c;
1516
bytes32 internal constant KERNEL_DEFAULT_ACL_APP_ID = 0xe3262375f45a6e2026b7e7b18c2b807434f2508fe1a2a3dfb493c7df8f4aad6a;
1617
bytes32 internal constant KERNEL_DEFAULT_VAULT_APP_ID = 0x7e852e0fcfce6551c13800f1e7476f982525c2b5277ba14b24339c68416336d1;
18+
bytes32 internal constant KERNEL_DEFAULT_KILL_SWITCH_APP_ID = 0x05b6cbc146cecc3a8014843768ab6e17332ef00418da7f6babf4ea94c76ab6a1;
1719
}
1820

1921

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
pragma solidity 0.4.24;
2+
3+
4+
contract IIssuesRegistry {
5+
enum Severity { None, Low, Mid, High, Critical }
6+
7+
event SeveritySet(address indexed entry, Severity severity, address sender);
8+
9+
function initialize() external;
10+
11+
function setSeverityFor(address entry, Severity severity) external;
12+
13+
function isSeverityFor(address entry) public view returns (bool);
14+
15+
function getSeverityFor(address entry) public view returns (Severity);
16+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
pragma solidity 0.4.24;
2+
3+
import "./IIssuesRegistry.sol";
4+
5+
6+
contract IKillSwitch {
7+
function initialize(IIssuesRegistry _issuesRegistry) external;
8+
9+
function shouldDenyCallingContract(address _contract) external returns (bool);
10+
}
Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,28 @@
11
pragma solidity 0.4.24;
22

33
import "../apps/AragonApp.sol";
4+
import "./IIssuesRegistry.sol";
45

56

6-
contract IssuesRegistry is AragonApp {
7+
contract IssuesRegistry is IIssuesRegistry, AragonApp {
78
bytes32 constant public SET_ENTRY_SEVERITY_ROLE = keccak256("SET_ENTRY_SEVERITY_ROLE");
89

9-
enum Severity { None, Low, Mid, High, Critical }
10-
1110
mapping (address => Severity) internal issuesSeverity;
1211

13-
event SeveritySet(address indexed entry, Severity severity, address sender);
14-
15-
function initialize() public onlyInit {
12+
function initialize() external onlyInit {
1613
initialized();
1714
}
1815

16+
function setSeverityFor(address entry, Severity severity) external authP(SET_ENTRY_SEVERITY_ROLE, arr(entry, msg.sender)) {
17+
issuesSeverity[entry] = severity;
18+
emit SeveritySet(entry, severity, msg.sender);
19+
}
20+
1921
function isSeverityFor(address entry) public view isInitialized returns (bool) {
2022
return issuesSeverity[entry] != Severity.None;
2123
}
2224

2325
function getSeverityFor(address entry) public view isInitialized returns (Severity) {
2426
return issuesSeverity[entry];
2527
}
26-
27-
function setSeverityFor(address entry, Severity severity) public authP(SET_ENTRY_SEVERITY_ROLE, arr(entry, msg.sender)) {
28-
issuesSeverity[entry] = severity;
29-
emit SeveritySet(entry, severity, msg.sender);
30-
}
3128
}

0 commit comments

Comments
 (0)