@@ -6,6 +6,7 @@ import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
66import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol " ;
77import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol " ;
88import { ExecutionLib } from "@erc7579/lib/ExecutionLib.sol " ;
9+ import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol " ;
910
1011import { BasicERC20 } from "../utils/BasicERC20.t.sol " ;
1112import { BaseTest } from "../utils/BaseTest.t.sol " ;
@@ -92,7 +93,7 @@ abstract contract DelegationMetaSwapAdapterBaseTest is BaseTest {
9293 * @dev Generates a valid signature for _apiData with a given _expiration.
9394 */
9495 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));
9697 bytes32 ethSignedMessageHash = MessageHashUtils.toEthSignedMessageHash (messageHash);
9798 (uint8 v , bytes32 r , bytes32 s ) = vm.sign (swapSignerPrivateKey, ethSignedMessageHash);
9899 return abi.encodePacked (r, s, v);
@@ -296,10 +297,114 @@ abstract contract DelegationMetaSwapAdapterBaseTest is BaseTest {
296297 * @notice These tests run in a purely local environment. No fork is created.
297298 */
298299contract DelegationMetaSwapAdapterMockTest is DelegationMetaSwapAdapterBaseTest {
300+ DelegationMetaSwapAdapterSignatureTest public adapter;
301+ address public swapApiSigner;
302+ uint256 private _swapSignerPrivateKey = 12345 ;
303+
299304 function setUp () public override {
300305 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);
301364 }
302365
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+
303408 /**
304409 * @notice Verifies that tokens can be swapped by delegations in a purely local environment (using a MetaSwapMock).
305410 */
@@ -1444,3 +1549,25 @@ contract MetaSwapMock {
14441549 }
14451550 }
14461551}
1552+
1553+ contract DelegationMetaSwapAdapterSignatureTest is DelegationMetaSwapAdapter {
1554+ constructor (
1555+ address _owner ,
1556+ address _swapApiSigner ,
1557+ address _delegationManager ,
1558+ address _metaSwap ,
1559+ address _argsEqualityCheckEnforcer
1560+ )
1561+ DelegationMetaSwapAdapter (
1562+ _owner,
1563+ _swapApiSigner,
1564+ IDelegationManager (_delegationManager),
1565+ IMetaSwap (_metaSwap),
1566+ _argsEqualityCheckEnforcer
1567+ )
1568+ { }
1569+
1570+ function exposedValidateSignature (SignatureData memory _signatureData ) public view {
1571+ _validateSignature (_signatureData);
1572+ }
1573+ }
0 commit comments