1
+ import "helpers/helpers.spec" ;
2
+ import "methods/IAccount.spec" ;
3
+
4
+ /*
5
+ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
6
+ │ Module management │
7
+ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
8
+ */
9
+ rule moduleManagementRule (
10
+ env e ,
11
+ method f ,
12
+ calldataarg args ,
13
+ uint256 moduleTypeId ,
14
+ address module ,
15
+ bytes additionalContext
16
+ ) {
17
+ bytes context ;
18
+ require context . length == 0 ;
19
+
20
+ bool isEntryPoint = e . msg . sender == entryPoint ( ) ;
21
+ bool isEntryPointOrSelf = e . msg . sender == entryPoint ( ) || e . msg . sender == currentContract ;
22
+ bool isExecutionModule = isModuleInstalled ( 2 , e . msg . sender , context ) ;
23
+
24
+ bool isModuleInstalledBefore = isModuleInstalled ( moduleTypeId , module , additionalContext ) ;
25
+ f ( e , args ) ;
26
+ bool isModuleInstalledAfter = isModuleInstalled ( moduleTypeId , module , additionalContext ) ;
27
+
28
+ assert (
29
+ isModuleInstalledBefore != isModuleInstalledAfter
30
+ ) => (
31
+ (
32
+ f . selector == sig :execute ( bytes32 , bytes ) . selector &&
33
+ isEntryPointOrSelf
34
+ ) || (
35
+ f . selector == sig :executeFromExecutor ( bytes32 , bytes ) . selector &&
36
+ isExecutionModule
37
+ ) || (
38
+ f . selector == sig :installModule ( uint256 , address , bytes ) . selector &&
39
+ isEntryPointOrSelf
40
+ ) || (
41
+ f . selector == sig :uninstallModule ( uint256 , address , bytes ) . selector &&
42
+ isEntryPointOrSelf
43
+ )
44
+ ) ;
45
+ }
46
+
47
+ /*
48
+ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
49
+ │ CALL OPCODE │
50
+ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
51
+ */
52
+ ghost bool call ;
53
+ ghost address call_target ;
54
+ ghost uint256 call_value ;
55
+ ghost uint256 call_argsLength ;
56
+
57
+ hook CALL ( uint256 gas , address target , uint256 value , uint256 argsOffset , uint256 argsLength , uint256 retOffset , uint256 retLength ) uint256 rc {
58
+ call = true ;
59
+ call_target = target ;
60
+ call_value = value ;
61
+ call_argsLength = argsLength ;
62
+ }
63
+
64
+ rule callOpcodeRule (
65
+ env e ,
66
+ method f ,
67
+ calldataarg args
68
+ ) {
69
+ require !call ;
70
+
71
+ bytes context ;
72
+ require context . length == 0 ;
73
+
74
+ bool isEntryPoint = e . msg . sender == entryPoint ( ) ;
75
+ bool isEntryPointOrSelf = e . msg . sender == entryPoint ( ) || e . msg . sender == currentContract ;
76
+ bool isExecutionModule = isModuleInstalled ( 2 , e . msg . sender , context ) ;
77
+ address fallbackHandler = getFallbackHandler ( f . selector ) ;
78
+
79
+ f ( e , args ) ;
80
+
81
+ assert call => (
82
+ (
83
+ f . selector == sig :execute ( bytes32 , bytes ) . selector &&
84
+ isEntryPointOrSelf
85
+ ) || (
86
+ f . selector == sig :executeFromExecutor ( bytes32 , bytes ) . selector &&
87
+ isExecutionModule
88
+ ) || (
89
+ f . selector == sig :installModule ( uint256 , address , bytes ) . selector &&
90
+ isEntryPointOrSelf
91
+ ) || (
92
+ f . selector == sig :uninstallModule ( uint256 , address , bytes ) . selector &&
93
+ isEntryPointOrSelf
94
+ ) || (
95
+ f . selector == sig :validateUserOp ( Account . PackedUserOperation , bytes32 , uint256 ) . selector &&
96
+ isEntryPoint &&
97
+ (
98
+ // payPrefund ( target is entryPoint and argsLength is 0 )
99
+ ( call_target == entryPoint ( ) && call_argsLength == 0 && call_value > 0 )
100
+ ||
101
+ // isValidSignatureWithSender ( target is as validation module )
102
+ ( isModuleInstalled ( 1 , call_target , context ) )
103
+ )
104
+ ) || (
105
+ fallbackHandler != 0 &&
106
+ call_target == fallbackHandler
107
+ )
108
+ ) ;
109
+ }
0 commit comments