-
Notifications
You must be signed in to change notification settings - Fork 179
Expand file tree
/
Copy pathGuardians.symbolic.t.sol
More file actions
110 lines (87 loc) · 3.33 KB
/
Copy pathGuardians.symbolic.t.sol
File metadata and controls
110 lines (87 loc) · 3.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;
import {SymTest} from "halmos-cheatcodes/SymTest.sol";
import {Test} from "forge-std/Test.sol";
import {Guardians} from "../../../src/abstract/Guardians.sol";
contract GuardiansExample is Guardians {
constructor(address owner) Guardians(owner) {}
}
contract GuardiansSymTest is SymTest, Test {
GuardiansExample guarded;
address owner;
address x;
address y;
function setUp() public {
owner = address(0x1000);
// Setup Guardians
guarded = new GuardiansExample(owner);
// Create symbolic addresses
x = svm.createAddress("x");
y = svm.createAddress("y");
}
function check_Invariants(address caller) public {
_initState();
vm.assume(x != owner);
vm.assume(x != y);
// Record pre-state
bool oldPaused = guarded.paused();
bool oldGuardianX = guarded.guardians(x);
bool oldGuardianY = guarded.guardians(y);
bytes memory data = svm.createCalldata("GuardiansExample");
bytes4 selector = bytes4(data);
// Execute an arbitrary tx
vm.prank(caller);
(bool success,) = address(guarded).call(data);
vm.assume(success); // ignore reverting cases
// Record post-state
bool newPaused = guarded.paused();
bool newGuardianX = guarded.guardians(x);
bool newGuardianY = guarded.guardians(y);
// If the paused state is changed by any transaction...
if (newPaused != oldPaused) {
// If it wasn't paused before...
if (!oldPaused) {
// It must be paused now.
assert(guarded.paused());
// The function called was pause().
assert(selector == guarded.pause.selector);
// The caller must be the owner or a guardian.
assert(caller == owner || guarded.guardians(caller));
} // Otherwise, if it *was* paused before...
else {
// It must be unpaused now.
assert(!guarded.paused());
// The function called was unpause().
assert(selector == guarded.unpause.selector);
// The caller must be the owner.
assert(caller == owner);
}
}
// If X's guardian state is changed by any transaction...
if (newGuardianX != oldGuardianX) {
// The caller must be the owner.
assert(caller == owner);
// Y's guardian state must not be changed.
assert(newGuardianY == oldGuardianY);
}
// If Y's guardian state is changed by any transaction...
if (newGuardianY != oldGuardianY) {
// The caller must be the owner.
assert(caller == owner);
// X's guardian state must not be changed.
assert(newGuardianX == oldGuardianX);
}
}
/*//////////////////////////////////////////////////////////////
HELPERS
//////////////////////////////////////////////////////////////*/
/**
* @dev Initialize IdRegistry with symbolic arguments for state.
*/
function _initState() public {
if (svm.createBool("pause?")) {
vm.prank(owner);
guarded.pause();
}
}
}