draft-ERC4337Utils.sol 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. // SPDX-License-Identifier: MIT
  2. // OpenZeppelin Contracts (last updated v5.2.0) (account/utils/draft-ERC4337Utils.sol)
  3. pragma solidity ^0.8.20;
  4. import {IEntryPoint, PackedUserOperation} from "../../interfaces/draft-IERC4337.sol";
  5. import {Math} from "../../utils/math/Math.sol";
  6. import {Calldata} from "../../utils/Calldata.sol";
  7. import {Packing} from "../../utils/Packing.sol";
  8. /**
  9. * @dev Library with common ERC-4337 utility functions.
  10. *
  11. * See https://eips.ethereum.org/EIPS/eip-4337[ERC-4337].
  12. */
  13. library ERC4337Utils {
  14. using Packing for *;
  15. /// @dev Address of the entrypoint v0.7.0
  16. IEntryPoint internal constant ENTRYPOINT = IEntryPoint(0x0000000071727De22E5E9d8BAf0edAc6f37da032);
  17. /// @dev For simulation purposes, validateUserOp (and validatePaymasterUserOp) return this value on success.
  18. uint256 internal constant SIG_VALIDATION_SUCCESS = 0;
  19. /// @dev For simulation purposes, validateUserOp (and validatePaymasterUserOp) must return this value in case of signature failure, instead of revert.
  20. uint256 internal constant SIG_VALIDATION_FAILED = 1;
  21. /// @dev Parses the validation data into its components. See {packValidationData}.
  22. function parseValidationData(
  23. uint256 validationData
  24. ) internal pure returns (address aggregator, uint48 validAfter, uint48 validUntil) {
  25. validAfter = uint48(bytes32(validationData).extract_32_6(0));
  26. validUntil = uint48(bytes32(validationData).extract_32_6(6));
  27. aggregator = address(bytes32(validationData).extract_32_20(12));
  28. if (validUntil == 0) validUntil = type(uint48).max;
  29. }
  30. /// @dev Packs the validation data into a single uint256. See {parseValidationData}.
  31. function packValidationData(
  32. address aggregator,
  33. uint48 validAfter,
  34. uint48 validUntil
  35. ) internal pure returns (uint256) {
  36. return uint256(bytes6(validAfter).pack_6_6(bytes6(validUntil)).pack_12_20(bytes20(aggregator)));
  37. }
  38. /// @dev Same as {packValidationData}, but with a boolean signature success flag.
  39. function packValidationData(bool sigSuccess, uint48 validAfter, uint48 validUntil) internal pure returns (uint256) {
  40. return
  41. packValidationData(
  42. address(uint160(Math.ternary(sigSuccess, SIG_VALIDATION_SUCCESS, SIG_VALIDATION_FAILED))),
  43. validAfter,
  44. validUntil
  45. );
  46. }
  47. /**
  48. * @dev Combines two validation data into a single one.
  49. *
  50. * The `aggregator` is set to {SIG_VALIDATION_SUCCESS} if both are successful, while
  51. * the `validAfter` is the maximum and the `validUntil` is the minimum of both.
  52. */
  53. function combineValidationData(uint256 validationData1, uint256 validationData2) internal pure returns (uint256) {
  54. (address aggregator1, uint48 validAfter1, uint48 validUntil1) = parseValidationData(validationData1);
  55. (address aggregator2, uint48 validAfter2, uint48 validUntil2) = parseValidationData(validationData2);
  56. bool success = aggregator1 == address(uint160(SIG_VALIDATION_SUCCESS)) &&
  57. aggregator2 == address(uint160(SIG_VALIDATION_SUCCESS));
  58. uint48 validAfter = uint48(Math.max(validAfter1, validAfter2));
  59. uint48 validUntil = uint48(Math.min(validUntil1, validUntil2));
  60. return packValidationData(success, validAfter, validUntil);
  61. }
  62. /// @dev Returns the aggregator of the `validationData` and whether it is out of time range.
  63. function getValidationData(uint256 validationData) internal view returns (address aggregator, bool outOfTimeRange) {
  64. (address aggregator_, uint48 validAfter, uint48 validUntil) = parseValidationData(validationData);
  65. return (aggregator_, block.timestamp < validAfter || validUntil < block.timestamp);
  66. }
  67. /// @dev Computes the hash of a user operation for a given entrypoint and chainid.
  68. function hash(
  69. PackedUserOperation calldata self,
  70. address entrypoint,
  71. uint256 chainid
  72. ) internal pure returns (bytes32) {
  73. bytes32 result = keccak256(
  74. abi.encode(
  75. keccak256(
  76. abi.encode(
  77. self.sender,
  78. self.nonce,
  79. keccak256(self.initCode),
  80. keccak256(self.callData),
  81. self.accountGasLimits,
  82. self.preVerificationGas,
  83. self.gasFees,
  84. keccak256(self.paymasterAndData)
  85. )
  86. ),
  87. entrypoint,
  88. chainid
  89. )
  90. );
  91. return result;
  92. }
  93. /// @dev Returns `factory` from the {PackedUserOperation}, or address(0) if the initCode is empty or not properly formatted.
  94. function factory(PackedUserOperation calldata self) internal pure returns (address) {
  95. return self.initCode.length < 20 ? address(0) : address(bytes20(self.initCode[0:20]));
  96. }
  97. /// @dev Returns `factoryData` from the {PackedUserOperation}, or empty bytes if the initCode is empty or not properly formatted.
  98. function factoryData(PackedUserOperation calldata self) internal pure returns (bytes calldata) {
  99. return self.initCode.length < 20 ? Calldata.emptyBytes() : self.initCode[20:];
  100. }
  101. /// @dev Returns `verificationGasLimit` from the {PackedUserOperation}.
  102. function verificationGasLimit(PackedUserOperation calldata self) internal pure returns (uint256) {
  103. return uint128(self.accountGasLimits.extract_32_16(0));
  104. }
  105. /// @dev Returns `callGasLimit` from the {PackedUserOperation}.
  106. function callGasLimit(PackedUserOperation calldata self) internal pure returns (uint256) {
  107. return uint128(self.accountGasLimits.extract_32_16(16));
  108. }
  109. /// @dev Returns the first section of `gasFees` from the {PackedUserOperation}.
  110. function maxPriorityFeePerGas(PackedUserOperation calldata self) internal pure returns (uint256) {
  111. return uint128(self.gasFees.extract_32_16(0));
  112. }
  113. /// @dev Returns the second section of `gasFees` from the {PackedUserOperation}.
  114. function maxFeePerGas(PackedUserOperation calldata self) internal pure returns (uint256) {
  115. return uint128(self.gasFees.extract_32_16(16));
  116. }
  117. /// @dev Returns the total gas price for the {PackedUserOperation} (ie. `maxFeePerGas` or `maxPriorityFeePerGas + basefee`).
  118. function gasPrice(PackedUserOperation calldata self) internal view returns (uint256) {
  119. unchecked {
  120. // Following values are "per gas"
  121. uint256 maxPriorityFee = maxPriorityFeePerGas(self);
  122. uint256 maxFee = maxFeePerGas(self);
  123. return Math.min(maxFee, maxPriorityFee + block.basefee);
  124. }
  125. }
  126. /// @dev Returns the first section of `paymasterAndData` from the {PackedUserOperation}.
  127. function paymaster(PackedUserOperation calldata self) internal pure returns (address) {
  128. return self.paymasterAndData.length < 52 ? address(0) : address(bytes20(self.paymasterAndData[0:20]));
  129. }
  130. /// @dev Returns the second section of `paymasterAndData` from the {PackedUserOperation}.
  131. function paymasterVerificationGasLimit(PackedUserOperation calldata self) internal pure returns (uint256) {
  132. return self.paymasterAndData.length < 52 ? 0 : uint128(bytes16(self.paymasterAndData[20:36]));
  133. }
  134. /// @dev Returns the third section of `paymasterAndData` from the {PackedUserOperation}.
  135. function paymasterPostOpGasLimit(PackedUserOperation calldata self) internal pure returns (uint256) {
  136. return self.paymasterAndData.length < 52 ? 0 : uint128(bytes16(self.paymasterAndData[36:52]));
  137. }
  138. /// @dev Returns the fourth section of `paymasterAndData` from the {PackedUserOperation}.
  139. function paymasterData(PackedUserOperation calldata self) internal pure returns (bytes calldata) {
  140. return self.paymasterAndData.length < 52 ? Calldata.emptyBytes() : self.paymasterAndData[52:];
  141. }
  142. /// @dev Deposit ether into the entrypoint.
  143. function depositTo(address to, uint256 value) internal {
  144. ENTRYPOINT.depositTo{value: value}(to);
  145. }
  146. /// @dev Withdraw ether from the entrypoint.
  147. function withdrawTo(address payable to, uint256 value) internal {
  148. ENTRYPOINT.withdrawTo(to, value);
  149. }
  150. /// @dev Add stake to the entrypoint.
  151. function addStake(uint256 value, uint32 unstakeDelaySec) internal {
  152. ENTRYPOINT.addStake{value: value}(unstakeDelaySec);
  153. }
  154. /// @dev Unlock stake on the entrypoint.
  155. function unlockStake() internal {
  156. ENTRYPOINT.unlockStake();
  157. }
  158. /// @dev Withdraw unlocked stake from the entrypoint.
  159. function withdrawStake(address payable to) internal {
  160. ENTRYPOINT.withdrawStake(to);
  161. }
  162. }