@@ -12,8 +12,8 @@ interface IEmergencyBrake {
1212
1313 function plan (address target , Permission[] calldata permissions ) external returns (bytes32 txHash );
1414 function cancel (bytes32 txHash ) external ;
15- function execute (address target , Permission[] calldata permissions ) external ;
16- function restore (address target , Permission[] calldata permissions ) external ;
15+ function execute (bytes32 txHash ) external ;
16+ function restore (bytes32 txHash ) external ;
1717 function terminate (bytes32 txHash ) external ;
1818}
1919
@@ -28,13 +28,19 @@ interface IEmergencyBrake {
2828contract EmergencyBrake is AccessControl , IEmergencyBrake {
2929 enum State {UNPLANNED, PLANNED, EXECUTED}
3030
31+ struct Plan {
32+ State state;
33+ address target;
34+ bytes permissions;
35+ }
36+
3137 event Planned (bytes32 indexed txHash , address indexed target );
3238 event Cancelled (bytes32 indexed txHash );
3339 event Executed (bytes32 indexed txHash , address indexed target );
3440 event Restored (bytes32 indexed txHash , address indexed target );
3541 event Terminated (bytes32 indexed txHash );
3642
37- mapping (bytes32 => State ) public plans;
43+ mapping (bytes32 => Plan ) public plans;
3844
3945 constructor (address planner , address executor ) AccessControl () {
4046 _grantRole (IEmergencyBrake.plan.selector , planner);
@@ -51,6 +57,8 @@ contract EmergencyBrake is AccessControl, IEmergencyBrake {
5157 external override auth
5258 returns (bytes32 txHash )
5359 {
60+ txHash = keccak256 (abi.encode (target, permissions));
61+ require (plans[txHash].state == State.UNPLANNED, "Emergency already planned for. " );
5462
5563 // Removing or granting ROOT permissions is out of bounds for EmergencyBrake
5664 for (uint256 i = 0 ; i < permissions.length ; i++ ){
@@ -61,69 +69,78 @@ contract EmergencyBrake is AccessControl, IEmergencyBrake {
6169 );
6270 }
6371 }
64- txHash = keccak256 (abi.encode (target, permissions));
65- require (plans[txHash] == State.UNPLANNED, "Emergency already planned for. " );
66- plans[txHash] = State.PLANNED;
72+
73+ plans[txHash] = Plan ({
74+ state: State.PLANNED,
75+ target: target,
76+ permissions: abi.encode (permissions)
77+ });
6778 emit Planned (txHash, target);
6879 }
6980
7081 /// @dev Erase a planned access removal transaction
7182 function cancel (bytes32 txHash )
7283 external override auth
7384 {
74- require (plans[txHash] == State.PLANNED, "Emergency not planned for. " );
75- plans[txHash] = State.UNPLANNED ;
85+ require (plans[txHash].state == State.PLANNED, "Emergency not planned for. " );
86+ delete plans[txHash];
7687 emit Cancelled (txHash);
7788 }
7889
7990 /// @dev Execute an access removal transaction
80- function execute (address target , Permission[] calldata permissions )
91+ function execute (bytes32 txHash )
8192 external override auth
8293 {
83- bytes32 txHash = keccak256 ( abi.encode (target, permissions)) ;
84- require (plans[txHash] == State.PLANNED, "Emergency not planned for. " );
85- plans[txHash] = State.EXECUTED;
94+ Plan memory plan_ = plans[txHash] ;
95+ require (plan_.state == State.PLANNED, "Emergency not planned for. " );
96+ plans[txHash].state = State.EXECUTED;
8697
87- for (uint256 i = 0 ; i < permissions.length ; i++ ){
98+ Permission[] memory permissions_ = abi.decode (plan_.permissions, (Permission[]));
99+
100+ for (uint256 i = 0 ; i < permissions_.length ; i++ ){
88101 // AccessControl.sol doesn't revert if revoking permissions that haven't been granted
89102 // If we don't check, planner and executor can collude to gain access to contacts
90- for (uint256 j = 0 ; j < permissions[i].signatures.length ; j++ ){
91- AccessControl contact = AccessControl (permissions[i].contact);
92- bytes4 permission = permissions[i].signatures[j];
103+ Permission memory permission_ = permissions_[i];
104+ for (uint256 j = 0 ; j < permission_.signatures.length ; j++ ){
105+ AccessControl contact = AccessControl (permission_.contact);
106+ bytes4 signature_ = permission_.signatures[j];
93107 require (
94- contact.hasRole (permission, target),
108+ contact.hasRole (signature_, plan_. target),
95109 "Permission not found "
96110 );
97- contact.revokeRole (permission, target);
111+ contact.revokeRole (signature_, plan_. target);
98112 }
99113 }
100- emit Executed (txHash, target);
114+ emit Executed (txHash, plan_. target);
101115 }
102116
103117 /// @dev Restore the orchestration from an isolated target
104- function restore (address target , Permission[] calldata permissions )
118+ function restore (bytes32 txHash )
105119 external override auth
106120 {
107- bytes32 txHash = keccak256 (abi.encode (target, permissions));
108- require (plans[txHash] == State.EXECUTED, "Emergency plan not executed. " );
109- plans[txHash] = State.PLANNED;
110-
111- for (uint256 i = 0 ; i < permissions.length ; i++ ){
112- for (uint256 j = 0 ; j < permissions[i].signatures.length ; j++ ){
113- AccessControl contact = AccessControl (permissions[i].contact);
114- bytes4 permission = permissions[i].signatures[j];
115- contact.grantRole (permission, target);
121+ Plan memory plan_ = plans[txHash];
122+ require (plan_.state == State.EXECUTED, "Emergency plan not executed. " );
123+ plans[txHash].state = State.PLANNED;
124+
125+ Permission[] memory permissions_ = abi.decode (plan_.permissions, (Permission[]));
126+
127+ for (uint256 i = 0 ; i < permissions_.length ; i++ ){
128+ Permission memory permission_ = permissions_[i];
129+ for (uint256 j = 0 ; j < permission_.signatures.length ; j++ ){
130+ AccessControl contact = AccessControl (permission_.contact);
131+ bytes4 signature_ = permission_.signatures[j];
132+ contact.grantRole (signature_, plan_.target);
116133 }
117134 }
118- emit Restored (txHash, target);
135+ emit Restored (txHash, plan_. target);
119136 }
120137
121138 /// @dev Remove the restoring option from an isolated target
122139 function terminate (bytes32 txHash )
123140 external override auth
124141 {
125- require (plans[txHash] == State.EXECUTED, "Emergency plan not executed. " );
126- plans[txHash] = State.UNPLANNED ;
142+ require (plans[txHash].state == State.EXECUTED, "Emergency plan not executed. " );
143+ delete plans[txHash];
127144 emit Terminated (txHash);
128145 }
129146}
0 commit comments