|
| 1 | +// SPDX-License-Identifier: MIT |
| 2 | +pragma solidity ^0.8.27; |
| 3 | + |
| 4 | +import {IModule} from '../../../src/interfaces/IERC7579Module.sol'; |
| 5 | +import {IModuleManager} from '../../../src/interfaces/core/IModuleManager.sol'; |
| 6 | +import { |
| 7 | + ERC1271_INVALID, |
| 8 | + ERC1271_MAGICVALUE, |
| 9 | + MODULE_TYPE_VALIDATOR, |
| 10 | + VALIDATION_FAILED, |
| 11 | + VALIDATION_SUCCESS |
| 12 | +} from '../../../src/types/Constants.sol'; |
| 13 | + |
| 14 | +import {MessageHashUtils} from '@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol'; |
| 15 | +import {PackedUserOperation} from 'account-abstraction/interfaces/PackedUserOperation.sol'; |
| 16 | +import {ERC7739Validator} from 'erc7739Validator/ERC7739Validator.sol'; |
| 17 | +import {ECDSA} from 'solady/utils/ECDSA.sol'; |
| 18 | + |
| 19 | +contract MockValidator is ERC7739Validator { |
| 20 | + error ValidatorStillInstalled(); |
| 21 | + |
| 22 | + using ECDSA for bytes32; |
| 23 | + |
| 24 | + mapping(address => address) public smartAccountOwners; |
| 25 | + |
| 26 | + function validateUserOp( |
| 27 | + PackedUserOperation calldata userOp, |
| 28 | + bytes32 userOpHash |
| 29 | + ) external view returns (uint256 validation) { |
| 30 | + address owner = getOwner(msg.sender); |
| 31 | + return _validateSignatureForOwner(owner, userOpHash, userOp.signature) ? VALIDATION_SUCCESS : VALIDATION_FAILED; |
| 32 | + } |
| 33 | + |
| 34 | + function isValidSignatureWithSender( |
| 35 | + address sender, |
| 36 | + bytes32 hash, |
| 37 | + bytes calldata signature |
| 38 | + ) external view virtual returns (bytes4 sigValidationResult) { |
| 39 | + // can put additional checks based on sender here |
| 40 | + return _erc1271IsValidSignatureWithSender(sender, hash, _erc1271UnwrapSignature(signature)); |
| 41 | + } |
| 42 | + |
| 43 | + // ISessionValidator interface for smart session |
| 44 | + function validateSignatureWithData( |
| 45 | + bytes32 hash, |
| 46 | + bytes calldata sig, |
| 47 | + bytes calldata data |
| 48 | + ) external view returns (bool validSig) { |
| 49 | + address owner = address(bytes20(data[0:20])); |
| 50 | + return _validateSignatureForOwner(owner, hash, sig); |
| 51 | + } |
| 52 | + |
| 53 | + function _validateSignatureForOwner( |
| 54 | + address owner, |
| 55 | + bytes32 hash, |
| 56 | + bytes calldata signature |
| 57 | + ) internal view returns (bool) { |
| 58 | + if (_recoverSigner(hash, signature) == owner) return true; |
| 59 | + if (_recoverSigner(hash.toEthSignedMessageHash(), signature) == owner) return true; |
| 60 | + return false; |
| 61 | + } |
| 62 | + |
| 63 | + function _recoverSigner(bytes32 hash, bytes calldata signature) internal view returns (address) { |
| 64 | + return hash.tryRecoverCalldata(signature); |
| 65 | + } |
| 66 | + |
| 67 | + /// @dev Returns whether the `hash` and `signature` are valid. |
| 68 | + /// Obtains the authorized signer's credentials and calls some |
| 69 | + /// module's specific internal function to validate the signature |
| 70 | + /// against credentials. |
| 71 | + function _erc1271IsValidSignatureNowCalldata( |
| 72 | + bytes32 hash, |
| 73 | + bytes calldata signature |
| 74 | + ) internal view override returns (bool) { |
| 75 | + // call custom internal function to validate the signature against credentials |
| 76 | + return _validateSignatureForOwner(getOwner(msg.sender), hash, signature); |
| 77 | + } |
| 78 | + |
| 79 | + /// @dev Returns whether the `sender` is considered safe, such |
| 80 | + /// that we don't need to use the nested EIP-712 workflow. |
| 81 | + /// See: https://mirror.xyz/curiousapple.eth/pFqAdW2LiJ-6S4sg_u1z08k4vK6BCJ33LcyXpnNb8yU |
| 82 | + // The canonical `MulticallerWithSigner` at 0x000000000000D9ECebf3C23529de49815Dac1c4c |
| 83 | + // is known to include the account in the hash to be signed. |
| 84 | + // msg.sender = Smart Account |
| 85 | + // sender = 1271 og request sender |
| 86 | + function _erc1271CallerIsSafe(address sender) internal view virtual override returns (bool) { |
| 87 | + return ( |
| 88 | + sender == 0x000000000000D9ECebf3C23529de49815Dac1c4c // MulticallerWithSigner |
| 89 | + || sender == msg.sender |
| 90 | + ); |
| 91 | + } |
| 92 | + |
| 93 | + /** |
| 94 | + * Get the owner of the smart account |
| 95 | + * @param smartAccount The address of the smart account |
| 96 | + * @return The owner of the smart account |
| 97 | + */ |
| 98 | + function getOwner(address smartAccount) public view returns (address) { |
| 99 | + address owner = smartAccountOwners[smartAccount]; |
| 100 | + return owner == address(0) ? smartAccount : owner; |
| 101 | + } |
| 102 | + |
| 103 | + function onInstall(bytes calldata data) external { |
| 104 | + smartAccountOwners[msg.sender] = address(bytes20(data)); |
| 105 | + } |
| 106 | + |
| 107 | + function onUninstall(bytes calldata data) external { |
| 108 | + if (IModuleManager(msg.sender).isModuleInstalled(MODULE_TYPE_VALIDATOR, address(this), '')) { |
| 109 | + revert ValidatorStillInstalled(); |
| 110 | + } |
| 111 | + data; |
| 112 | + delete smartAccountOwners[msg.sender]; |
| 113 | + } |
| 114 | + |
| 115 | + function isModuleType(uint256 moduleTypeId) external pure returns (bool) { |
| 116 | + return moduleTypeId == MODULE_TYPE_VALIDATOR; |
| 117 | + } |
| 118 | + |
| 119 | + function isOwner(address account, address owner) external view returns (bool) { |
| 120 | + return smartAccountOwners[account] == owner; |
| 121 | + } |
| 122 | + |
| 123 | + function isInitialized(address) external view returns (bool) { |
| 124 | + return smartAccountOwners[msg.sender] != address(0); |
| 125 | + } |
| 126 | +} |
0 commit comments