@@ -4,6 +4,8 @@ pragma solidity ^0.8.25;
44import {IModule, ModuleMetadata} from "../../interfaces/IModule.sol " ;
55import {IValidationModule} from "../../interfaces/IValidationModule.sol " ;
66import {BaseModule} from "../BaseModule.sol " ;
7+
8+ import {ReplaySafeWrapper} from "../ReplaySafeWrapper.sol " ;
79import {ISingleSignerValidationModule} from "./ISingleSignerValidationModule.sol " ;
810import {PackedUserOperation} from "@eth-infinitism/account-abstraction/interfaces/PackedUserOperation.sol " ;
911import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol " ;
@@ -17,12 +19,11 @@ import {SignatureChecker} from "@openzeppelin/contracts/utils/cryptography/Signa
1719/// the account. Account states are to be retrieved from this global singleton directly.
1820///
1921/// - This validation supports ERC-1271. The signature is valid if it is signed by the owner's private key
20- /// (if the owner is an EOA) or if it is a valid ERC-1271 signature from the
21- /// owner (if the owner is a contract).
22+ /// (if the owner is an EOA) or if it is a valid ERC-1271 signature from the owner (if the owner is a contract).
2223///
2324/// - This validation supports composition that other validation can relay on entities in this validation
2425/// to validate partially or fully.
25- contract SingleSignerValidationModule is ISingleSignerValidationModule , BaseModule {
26+ contract SingleSignerValidationModule is ISingleSignerValidationModule , ReplaySafeWrapper , BaseModule {
2627 using MessageHashUtils for bytes32 ;
2728
2829 string internal constant _NAME = "SingleSigner Validation " ;
@@ -93,14 +94,17 @@ contract SingleSignerValidationModule is ISingleSignerValidationModule, BaseModu
9394 /// @inheritdoc IValidationModule
9495 /// @dev The signature is valid if it is signed by the owner's private key
9596 /// (if the owner is an EOA) or if it is a valid ERC-1271 signature from the
96- /// owner (if the owner is a contract). Note that the signature is wrapped in an EIP-191 message
97+ /// owner (if the owner is a contract).
98+ /// Note that the digest is wrapped in an EIP-712 struct to prevent cross-account replay attacks. The
99+ /// replay-safe hash may be retrieved by calling the public function `replaySafeHash`.
97100 function validateSignature (address account , uint32 entityId , address , bytes32 digest , bytes calldata signature )
98101 external
99102 view
100103 override
101104 returns (bytes4 )
102105 {
103- if (SignatureChecker.isValidSignatureNow (signers[entityId][account], digest, signature)) {
106+ bytes32 _replaySafeHash = replaySafeHash (account, digest);
107+ if (SignatureChecker.isValidSignatureNow (signers[entityId][account], _replaySafeHash, signature)) {
104108 return _1271_MAGIC_VALUE;
105109 }
106110 return _1271_INVALID;
0 commit comments