Add Pausable FV (#4117)

Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
pull/4125/head
Ernesto García 2 years ago committed by GitHub
parent 4f4b6ab403
commit 1a60b061d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      .gitignore
  2. 19
      certora/harnesses/PausableHarness.sol
  3. 5
      certora/specs.json
  4. 96
      certora/specs/Pausable.spec

1
.gitignore vendored

@ -68,3 +68,4 @@ contracts-exposed
.certora*
.last_confs
certora_*
.zip-output-url.txt

@ -0,0 +1,19 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../patched/security/Pausable.sol";
contract PausableHarness is Pausable {
function pause() external {
_pause();
}
function unpause() external {
_unpause();
}
function onlyWhenPaused() external whenPaused {}
function onlyWhenNotPaused() external whenNotPaused {}
}

@ -1,4 +1,9 @@
[
{
"spec": "Pausable",
"contract": "PausableHarness",
"files": ["certora/harnesses/PausableHarness.sol"]
},
{
"spec": "AccessControl",
"contract": "AccessControlHarness",

@ -0,0 +1,96 @@
import "helpers.spec"
methods {
paused() returns (bool) envfree
pause()
unpause()
onlyWhenPaused()
onlyWhenNotPaused()
}
/*
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ Function correctness: _pause pauses the contract │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
*/
rule pause(env e) {
require nonpayable(e);
bool pausedBefore = paused();
pause@withrevert(e);
bool success = !lastReverted;
bool pausedAfter = paused();
// liveness
assert success <=> !pausedBefore, "works if and only if the contract was not paused before";
// effect
assert success => pausedAfter, "contract must be paused after a successful call";
}
/*
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ Function correctness: _unpause unpauses the contract │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
*/
rule unpause(env e) {
require nonpayable(e);
bool pausedBefore = paused();
unpause@withrevert(e);
bool success = !lastReverted;
bool pausedAfter = paused();
// liveness
assert success <=> pausedBefore, "works if and only if the contract was paused before";
// effect
assert success => !pausedAfter, "contract must be unpaused after a successful call";
}
/*
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ Function correctness: whenPaused modifier can only be called if the contract is paused │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
*/
rule whenPaused(env e) {
require nonpayable(e);
onlyWhenPaused@withrevert(e);
assert !lastReverted <=> paused(), "works if and only if the contract is paused";
}
/*
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ Function correctness: whenNotPaused modifier can only be called if the contract is not paused │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
*/
rule whenNotPaused(env e) {
require nonpayable(e);
onlyWhenNotPaused@withrevert(e);
assert !lastReverted <=> !paused(), "works if and only if the contract is not paused";
}
/*
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ Rules: only _pause and _unpause can change paused status │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
*/
rule noPauseChange(env e) {
method f;
calldataarg args;
bool pausedBefore = paused();
f(e, args);
bool pausedAfter = paused();
assert pausedBefore != pausedAfter => (
(!pausedAfter && f.selector == unpause().selector) ||
(pausedAfter && f.selector == pause().selector)
), "contract's paused status can only be changed by _pause() or _unpause()";
}
Loading…
Cancel
Save