@@ -72,4 +72,39 @@ contract ERC7739Test is DelegationHandler, TokenHandler, ERC1271Handler, FFISign
72
72
// Assert that the signature is valid when compared against the ffi generated signature
73
73
assertEq (signature, key.sign (typedDataSignDigest));
74
74
}
75
+
76
+ function test_signTypedSignData_usingImplicitType_wrongSignature_ffi () public {
77
+ TestKey memory key = TestKeyManager.withSeed (KeyType.Secp256k1, signerPrivateKey);
78
+
79
+ PermitSingle memory permitSingle = PermitSingle ({
80
+ details: PermitDetails ({token: address (0 ), amount: 0 , expiration: 0 , nonce: 0 }),
81
+ spender: address (0 ),
82
+ sigDeadline: 0
83
+ });
84
+ // Locally generate the full TypedSignData hash
85
+ bytes32 contentsHash = mockERC1271VerifyingContract.hash (permitSingle);
86
+ bytes32 appSeparator = mockERC1271VerifyingContract.domainSeparator ();
87
+
88
+ // Incorrectly use the implicit type descriptor string, causing the top level type to be
89
+ // TypeDataSign(...)PermitSingle(...)PermitDetails(...) which does not follow EIP-712 ordering
90
+ string memory contentsDescrImplicit = mockERC1271VerifyingContract.contentsDescrImplicit ();
91
+
92
+ bytes memory signerAccountDomainBytes = IERC5267 (address (signerAccount)).toDomainBytes ();
93
+ bytes32 typedDataSignDigest =
94
+ contentsHash.hashTypedDataSign (signerAccountDomainBytes, appSeparator, contentsDescrImplicit);
95
+
96
+ // Make it clear that the verifying contract is set properly.
97
+ address verifyingContract = address (signerAccount);
98
+
99
+ (bytes memory signature ) = ffi_signWrappedTypedData (
100
+ signerPrivateKey,
101
+ verifyingContract,
102
+ DOMAIN_NAME,
103
+ DOMAIN_VERSION,
104
+ address (mockERC1271VerifyingContract),
105
+ permitSingle
106
+ );
107
+ // Assert that the ffi generated signature is NOT the same as the locally generated signature
108
+ assertNotEq (signature, key.sign (typedDataSignDigest));
109
+ }
75
110
}
0 commit comments