Skip to content

Commit

Permalink
extend some rules, deprecate/remove fixes used because I couldn't res…
Browse files Browse the repository at this point in the history
…olve some CVL issues, filter the invariant fallbackHanlderNeverSelf for sanity, etc. overall improvement of rules for fallback
  • Loading branch information
Derek Sorensen authored and Derek Sorensen committed Dec 18, 2024
1 parent 019aef5 commit 206a82b
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 19 deletions.
5 changes: 0 additions & 5 deletions certora/harnesses/SafeHarness.sol
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,6 @@ contract SafeHarness is Safe {
return handler ;
}

// TODO deprecate this with CVL2
function addressToBytes32(address addr) public pure returns (bytes32) {
return bytes32(uint256(uint160(addr)));
}

function getTransactionHashPublic(
address to,
uint256 value,
Expand Down
64 changes: 50 additions & 14 deletions certora/specs/v1.5/Fallback.spec
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ using SafeHarness as safe;
methods {

function getFallbackHandler() external returns (address) envfree;
function addressToBytes32(address) external returns (bytes32) envfree;


function _.handle(address _safe, address sender, uint256 value, bytes data) external => DISPATCHER(true);
}

Expand All @@ -36,36 +35,73 @@ rule setFallbackIntegrity(address handler) {
}

/// @dev invariant: the address in fallback handler slot is never self
/// @status Done (?)s: https://prover.certora.com/output/39601/103eb341ceef481c830e0ba04eb06766?anonymousKey=61cb4fd6726ab3d0fad887f6393865263eecf3f0
invariant fallbackHanlderNeverSelf()
getFallbackHandler() != safe ;
/// @status Done: https://prover.certora.com/output/39601/edb75f86f23445cdbc7cd7b5c4c420b6?anonymousKey=62191f4f70404bcbce784f5172e3ed7ab323d416
invariant fallbackHanlderNeverSelf()
getFallbackHandler() != safe
filtered {
f -> f.selector != sig:simulateAndRevert(address,bytes).selector
}

// for soundness of fallbackHanlderNeverSelf, we prove a rule that simulateAndRevert always reverts
rule simulateAndRevertReverts(address caddr, bytes b) {
env e;
simulateAndRevert@withrevert(e,caddr,b);
assert lastReverted;
}

/// @dev 3 rules for set safe method integrity: sets/modifies/removes handler
/// @status Done: https://prover.certora.com/output/39601/bab9860cdfc44a83bed82e79d8c06218?anonymousKey=b4c5dbef050bb201ad78b3dd5af5cdca8ffa9f92
rule setSafeMethodSets(bytes4 selector, address newMethodCaddr) {
env e;

bytes32 newMethod = to_bytes32(assert_uint256(newMethodCaddr));

fallbackHandler.setSafeMethod(e,selector,newMethod);
bytes32 thisMethod = fallbackHandler.getSafeMethod(e,e.msg.sender,selector);

assert (thisMethod == thisMethod);
}

/// @dev set safe method integrity: sets/modifies/removes handler
/// @status Done: https://prover.certora.com/output/39601/09912f9691e04917b4c0277e30ad8e38?anonymousKey=61db5fd06c13a287939455e3a531ff841442ee2e
rule setSafeMethodIntegrity(bytes4 selector, address newMethod_addr) {
/// @status Done: https://prover.certora.com/output/39601/8591535c4a434f3e826af00b95ea1ca8?anonymousKey=a7b6743a3161a3289883f99014619a9d6e7196e1
/// note this is a special case of the rule above, but we still include it here for illustration
rule setSafeMethodRemoves(bytes4 selector) {
env e;

bytes32 newMethod = addressToBytes32(newMethod_addr);
bytes32 newMethod = to_bytes32(0); // call setSafeMethod with the zero address

fallbackHandler.setSafeMethod(e,selector,newMethod);
bytes32 this_method = fallbackHandler.getSafeMethod(e,e.msg.sender,selector);
bytes32 thisMethod = fallbackHandler.getSafeMethod(e,e.msg.sender,selector);

assert (thisMethod == to_bytes32(0)); // there is nothing stored
}

/// @status Done: https://prover.certora.com/output/39601/b44efe9ef3bd4ff5a1af710a7d3d7ee4?anonymousKey=7fd15cc355164c803123c27b41660fed34548647
rule setSafeMethodChanges(bytes4 selector, address newMethodCaddr) {
env e;

bytes32 newMethod = to_bytes32(assert_uint256(newMethodCaddr));
bytes32 oldMethod = fallbackHandler.getSafeMethod(e,e.msg.sender,selector);
require (newMethod != oldMethod); // we are changing the method address

fallbackHandler.setSafeMethod(e,selector,newMethod);

bytes32 thisMethod = fallbackHandler.getSafeMethod(e,e.msg.sender,selector);

assert (newMethod == this_method);
assert (thisMethod == newMethod);
}


/// @dev a handler, once set via setSafeMethod, is possible to call
/// @status Done: https://prover.certora.com/output/39601/9fcde04ecd434963b9ce788f7ddea8c1?anonymousKey=a7efde58b28ef7c99264424b66984a8d39b78518
rule hanlderCallableIfSet(bytes4 selector,method f) filtered { f -> f.isFallback } {
rule hanlderCallableIfSet(method f) filtered { f -> f.isFallback } {
env e;

// the fallback handler is in the scene
require (getFallbackHandler() == fallbackHandler);

// the dummy (sub) handler is a valid handler for this safe
bytes32 dummy_bytes = addressToBytes32(dummyHandler); // TODO to_bytes32 from CVL2
// bytes4 selector = to_bytes4(00); // 0x00 indicates this is a non-static call
bytes32 dummy_bytes = to_bytes32(assert_uint256(dummyHandler));
bytes4 selector = to_bytes4(00); // 0x00 indicates this is a non-static call
fallbackHandler.setSafeMethod(e,selector,dummy_bytes); // we've set the dummy as a handler

// reset the check to see if dummy handler has been called
Expand Down

0 comments on commit 206a82b

Please sign in to comment.