@@ -6,6 +6,7 @@ import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
6
6
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol " ;
7
7
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol " ;
8
8
import { ExecutionLib } from "@erc7579/lib/ExecutionLib.sol " ;
9
+ import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol " ;
9
10
10
11
import { BasicERC20 } from "../utils/BasicERC20.t.sol " ;
11
12
import { BaseTest } from "../utils/BaseTest.t.sol " ;
@@ -92,7 +93,7 @@ abstract contract DelegationMetaSwapAdapterBaseTest is BaseTest {
92
93
* @dev Generates a valid signature for _apiData with a given _expiration.
93
94
*/
94
95
function _getValidSignature (bytes memory _apiData , uint256 _expiration ) internal returns (bytes memory ) {
95
- bytes32 messageHash = keccak256 (abi.encodePacked (_apiData, _expiration));
96
+ bytes32 messageHash = keccak256 (abi.encode (_apiData, _expiration));
96
97
bytes32 ethSignedMessageHash = MessageHashUtils.toEthSignedMessageHash (messageHash);
97
98
(uint8 v , bytes32 r , bytes32 s ) = vm.sign (swapSignerPrivateKey, ethSignedMessageHash);
98
99
return abi.encodePacked (r, s, v);
@@ -296,10 +297,114 @@ abstract contract DelegationMetaSwapAdapterBaseTest is BaseTest {
296
297
* @notice These tests run in a purely local environment. No fork is created.
297
298
*/
298
299
contract DelegationMetaSwapAdapterMockTest is DelegationMetaSwapAdapterBaseTest {
300
+ DelegationMetaSwapAdapterSignatureTest public adapter;
301
+ address public swapApiSigner;
302
+ uint256 private _swapSignerPrivateKey = 12345 ;
303
+
299
304
function setUp () public override {
300
305
super .setUp ();
306
+ swapApiSigner = vm.addr (_swapSignerPrivateKey);
307
+ adapter =
308
+ new DelegationMetaSwapAdapterSignatureTest (address (this ), swapApiSigner, address (0x123 ), address (0x456 ), address (0x789 ));
309
+ }
310
+
311
+ ////////////////////////////// Signature validation tests //////////////////////////////
312
+
313
+ /**
314
+ * @notice Verifies that a valid signature is accepted.
315
+ */
316
+ function test_validateSignature_valid () public view {
317
+ bytes memory apiData_ = hex "1234 " ;
318
+ uint256 expiration_ = block .timestamp + 1 hours ;
319
+ bytes32 messageHash_ = keccak256 (abi.encode (apiData_, expiration_));
320
+ bytes32 ethSignedMessageHash_ = MessageHashUtils.toEthSignedMessageHash (messageHash_);
321
+ (uint8 v_ , bytes32 r_ , bytes32 s_ ) = vm.sign (_swapSignerPrivateKey, ethSignedMessageHash_);
322
+ bytes memory signature_ = abi.encodePacked (r_, s_, v_);
323
+
324
+ DelegationMetaSwapAdapter.SignatureData memory sigData_ =
325
+ DelegationMetaSwapAdapter.SignatureData ({ apiData: apiData_, expiration: expiration_, signature: signature_ });
326
+
327
+ adapter.exposedValidateSignature (sigData_);
328
+ }
329
+
330
+ /**
331
+ * @notice Verifies that an expired signature is rejected.
332
+ */
333
+ function test_validateSignature_expired () public {
334
+ bytes memory apiData_ = hex "1234 " ;
335
+ uint256 expiration_ = block .timestamp - 1 ;
336
+ bytes32 messageHash_ = keccak256 (abi.encode (apiData_, expiration_));
337
+ bytes32 ethSignedMessageHash_ = MessageHashUtils.toEthSignedMessageHash (messageHash_);
338
+ (uint8 v_ , bytes32 r_ , bytes32 s_ ) = vm.sign (_swapSignerPrivateKey, ethSignedMessageHash_);
339
+ bytes memory signature_ = abi.encodePacked (r_, s_, v_);
340
+
341
+ DelegationMetaSwapAdapter.SignatureData memory sigData_ =
342
+ DelegationMetaSwapAdapter.SignatureData ({ apiData: apiData_, expiration: expiration_, signature: signature_ });
343
+
344
+ vm.expectRevert (DelegationMetaSwapAdapter.SignatureExpired.selector );
345
+ adapter.exposedValidateSignature (sigData_);
346
+ }
347
+
348
+ /**
349
+ * @notice Verifies that an invalid signature is rejected.
350
+ */
351
+ function test_validateSignature_invalidSigner () public {
352
+ bytes memory apiData = hex "1234 " ;
353
+ uint256 expiration = block .timestamp + 1 hours ;
354
+ bytes32 messageHash = keccak256 (abi.encode (apiData, expiration));
355
+ // Use a different private key to generate an invalid signature
356
+ (uint8 v , bytes32 r , bytes32 s ) = vm.sign (_swapSignerPrivateKey + 1 , messageHash);
357
+ bytes memory signature = abi.encodePacked (r, s, v);
358
+
359
+ DelegationMetaSwapAdapter.SignatureData memory sigData =
360
+ DelegationMetaSwapAdapter.SignatureData ({ apiData: apiData, expiration: expiration, signature: signature });
361
+
362
+ vm.expectRevert (DelegationMetaSwapAdapter.InvalidApiSignature.selector );
363
+ adapter.exposedValidateSignature (sigData);
301
364
}
302
365
366
+ /**
367
+ * @notice Verifies that an empty signature is rejected.
368
+ */
369
+ function test_validateSignature_emptySignature () public {
370
+ bytes memory apiData = hex "1234 " ;
371
+ uint256 expiration = block .timestamp + 1 hours ;
372
+ bytes memory emptySignature = "" ;
373
+
374
+ DelegationMetaSwapAdapter.SignatureData memory sigData =
375
+ DelegationMetaSwapAdapter.SignatureData ({ apiData: apiData, expiration: expiration, signature: emptySignature });
376
+
377
+ vm.expectRevert (abi.encodeWithSelector (ECDSA.ECDSAInvalidSignatureLength.selector , 0 ));
378
+ adapter.exposedValidateSignature (sigData);
379
+ }
380
+
381
+ /**
382
+ * @notice Verifies that a hardcoded valid signature works
383
+ */
384
+ function test_validateSignature_hardcodedSignature () public {
385
+ // Taken from the swaps api
386
+ address swapApiSigner_ = 0x533FbF047Ed13C20e263e2576e41c747206d1348 ;
387
+
388
+ vm.prank (address (this ));
389
+ adapter.setSwapApiSigner (swapApiSigner_);
390
+
391
+ bytes memory apiData_ =
392
+ hex"5f5755290000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000470de4df82000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000001c616972737761704c696768743446656544796e616d696346697865640000000000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000196652ed3350000000000000000000000000000000000000000000000000000000068098586000000000000000000000000111bb8c3542f2b92fb41b8d913c01d37884311110000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000001eb87e2999f2f8380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000466ebb82ac1000000000000000000000000000000000000000000000000000000000000000001c427cdd17278850f9344bb9b4940a6ce83afbb34b58410cdcdf1ff8b27ea8b7eb338693a44fa8d73a0878779e2f6b41c6af69f42510d98f1bfd19d7675e1b3a9d00000000000000000000000000000000000000000000000000009f295cd5f000000000000000000000000000f326e4de8f66a0bdc0970b79e0924e33c79f19150000000000000000000000000000000000000000000000000000000000000000007f";
393
+ uint256 expiration_ = 1745454591251 ;
394
+
395
+ // This signature was generated with the test private key for the above data and expiration
396
+ bytes memory signature =
397
+ hex "fccc4800a4a9d9aa6a8cf933ca759f3974d8eed02e47b12a739601ef1e83617a08c7597d0dd875f955511248da6cf4cfb92be67c0d7241104c061a3c4d45f3b51b " ;
398
+
399
+ DelegationMetaSwapAdapter.SignatureData memory sigData_ =
400
+ DelegationMetaSwapAdapter.SignatureData ({ apiData: apiData_, expiration: expiration_, signature: signature });
401
+
402
+ // Should not revert since signature is valid
403
+ adapter.exposedValidateSignature (sigData_);
404
+ }
405
+
406
+ ////////////////////////////// Swap tests //////////////////////////////
407
+
303
408
/**
304
409
* @notice Verifies that the contract reverts when the zero address is used as an input.
305
410
*/
@@ -1501,3 +1606,25 @@ contract MetaSwapMock {
1501
1606
}
1502
1607
}
1503
1608
}
1609
+
1610
+ contract DelegationMetaSwapAdapterSignatureTest is DelegationMetaSwapAdapter {
1611
+ constructor (
1612
+ address _owner ,
1613
+ address _swapApiSigner ,
1614
+ address _delegationManager ,
1615
+ address _metaSwap ,
1616
+ address _argsEqualityCheckEnforcer
1617
+ )
1618
+ DelegationMetaSwapAdapter (
1619
+ _owner,
1620
+ _swapApiSigner,
1621
+ IDelegationManager (_delegationManager),
1622
+ IMetaSwap (_metaSwap),
1623
+ _argsEqualityCheckEnforcer
1624
+ )
1625
+ { }
1626
+
1627
+ function exposedValidateSignature (SignatureData memory _signatureData ) public view {
1628
+ _validateSignature (_signatureData);
1629
+ }
1630
+ }
0 commit comments