Skip to content

Commit 0644d7a

Browse files
Derek SorensenDerek Sorensen
authored andcommitted
enhances rules about module and transaction guards to include the proposition that the correct guard is called
1 parent 853c03b commit 0644d7a

File tree

4 files changed

+175
-7
lines changed

4 files changed

+175
-7
lines changed

certora/conf/v1.5/guards.conf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
"files": [
44
"certora/harnesses/SafeHarness.sol",
55
"certora/mocks/ModuleGuardMock.sol", // a module guard
6+
"certora/mocks/ModuleGuardMockDuplicate.sol",
67
"certora/mocks/TxnGuardMock.sol", // a (safe) guard
8+
"certora/mocks/TxnGuardMockDuplicate.sol",
79
],
810
"link": [
911

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// SPDX-License-Identifier: LGPL-3.0-only
2+
/* solhint-disable one-contract-per-file */
3+
pragma solidity >=0.7.0 <0.9.0;
4+
import {IModuleGuard} from "../munged/base/ModuleManager.sol";
5+
import {IERC165} from "../munged/interfaces/IERC165.sol";
6+
import "../munged/libraries/Enum.sol";
7+
8+
contract ModuleGuardMockDuplicate is IModuleGuard {
9+
10+
constructor(){
11+
preCheckedTransactions = false ;
12+
postCheckedTransactions = false ;
13+
}
14+
15+
// some mock variables
16+
bool public preCheckedTransactions ;
17+
bool public postCheckedTransactions ;
18+
19+
function resetChecks() external {
20+
preCheckedTransactions = false ;
21+
postCheckedTransactions = false ;
22+
}
23+
24+
/**
25+
* @notice Checks the module transaction details.
26+
* @dev The function needs to implement module transaction validation logic.
27+
* @param to The address to which the transaction is intended.
28+
* @param value The value of the transaction in Wei.
29+
* @param data The transaction data.
30+
* @param operation The type of operation of the module transaction.
31+
* @param module The module involved in the transaction.
32+
* @return moduleTxHash The hash of the module transaction.
33+
*/
34+
function checkModuleTransaction(
35+
address to,
36+
uint256 value,
37+
bytes memory data,
38+
Enum.Operation operation,
39+
address module
40+
) external override returns (bytes32 moduleTxHash) {
41+
// updates transaction checked
42+
preCheckedTransactions = true ;
43+
// if it passes, it returns a string of bytes
44+
return bytes32(0);
45+
}
46+
47+
/**
48+
* @notice Checks after execution of module transaction.
49+
* @dev The function needs to implement a check after the execution of the module transaction.
50+
* @param txHash The hash of the module transaction.
51+
* @param success The status of the module transaction execution.
52+
*/
53+
function checkAfterModuleExecution(bytes32 txHash, bool success) external override {
54+
postCheckedTransactions = true;
55+
}
56+
57+
/**
58+
* @dev Returns true if this contract implements the interface defined by `interfaceId`.
59+
* See the corresponding EIP section
60+
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified
61+
* to learn more about how these ids are created.
62+
*
63+
* This function call must use less than 30 000 gas.
64+
*/
65+
function supportsInterface(bytes4 interfaceId) external view virtual override returns (bool) {
66+
return
67+
interfaceId == type(IModuleGuard).interfaceId || // 0x58401ed8
68+
interfaceId == type(IERC165).interfaceId; // 0x01ffc9a7
69+
}
70+
71+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// SPDX-License-Identifier: LGPL-3.0-only
2+
/* solhint-disable one-contract-per-file */
3+
pragma solidity >=0.7.0 <0.9.0;
4+
import {ITransactionGuard} from "../munged/base/GuardManager.sol";
5+
import {IERC165} from "../munged/interfaces/IERC165.sol";
6+
import "../munged/libraries/Enum.sol";
7+
8+
contract TxnGuardMockDuplicate is ITransactionGuard {
9+
10+
constructor(){}
11+
12+
// some mock variables
13+
bool public preCheckedTransactions ;
14+
bool public postCheckedTransactions ;
15+
16+
function resetChecks() external {
17+
preCheckedTransactions = false ;
18+
postCheckedTransactions = false ;
19+
}
20+
21+
/**
22+
* @notice Checks the transaction details.
23+
* @dev The function needs to implement transaction validation logic.
24+
* @param to The address to which the transaction is intended.
25+
* @param value The value of the transaction in Wei.
26+
* @param data The transaction data.
27+
* @param operation The type of operation of the transaction.
28+
* @param safeTxGas Gas used for the transaction.
29+
* @param baseGas The base gas for the transaction.
30+
* @param gasPrice The price of gas in Wei for the transaction.
31+
* @param gasToken The token used to pay for gas.
32+
* @param refundReceiver The address which should receive the refund.
33+
* @param signatures The signatures of the transaction.
34+
* @param msgSender The address of the message sender.
35+
*/
36+
function checkTransaction(
37+
address to,
38+
uint256 value,
39+
bytes memory data,
40+
Enum.Operation operation,
41+
uint256 safeTxGas,
42+
uint256 baseGas,
43+
uint256 gasPrice,
44+
address gasToken,
45+
address payable refundReceiver,
46+
bytes memory signatures,
47+
address msgSender
48+
) external override {
49+
// updates transaction checked
50+
preCheckedTransactions = true;
51+
}
52+
53+
/**
54+
* @notice Checks after execution of the transaction.
55+
* @dev The function needs to implement a check after the execution of the transaction.
56+
* @param hash The hash of the transaction.
57+
* @param success The status of the transaction execution.
58+
*/
59+
function checkAfterExecution(bytes32 hash, bool success) external override {
60+
// updates transaction checked
61+
postCheckedTransactions = true ;
62+
}
63+
64+
/**
65+
* @dev Returns true if this contract implements the interface defined by `interfaceId`.
66+
* See the corresponding EIP section
67+
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified
68+
* to learn more about how these ids are created.
69+
*
70+
* This function call must use less than 30 000 gas.
71+
*/
72+
function supportsInterface(bytes4 interfaceId) external view virtual override returns (bool) {
73+
return
74+
interfaceId == type(ITransactionGuard).interfaceId || // 0xe6d7a83a
75+
interfaceId == type(IERC165).interfaceId; // 0x01ffc9a7
76+
}
77+
78+
}

certora/specs/v1.5/Guards.spec

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
/* A specification of the safe guard and module guard */
22

33
using ModuleGuardMock as modGuardMock;
4+
using ModuleGuardMockDuplicate as modGuardMock2;
45
using TxnGuardMock as txnGuardMock;
6+
using TxnGuardMockDuplicate as txnGuardMock2;
57
using SafeHarness as safe;
68

79
// ---- Methods block ----------------------------------------------------------
@@ -140,7 +142,7 @@ rule setModuleGuardReentrant(address guard) {
140142

141143

142144
/// @dev the transaction guard gets called both pre- and post- any execTransaction
143-
/// @status Done: https://prover.certora.com/output/39601/a05e24787c68404d877ae4acce693734?anonymousKey=02030d2ca97a19d0d7a70deb5a91dc4b75bca89d
145+
/// @status Done: https://prover.certora.com/output/39601/a9a8eaeba7994e10bf29dbe8813798b9?anonymousKey=fbddda2f78b44a7df3dff4707715b90b2d08ab63
144146
rule txnGuardCalled(
145147
address to,
146148
uint256 value,
@@ -157,19 +159,24 @@ rule txnGuardCalled(
157159
// the txn guard is the mock
158160
require (getSafeGuard() == txnGuardMock);
159161

160-
// execTxn passes
162+
txnGuardMock.resetChecks(e); // reset the check triggers
163+
txnGuardMock2.resetChecks(e);
164+
161165
execTransaction(e,to,value,data,operation,safeTxGas,baseGas,
162166
gasPrice,gasToken,refundReceiver,signatures);
163167

164168
// the pre- and post- module transaction guards were called
165169
assert (
166170
txnGuardMock.preCheckedTransactions() &&
167-
txnGuardMock.postCheckedTransactions()
171+
txnGuardMock.postCheckedTransactions() &&
172+
// the right guard was called
173+
!txnGuardMock2.preCheckedTransactions(e) &&
174+
!txnGuardMock2.postCheckedTransactions(e)
168175
);
169176
}
170177

171178
/// @dev the module guard gets called both pre- and post- any execTransactionFromModule
172-
/// @status Done: https://prover.certora.com/output/39601/a05e24787c68404d877ae4acce693734?anonymousKey=02030d2ca97a19d0d7a70deb5a91dc4b75bca89d
179+
/// @status Done: https://prover.certora.com/output/39601/7591e8c61e6d407b847e38bbe8238e13?anonymousKey=5d99429f5046e77825a4ed015af0a6a0d088538d
173180
rule moduleGuardCalled(
174181
address to,
175182
uint256 value,
@@ -180,17 +187,22 @@ rule moduleGuardCalled(
180187
require (getModuleGuardExternal() == modGuardMock);
181188

182189
modGuardMock.resetChecks(e); // reset the check triggers
190+
modGuardMock2.resetChecks(e);
191+
183192
execTransactionFromModule(e,to,value,data,operation);
184193

185194
// the pre- and post- module transaction guards were called
186195
assert (
187196
modGuardMock.preCheckedTransactions() &&
188-
modGuardMock.postCheckedTransactions()
197+
modGuardMock.postCheckedTransactions() &&
198+
// the correct guard was called
199+
!modGuardMock2.preCheckedTransactions(e) &&
200+
!modGuardMock2.postCheckedTransactions(e)
189201
);
190202
}
191203

192204
/// @dev the module guard gets called both pre- and post- any execTransactionFromModuleReturnData
193-
/// @status Done: https://prover.certora.com/output/39601/15cfd3430d794986a26d304c9e2fbc6e?anonymousKey=92f0976aba6cb3fe40cf6c728d34b140a438bbae
205+
/// @status Done: https://prover.certora.com/output/39601/2de5a471d628464e8aaf4b9022e515de?anonymousKey=c4997fd77ba3808cf9bdc6a432f9b20eea551c95
194206
rule moduleGuardCalledReturn(
195207
address to,
196208
uint256 value,
@@ -201,12 +213,17 @@ rule moduleGuardCalledReturn(
201213
require (getModuleGuardExternal() == modGuardMock);
202214

203215
modGuardMock.resetChecks(e); // reset the check triggers
216+
modGuardMock2.resetChecks(e);
217+
204218
execTransactionFromModuleReturnData(e,to,value,data,operation);
205219

206220
// the pre- and post- module transaction guards were called
207221
assert (
208222
modGuardMock.preCheckedTransactions() &&
209-
modGuardMock.postCheckedTransactions()
223+
modGuardMock.postCheckedTransactions() &&
224+
// the correct guard was called
225+
!modGuardMock2.preCheckedTransactions(e) &&
226+
!modGuardMock2.postCheckedTransactions(e)
210227
);
211228
}
212229

0 commit comments

Comments
 (0)