Browse Source

Add setAuthority rule to AccessManaged

ernestognw 1 year ago
parent
commit
cd86596938
2 changed files with 32 additions and 7 deletions
  1. 9 6
      certora/harnesses/AccessManagedHarness.sol
  2. 23 1
      certora/specs/AccessManaged.spec

+ 9 - 6
certora/harnesses/AccessManagedHarness.sol

@@ -10,27 +10,30 @@ contract AccessManagedHarness is AccessManaged {
 
     constructor(address initialAuthority) AccessManaged(initialAuthority) {}
 
-    function someFunction() public restricted() {
+    function someFunction() public restricted {
         // Sanity for FV: the msg.data when calling this function should be the same as the data used when checking
         // the schedule. This is a reformulation of `msg.data == SOME_FUNCTION_CALLDATA` that focuses on the operation
         // hash for this call.
         require(
-            IAccessManager(authority()).hashOperation(_msgSender(), address(this), msg.data)
-            ==
-            IAccessManager(authority()).hashOperation(_msgSender(), address(this), SOME_FUNCTION_CALLDATA)
+            IAccessManager(authority()).hashOperation(_msgSender(), address(this), msg.data) ==
+                IAccessManager(authority()).hashOperation(_msgSender(), address(this), SOME_FUNCTION_CALLDATA)
         );
     }
 
     function authority_canCall_immediate(address caller) public view returns (bool result) {
-        (result,) = AuthorityUtils.canCallWithDelay(authority(), caller, address(this), this.someFunction.selector);
+        (result, ) = AuthorityUtils.canCallWithDelay(authority(), caller, address(this), this.someFunction.selector);
     }
 
     function authority_canCall_delay(address caller) public view returns (uint32 result) {
-        (,result) = AuthorityUtils.canCallWithDelay(authority(), caller, address(this), this.someFunction.selector);
+        (, result) = AuthorityUtils.canCallWithDelay(authority(), caller, address(this), this.someFunction.selector);
     }
 
     function authority_getSchedule(address caller) public view returns (uint48) {
         IAccessManager manager = IAccessManager(authority());
         return manager.getSchedule(manager.hashOperation(caller, address(this), SOME_FUNCTION_CALLDATA));
     }
+
+    function _hasCode(address account) public view returns (bool) {
+        return account.code.length > 0;
+    }
 }

+ 23 - 1
certora/specs/AccessManaged.spec

@@ -7,9 +7,10 @@ methods {
     function authority_canCall_immediate(address) external returns (bool);
     function authority_canCall_delay(address)     external returns (uint32);
     function authority_getSchedule(address)       external returns (uint48);
+    function _hasCode(address)                    external returns (bool) envfree;
 
     // Summaries
-    function _.setAuthority(address)               external => DISPATCHER(true);
+    function _.setAuthority(address)              external => DISPATCHER(true);
 }
 
 invariant isConsumingScheduledOpClean()
@@ -35,3 +36,24 @@ rule callRestrictedFunction(env e) {
         )
     );
 }
+
+/*
+โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
+โ”‚ Rule: Only valid authorities can be set by the current authority                                                    โ”‚
+โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
+*/
+rule setAuthority(env e) {
+    require nonpayable(e);
+
+    address newAuthority;
+
+    address previousAuthority = authority();
+
+    setAuthority@withrevert(e, newAuthority);
+    bool success = !lastReverted;
+
+    assert (success && authority() == newAuthority) <=> (
+        previousAuthority == e.msg.sender &&
+        _hasCode(newAuthority)
+    );
+}