Add Pausable FV (#4117)

Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
This commit is contained in:
Ernesto García
2023-03-16 13:08:28 -06:00
committed by GitHub
parent 4f4b6ab403
commit 1a60b061d5
4 changed files with 121 additions and 0 deletions

View File

@ -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()";
}