diff --git a/.changeset/wet-bottles-tie.md b/.changeset/wet-bottles-tie.md new file mode 100644 index 00000000000..2b86ee3a5fc --- /dev/null +++ b/.changeset/wet-bottles-tie.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': minor +--- + +`Account`: Add `signature` argument to the internal `_validateUserOp` function for custom signature handling logic. diff --git a/contracts/account/Account.sol b/contracts/account/Account.sol index 0767d5b7c9b..3c882596ca0 100644 --- a/contracts/account/Account.sol +++ b/contracts/account/Account.sol @@ -75,7 +75,7 @@ abstract contract Account is AbstractSigner, IAccount { bytes32 userOpHash, uint256 missingAccountFunds ) public virtual onlyEntryPoint returns (uint256) { - uint256 validationData = _validateUserOp(userOp, userOpHash); + uint256 validationData = _validateUserOp(userOp, userOpHash, userOp.signature); _payPrefund(missingAccountFunds); return validationData; } @@ -84,15 +84,21 @@ abstract contract Account is AbstractSigner, IAccount { * @dev Returns the validationData for a given user operation. By default, this checks the signature of the * signable hash (produced by {_signableUserOpHash}) using the abstract signer ({AbstractSigner-_rawSignatureValidation}). * + * The `signature` parameter is taken directly from the user operation's `signature` field. + * This design enables derived contracts to implement custom signature handling logic, + * such as embedding additional data within the signature and processing it by overriding this function + * and optionally invoking `super`. + * * NOTE: The userOpHash is assumed to be correct. Calling this function with a userOpHash that does not match the * userOp will result in undefined behavior. */ function _validateUserOp( PackedUserOperation calldata userOp, - bytes32 userOpHash + bytes32 userOpHash, + bytes calldata signature ) internal virtual returns (uint256) { return - _rawSignatureValidation(_signableUserOpHash(userOp, userOpHash), userOp.signature) + _rawSignatureValidation(_signableUserOpHash(userOp, userOpHash), signature) ? ERC4337Utils.SIG_VALIDATION_SUCCESS : ERC4337Utils.SIG_VALIDATION_FAILED; } diff --git a/contracts/account/extensions/draft-AccountERC7579.sol b/contracts/account/extensions/draft-AccountERC7579.sol index 41ebf2fed20..cd982167da1 100644 --- a/contracts/account/extensions/draft-AccountERC7579.sol +++ b/contracts/account/extensions/draft-AccountERC7579.sol @@ -207,13 +207,14 @@ abstract contract AccountERC7579 is Account, IERC1271, IERC7579Execution, IERC75 */ function _validateUserOp( PackedUserOperation calldata userOp, - bytes32 userOpHash + bytes32 userOpHash, + bytes calldata signature ) internal virtual override returns (uint256) { address module = _extractUserOpValidator(userOp); return isModuleInstalled(MODULE_TYPE_VALIDATOR, module, Calldata.emptyBytes()) ? IERC7579Validator(module).validateUserOp(userOp, _signableUserOpHash(userOp, userOpHash)) - : super._validateUserOp(userOp, userOpHash); + : super._validateUserOp(userOp, userOpHash, signature); } /** diff --git a/contracts/mocks/account/AccountMock.sol b/contracts/mocks/account/AccountMock.sol index b9617ca7454..b5e17bf42c7 100644 --- a/contracts/mocks/account/AccountMock.sol +++ b/contracts/mocks/account/AccountMock.sol @@ -102,9 +102,10 @@ abstract contract AccountERC7702WithModulesMock is { function _validateUserOp( PackedUserOperation calldata userOp, - bytes32 userOpHash + bytes32 userOpHash, + bytes calldata signature ) internal virtual override(Account, AccountERC7579) returns (uint256) { - return super._validateUserOp(userOp, userOpHash); + return super._validateUserOp(userOp, userOpHash, signature); } /// @dev Resolve implementation of ERC-1271 by both ERC7739 and AccountERC7579 to support both schemes.