@@ -10,6 +10,7 @@ import {KeyRegistryHarness} from "./utils/KeyRegistryHarness.sol";
1010import {IdRegistry} from "../../src/IdRegistry.sol " ;
1111import {StubValidator} from "../Utils.sol " ;
1212
13+ /// @custom:halmos --default-bytes-lengths 0,32,1024,65
1314contract KeyRegistrySymTest is SymTest , Test {
1415 IdRegistry idRegistry;
1516 address idRegistration;
@@ -81,7 +82,7 @@ contract KeyRegistrySymTest is SymTest, Test {
8182 }
8283
8384 // Verify the KeyRegistry invariants
84- function check_Invariants (bytes4 selector , address caller ) public {
85+ function check_Invariants (address caller ) public {
8586 // Additional setup to cover various input states
8687 if (svm.createBool ("migrate? " )) {
8788 vm.prank (migrator);
@@ -107,8 +108,16 @@ contract KeyRegistrySymTest is SymTest, Test {
107108 ! keyRegistry.isMigrated () || block .timestamp <= keyRegistry.migratedAt () + keyRegistry.gracePeriod ();
108109
109110 // Execute an arbitrary tx to KeyRegistry
111+ bytes memory data = svm.createCalldata ("KeyRegistry " );
112+ bytes4 selector = bytes4 (data);
113+
114+ // Link the first argument of removeFor() to the user variable so that it can be used later in assertions
115+ if (selector == keyRegistry.removeFor.selector ) {
116+ vm.assume (user == address (uint160 (uint256 (bytes32 (this .slice (data, 4 , 36 ))))));
117+ }
118+
110119 vm.prank (caller);
111- (bool success ,) = address (keyRegistry).call (mk_calldata (selector, user) );
120+ (bool success ,) = address (keyRegistry).call (data );
112121 vm.assume (success); // ignore reverting cases
113122
114123 // Record post-state
@@ -170,95 +179,7 @@ contract KeyRegistrySymTest is SymTest, Test {
170179 }
171180 }
172181
173- // Case-splitting tactic: explicitly branching into two states: cond vs !cond
174- function split_cases (bool cond ) internal pure {
175- if (cond) return ;
176- }
177-
178- function mk_calldata (bytes4 selector , address user ) internal returns (bytes memory ) {
179- // Ignore view functions
180- vm.assume (selector != keyRegistry.REMOVE_TYPEHASH.selector );
181- vm.assume (selector != keyRegistry.VERSION.selector );
182- vm.assume (selector != keyRegistry.eip712Domain.selector );
183- vm.assume (selector != keyRegistry.gatewayFrozen.selector );
184- vm.assume (selector != keyRegistry.gracePeriod.selector );
185- vm.assume (selector != keyRegistry.guardians.selector );
186- vm.assume (selector != keyRegistry.idRegistry.selector );
187- vm.assume (selector != keyRegistry.isMigrated.selector );
188- vm.assume (selector != keyRegistry.keyAt.selector );
189- vm.assume (selector != keyRegistry.keyDataOf.selector );
190- vm.assume (selector != keyRegistry.keyGateway.selector );
191- vm.assume (selector != keyRegistry.keys.selector );
192- vm.assume (selector != bytes4 (0x1f64222f )); // keysOf
193- vm.assume (selector != bytes4 (0xf27995e3 )); // keysOf paged
194- vm.assume (selector != keyRegistry.maxKeysPerFid.selector );
195- vm.assume (selector != keyRegistry.migratedAt.selector );
196- vm.assume (selector != keyRegistry.migrator.selector );
197- vm.assume (selector != keyRegistry.nonces.selector );
198- vm.assume (selector != keyRegistry.owner.selector );
199- vm.assume (selector != keyRegistry.paused.selector );
200- vm.assume (selector != keyRegistry.pendingOwner.selector );
201- vm.assume (selector != keyRegistry.totalKeys.selector );
202- vm.assume (selector != keyRegistry.validators.selector );
203-
204- // Create symbolic values to be included in calldata
205- uint256 fid = svm.createUint256 ("fid " );
206- uint32 keyType = uint32 (svm.createUint (32 , "keyType " ));
207- bytes memory key = svm.createBytes (32 , "key " );
208- uint8 metadataType = uint8 (svm.createUint (8 , "metadataType " ));
209- bytes memory metadata = svm.createBytes (32 , "metadata " );
210- uint256 deadline = svm.createUint256 ("deadline " );
211- bytes memory sig = svm.createBytes (65 , "sig " );
212-
213- // Halmos requires symbolic dynamic arrays to be given with a specific size.
214- // In this test, we provide arrays with length 2.
215- IKeyRegistry.BulkAddData[] memory addData = new IKeyRegistry.BulkAddData [](2 );
216- IKeyRegistry.BulkResetData[] memory resetData = new IKeyRegistry.BulkResetData [](2 );
217-
218- // New scope, stack workaround.
219- {
220- bytes [][] memory fidKeys = new bytes [][](2 );
221- fidKeys[0 ] = new bytes [](1 );
222- fidKeys[0 ][0 ] = key;
223-
224- bytes memory key2 = svm.createBytes (32 , "key2 " );
225- fidKeys[1 ] = new bytes [](1 );
226- fidKeys[1 ][0 ] = key2;
227-
228- uint256 fid2 = svm.createUint256 ("fid2 " );
229-
230- IKeyRegistry.BulkAddKey[] memory keyData1 = new IKeyRegistry.BulkAddKey [](1 );
231- IKeyRegistry.BulkAddKey[] memory keyData2 = new IKeyRegistry.BulkAddKey [](1 );
232- keyData1[0 ] = IKeyRegistry.BulkAddKey ({key: key, metadata: "" });
233- keyData2[0 ] = IKeyRegistry.BulkAddKey ({key: key2, metadata: "" });
234-
235- addData[0 ] = IKeyRegistry.BulkAddData ({fid: fid, keys: keyData1});
236- addData[1 ] = IKeyRegistry.BulkAddData ({fid: fid2, keys: keyData2});
237-
238- resetData[0 ] = IKeyRegistry.BulkResetData ({fid: fid, keys: fidKeys[0 ]});
239- resetData[1 ] = IKeyRegistry.BulkResetData ({fid: fid2, keys: fidKeys[1 ]});
240- }
241-
242- // Generate calldata based on the function selector
243- bytes memory args;
244- if (selector == keyRegistry.add.selector ) {
245- // Explicitly branching based on conditions.
246- // Note: The negations of conditions are also taken into account.
247- split_cases (keyType == uint32 (1 ) && metadataType == uint8 (1 ));
248- args = abi.encode (user, keyType, key, metadataType, metadata);
249- } else if (selector == keyRegistry.remove.selector ) {
250- args = abi.encode (key);
251- } else if (selector == keyRegistry.removeFor.selector ) {
252- args = abi.encode (user, key, deadline, sig);
253- } else if (selector == keyRegistry.bulkAddKeysForMigration.selector ) {
254- args = abi.encode (addData);
255- } else if (selector == keyRegistry.bulkResetKeysForMigration.selector ) {
256- args = abi.encode (resetData);
257- } else {
258- // For functions where all parameters are static (not dynamic arrays or bytes),
259- // a raw byte array is sufficient instead of explicitly specifying each argument.
260- args = svm.createBytes (1024 , "data " ); // choose a size that is large enough to cover all parameters
261- }
262- return abi.encodePacked (selector, args);
182+ function slice (bytes calldata data , uint start , uint end ) external returns (bytes memory ) {
183+ return data[start:end];
263184 }
264185}
0 commit comments