draft-ERC4337Utils.sol 7.9 KB

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