|
@@ -1,9 +1,117 @@
|
|
|
+methods {
|
|
|
+ balanceOf(address, uint256) returns uint256 envfree
|
|
|
+ paused() returns bool envfree
|
|
|
+}
|
|
|
+
|
|
|
+/// When a contract is in a paused state, the token balance for a given user and
|
|
|
+/// token must not change.
|
|
|
+rule balancesUnchangedWhenPaused() {
|
|
|
+ address user; uint256 token;
|
|
|
+ uint256 balanceBefore = balanceOf(user, token);
|
|
|
+
|
|
|
+ require paused();
|
|
|
+
|
|
|
+ method f; calldataarg arg; env e;
|
|
|
+ f(e, arg);
|
|
|
+
|
|
|
+ uint256 balanceAfter = balanceOf(user, token);
|
|
|
+
|
|
|
+ assert balanceBefore == balanceAfter,
|
|
|
+ "Token balance for a user must not change in a paused contract";
|
|
|
+}
|
|
|
+
|
|
|
+/// When a contract is in a paused state, transfer methods must revert.
|
|
|
+rule transferMethodsRevertWhenPaused (method f)
|
|
|
+filtered {
|
|
|
+ f -> f.selector == safeTransferFrom(address,address,uint256,uint256,bytes).selector
|
|
|
+ || f.selector == safeBatchTransferFrom(address,address,uint256[],uint256[],bytes).selector
|
|
|
+}
|
|
|
+{
|
|
|
+ require paused();
|
|
|
+
|
|
|
+ env e; calldataarg args;
|
|
|
+ f@withrevert(e, args);
|
|
|
+
|
|
|
+ assert lastReverted,
|
|
|
+ "Transfer methods must revert in a paused contract";
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/// Calling pause must pause an unpaused contract.
|
|
|
+/// When a contract is in an unpaused state, calling pause() must pause.
|
|
|
+rule pauseMethodPausesContract {
|
|
|
+ require !paused();
|
|
|
+
|
|
|
+ env e;
|
|
|
+ pause(e);
|
|
|
+
|
|
|
+ assert paused(),
|
|
|
+ "Calling pause must pause an unpaused contract";
|
|
|
+}
|
|
|
+
|
|
|
+/// When a contract is in a paused state, calling unpause() must unpause.
|
|
|
+rule unpauseMethodUnpausesContract {
|
|
|
+ require paused();
|
|
|
+
|
|
|
+ env e;
|
|
|
+ unpause(e);
|
|
|
|
|
|
+ assert !paused(),
|
|
|
+ "Calling unpause must unpause a paused contract";
|
|
|
+}
|
|
|
+
|
|
|
+/// When a contract is in a paused state, calling pause() must revert.
|
|
|
+rule cannotPauseWhilePaused {
|
|
|
+ require paused();
|
|
|
+
|
|
|
+ env e;
|
|
|
+ pause@withrevert(e);
|
|
|
+
|
|
|
+ assert lastReverted,
|
|
|
+ "A call to pause when already paused must revert";
|
|
|
+}
|
|
|
+
|
|
|
+/// When a contract is in an unpaused state, calling unpause() must revert.
|
|
|
+rule cannotUnpauseWhileUnpaused {
|
|
|
+ require !paused();
|
|
|
+
|
|
|
+ env e;
|
|
|
+ unpause@withrevert(e);
|
|
|
+
|
|
|
+ assert lastReverted,
|
|
|
+ "A call to unpause when already unpaused must revert";
|
|
|
+}
|
|
|
+
|
|
|
+/// When a contract is in a paused state, functions with the whenNotPaused
|
|
|
+/// modifier must revert.
|
|
|
+rule whenNotPausedModifierCausesRevertIfPaused {
|
|
|
+ require paused();
|
|
|
+
|
|
|
+ env e; calldataarg args;
|
|
|
+ onlyWhenNotPausedMethod@withrevert(e, args);
|
|
|
+
|
|
|
+ assert lastReverted,
|
|
|
+ "Functions with the whenNotPaused modifier must revert if the contract is paused";
|
|
|
+}
|
|
|
+
|
|
|
+/// When a contract is in an unpaused state, functions with the whenPaused
|
|
|
+/// modifier must revert.
|
|
|
+rule whenPausedModifierCausesRevertIfUnpaused {
|
|
|
+ require !paused();
|
|
|
+
|
|
|
+ env e; calldataarg args;
|
|
|
+ onlyWhenPausedMethod@withrevert(e, args);
|
|
|
+
|
|
|
+ assert lastReverted,
|
|
|
+ "Functions with the whenPaused modifier must revert if the contract is not paused";
|
|
|
+}
|
|
|
+
|
|
|
+/// This rule should always fail.
|
|
|
rule sanity {
|
|
|
method f; env e; calldataarg args;
|
|
|
|
|
|
f(e, args);
|
|
|
|
|
|
- assert false;
|
|
|
+ assert false,
|
|
|
+ "This rule should always fail";
|
|
|
}
|
|
|
-
|