Account.sol 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. // SPDX-License-Identifier: MIT
  2. // OpenZeppelin Contracts (last updated v5.4.0) (account/Account.sol)
  3. pragma solidity ^0.8.20;
  4. import {PackedUserOperation, IAccount, IEntryPoint} from "../interfaces/draft-IERC4337.sol";
  5. import {ERC4337Utils} from "./utils/draft-ERC4337Utils.sol";
  6. import {AbstractSigner} from "../utils/cryptography/signers/AbstractSigner.sol";
  7. /**
  8. * @dev A simple ERC4337 account implementation. This base implementation only includes the minimal logic to process
  9. * user operations.
  10. *
  11. * Developers must implement the {AbstractSigner-_rawSignatureValidation} function to define the account's validation logic.
  12. *
  13. * NOTE: This core account doesn't include any mechanism for performing arbitrary external calls. This is an essential
  14. * feature that all Account should have. We leave it up to the developers to implement the mechanism of their choice.
  15. * Common choices include ERC-6900, ERC-7579 and ERC-7821 (among others).
  16. *
  17. * IMPORTANT: Implementing a mechanism to validate signatures is a security-sensitive operation as it may allow an
  18. * attacker to bypass the account's security measures. Check out {SignerECDSA}, {SignerP256}, or {SignerRSA} for
  19. * digital signature validation implementations.
  20. *
  21. * @custom:stateless
  22. */
  23. abstract contract Account is AbstractSigner, IAccount {
  24. /**
  25. * @dev Unauthorized call to the account.
  26. */
  27. error AccountUnauthorized(address sender);
  28. /**
  29. * @dev Revert if the caller is not the entry point or the account itself.
  30. */
  31. modifier onlyEntryPointOrSelf() {
  32. _checkEntryPointOrSelf();
  33. _;
  34. }
  35. /**
  36. * @dev Revert if the caller is not the entry point.
  37. */
  38. modifier onlyEntryPoint() {
  39. _checkEntryPoint();
  40. _;
  41. }
  42. /**
  43. * @dev Canonical entry point for the account that forwards and validates user operations.
  44. */
  45. function entryPoint() public view virtual returns (IEntryPoint) {
  46. return ERC4337Utils.ENTRYPOINT_V08;
  47. }
  48. /**
  49. * @dev Return the account nonce for the canonical sequence.
  50. */
  51. function getNonce() public view virtual returns (uint256) {
  52. return getNonce(0);
  53. }
  54. /**
  55. * @dev Return the account nonce for a given sequence (key).
  56. */
  57. function getNonce(uint192 key) public view virtual returns (uint256) {
  58. return entryPoint().getNonce(address(this), key);
  59. }
  60. /**
  61. * @inheritdoc IAccount
  62. */
  63. function validateUserOp(
  64. PackedUserOperation calldata userOp,
  65. bytes32 userOpHash,
  66. uint256 missingAccountFunds
  67. ) public virtual onlyEntryPoint returns (uint256) {
  68. uint256 validationData = _validateUserOp(userOp, userOpHash);
  69. _payPrefund(missingAccountFunds);
  70. return validationData;
  71. }
  72. /**
  73. * @dev Returns the validationData for a given user operation. By default, this checks the signature of the
  74. * signable hash (produced by {_signableUserOpHash}) using the abstract signer ({AbstractSigner-_rawSignatureValidation}).
  75. *
  76. * NOTE: The userOpHash is assumed to be correct. Calling this function with a userOpHash that does not match the
  77. * userOp will result in undefined behavior.
  78. */
  79. function _validateUserOp(
  80. PackedUserOperation calldata userOp,
  81. bytes32 userOpHash
  82. ) internal virtual returns (uint256) {
  83. return
  84. _rawSignatureValidation(_signableUserOpHash(userOp, userOpHash), userOp.signature)
  85. ? ERC4337Utils.SIG_VALIDATION_SUCCESS
  86. : ERC4337Utils.SIG_VALIDATION_FAILED;
  87. }
  88. /**
  89. * @dev Virtual function that returns the signable hash for a user operations. Since v0.8.0 of the entrypoint,
  90. * `userOpHash` is an EIP-712 hash that can be signed directly.
  91. */
  92. function _signableUserOpHash(
  93. PackedUserOperation calldata /*userOp*/,
  94. bytes32 userOpHash
  95. ) internal view virtual returns (bytes32) {
  96. return userOpHash;
  97. }
  98. /**
  99. * @dev Sends the missing funds for executing the user operation to the {entrypoint}.
  100. * The `missingAccountFunds` must be defined by the entrypoint when calling {validateUserOp}.
  101. */
  102. function _payPrefund(uint256 missingAccountFunds) internal virtual {
  103. if (missingAccountFunds > 0) {
  104. (bool success, ) = payable(msg.sender).call{value: missingAccountFunds}("");
  105. success; // Silence warning. The entrypoint should validate the result.
  106. }
  107. }
  108. /**
  109. * @dev Ensures the caller is the {entrypoint}.
  110. */
  111. function _checkEntryPoint() internal view virtual {
  112. address sender = msg.sender;
  113. if (sender != address(entryPoint())) {
  114. revert AccountUnauthorized(sender);
  115. }
  116. }
  117. /**
  118. * @dev Ensures the caller is the {entrypoint} or the account itself.
  119. */
  120. function _checkEntryPointOrSelf() internal view virtual {
  121. address sender = msg.sender;
  122. if (sender != address(this) && sender != address(entryPoint())) {
  123. revert AccountUnauthorized(sender);
  124. }
  125. }
  126. /**
  127. * @dev Receive Ether.
  128. */
  129. receive() external payable virtual {}
  130. }