draft-AccountECDSA.sol 3.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. // SPDX-License-Identifier: MIT
  2. pragma solidity ^0.8.20;
  3. import {IERC5267} from "../interfaces/IERC5267.sol";
  4. import {PackedUserOperation} from "../interfaces/draft-IERC4337.sol";
  5. import {ERC4337Utils} from "../account/utils/draft-ERC4337Utils.sol";
  6. import {ERC721Holder} from "../token/ERC721/utils/ERC721Holder.sol";
  7. import {ERC1155Holder} from "../token/ERC1155/utils/ERC1155Holder.sol";
  8. import {ERC165} from "../utils/introspection/ERC165.sol";
  9. import {ECDSA} from "../utils/cryptography/ECDSA.sol";
  10. import {ERC7739Signer} from "../utils/cryptography/draft-ERC7739Signer.sol";
  11. import {MessageHashUtils} from "../utils/cryptography/MessageHashUtils.sol";
  12. import {AccountBase} from "./draft-AccountBase.sol";
  13. /**
  14. * @dev Account implementation using {ECDSA} signatures and {ERC7739Signer} for replay protection.
  15. *
  16. * An {_initializeSigner} function is provided to set the account's signer address. Doing so it's
  17. * easier for a factory, whose likely to use initializable clones of this contract.
  18. *
  19. * IMPORTANT: Avoiding to call {_initializeSigner} either during construction (if used standalone)
  20. * or during initialization (if used as a clone) may leave the account unusable.
  21. */
  22. abstract contract AccountECDSA is ERC165, IERC5267, AccountBase, ERC7739Signer, ERC721Holder, ERC1155Holder {
  23. using MessageHashUtils for bytes32;
  24. /**
  25. * @dev The {signer} is already initialized.
  26. */
  27. error AccountECDSAUninitializedSigner(address signer);
  28. address private _signer;
  29. /**
  30. * @dev Initializes the account with the address of the native signer. This function is called only once.
  31. */
  32. function _initializeSigner(address signerAddr) internal {
  33. if (_signer != address(0)) revert AccountECDSAUninitializedSigner(signerAddr);
  34. _signer = signerAddr;
  35. }
  36. /**
  37. * @dev Return the account's signer address.
  38. */
  39. function signer() public view virtual returns (address) {
  40. return _signer;
  41. }
  42. /**
  43. * @dev Returns the ERC-191 signed `userOpHash` hashed with keccak256 using `personal_sign`.
  44. */
  45. function _userOpSignedHash(
  46. PackedUserOperation calldata /* userOp */,
  47. bytes32 userOpHash
  48. ) internal view virtual override returns (bytes32) {
  49. return userOpHash.toEthSignedMessageHash();
  50. }
  51. /**
  52. * @dev Internal version of {validateUserOp} that relies on {_validateSignature}.
  53. *
  54. * The `userOpSignedHash` is the digest from {_userOpSignedHash}.
  55. *
  56. * NOTE: To override the signature functionality, try overriding {_validateSignature} instead.
  57. */
  58. function _validateUserOp(
  59. PackedUserOperation calldata userOp,
  60. bytes32 userOpSignedHash
  61. ) internal view virtual override returns (uint256) {
  62. return
  63. _isValidSignature(userOpSignedHash, userOp.signature)
  64. ? ERC4337Utils.SIG_VALIDATION_SUCCESS
  65. : ERC4337Utils.SIG_VALIDATION_FAILED;
  66. }
  67. /**
  68. * @dev Validates the signature using the account's signer.
  69. *
  70. * This function provides a nested EIP-712 hash. Developers must override only this
  71. * function to ensure no raw message signing is possible.
  72. */
  73. function _validateSignature(
  74. bytes32 nestedEIP712Hash,
  75. bytes calldata signature
  76. ) internal view virtual override returns (bool) {
  77. (address recovered, ECDSA.RecoverError err, ) = ECDSA.tryRecover(nestedEIP712Hash, signature);
  78. return signer() == recovered && err == ECDSA.RecoverError.NoError;
  79. }
  80. /// @inheritdoc ERC165
  81. function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, ERC1155Holder) returns (bool) {
  82. return super.supportsInterface(interfaceId);
  83. }
  84. }