draft-ERC7579Utils.sol 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. // SPDX-License-Identifier: MIT
  2. pragma solidity ^0.8.20;
  3. import {Execution} from "../../interfaces/draft-IERC7579.sol";
  4. import {Packing} from "../../utils/Packing.sol";
  5. import {Address} from "../../utils/Address.sol";
  6. type Mode is bytes32;
  7. type CallType is bytes1;
  8. type ExecType is bytes1;
  9. type ModeSelector is bytes4;
  10. type ModePayload is bytes22;
  11. /**
  12. * @dev Library with common ERC-7579 utility functions.
  13. *
  14. * See https://eips.ethereum.org/EIPS/eip-7579[ERC-7579].
  15. */
  16. // slither-disable-next-line unused-state
  17. library ERC7579Utils {
  18. using Packing for *;
  19. /// @dev A single `call` execution.
  20. CallType constant CALLTYPE_SINGLE = CallType.wrap(0x00);
  21. /// @dev A batch of `call` executions.
  22. CallType constant CALLTYPE_BATCH = CallType.wrap(0x01);
  23. /// @dev A `delegatecall` execution.
  24. CallType constant CALLTYPE_DELEGATECALL = CallType.wrap(0xFF);
  25. /// @dev Default execution type that reverts on failure.
  26. ExecType constant EXECTYPE_DEFAULT = ExecType.wrap(0x00);
  27. /// @dev Execution type that does not revert on failure.
  28. ExecType constant EXECTYPE_TRY = ExecType.wrap(0x01);
  29. /// @dev Emits when an {EXECTYPE_TRY} execution fails.
  30. event ERC7579TryExecuteFail(uint256 batchExecutionIndex, bytes result);
  31. /// @dev The provided {CallType} is not supported.
  32. error ERC7579UnsupportedCallType(CallType callType);
  33. /// @dev The provided {ExecType} is not supported.
  34. error ERC7579UnsupportedExecType(ExecType execType);
  35. /// @dev The provided module doesn't match the provided module type.
  36. error ERC7579MismatchedModuleTypeId(uint256 moduleTypeId, address module);
  37. /// @dev The module is not installed.
  38. error ERC7579UninstalledModule(uint256 moduleTypeId, address module);
  39. /// @dev The module is already installed.
  40. error ERC7579AlreadyInstalledModule(uint256 moduleTypeId, address module);
  41. /// @dev The module type is not supported.
  42. error ERC7579UnsupportedModuleType(uint256 moduleTypeId);
  43. /// @dev Executes a single call.
  44. function execSingle(
  45. ExecType execType,
  46. bytes calldata executionCalldata
  47. ) internal returns (bytes[] memory returnData) {
  48. (address target, uint256 value, bytes calldata callData) = decodeSingle(executionCalldata);
  49. returnData = new bytes[](1);
  50. returnData[0] = _call(0, execType, target, value, callData);
  51. }
  52. /// @dev Executes a batch of calls.
  53. function execBatch(
  54. ExecType execType,
  55. bytes calldata executionCalldata
  56. ) internal returns (bytes[] memory returnData) {
  57. Execution[] calldata executionBatch = decodeBatch(executionCalldata);
  58. returnData = new bytes[](executionBatch.length);
  59. for (uint256 i = 0; i < executionBatch.length; ++i) {
  60. returnData[i] = _call(
  61. i,
  62. execType,
  63. executionBatch[i].target,
  64. executionBatch[i].value,
  65. executionBatch[i].callData
  66. );
  67. }
  68. }
  69. /// @dev Executes a delegate call.
  70. function execDelegateCall(
  71. ExecType execType,
  72. bytes calldata executionCalldata
  73. ) internal returns (bytes[] memory returnData) {
  74. (address target, bytes calldata callData) = decodeDelegate(executionCalldata);
  75. returnData = new bytes[](1);
  76. returnData[0] = _delegatecall(0, execType, target, callData);
  77. }
  78. /// @dev Encodes the mode with the provided parameters. See {decodeMode}.
  79. function encodeMode(
  80. CallType callType,
  81. ExecType execType,
  82. ModeSelector selector,
  83. ModePayload payload
  84. ) internal pure returns (Mode mode) {
  85. return
  86. Mode.wrap(
  87. CallType
  88. .unwrap(callType)
  89. .pack_1_1(ExecType.unwrap(execType))
  90. .pack_2_4(bytes4(0))
  91. .pack_6_4(ModeSelector.unwrap(selector))
  92. .pack_10_22(ModePayload.unwrap(payload))
  93. );
  94. }
  95. /// @dev Decodes the mode into its parameters. See {encodeMode}.
  96. function decodeMode(
  97. Mode mode
  98. ) internal pure returns (CallType callType, ExecType execType, ModeSelector selector, ModePayload payload) {
  99. return (
  100. CallType.wrap(Packing.extract_32_1(Mode.unwrap(mode), 0)),
  101. ExecType.wrap(Packing.extract_32_1(Mode.unwrap(mode), 1)),
  102. ModeSelector.wrap(Packing.extract_32_4(Mode.unwrap(mode), 6)),
  103. ModePayload.wrap(Packing.extract_32_22(Mode.unwrap(mode), 10))
  104. );
  105. }
  106. /// @dev Encodes a single call execution. See {decodeSingle}.
  107. function encodeSingle(
  108. address target,
  109. uint256 value,
  110. bytes calldata callData
  111. ) internal pure returns (bytes memory executionCalldata) {
  112. return abi.encodePacked(target, value, callData);
  113. }
  114. /// @dev Decodes a single call execution. See {encodeSingle}.
  115. function decodeSingle(
  116. bytes calldata executionCalldata
  117. ) internal pure returns (address target, uint256 value, bytes calldata callData) {
  118. target = address(bytes20(executionCalldata[0:20]));
  119. value = uint256(bytes32(executionCalldata[20:52]));
  120. callData = executionCalldata[52:];
  121. }
  122. /// @dev Encodes a delegate call execution. See {decodeDelegate}.
  123. function encodeDelegate(
  124. address target,
  125. bytes calldata callData
  126. ) internal pure returns (bytes memory executionCalldata) {
  127. return abi.encodePacked(target, callData);
  128. }
  129. /// @dev Decodes a delegate call execution. See {encodeDelegate}.
  130. function decodeDelegate(
  131. bytes calldata executionCalldata
  132. ) internal pure returns (address target, bytes calldata callData) {
  133. target = address(bytes20(executionCalldata[0:20]));
  134. callData = executionCalldata[20:];
  135. }
  136. /// @dev Encodes a batch of executions. See {decodeBatch}.
  137. function encodeBatch(Execution[] memory executionBatch) internal pure returns (bytes memory executionCalldata) {
  138. return abi.encode(executionBatch);
  139. }
  140. /// @dev Decodes a batch of executions. See {encodeBatch}.
  141. function decodeBatch(bytes calldata executionCalldata) internal pure returns (Execution[] calldata executionBatch) {
  142. assembly ("memory-safe") {
  143. let ptr := add(executionCalldata.offset, calldataload(executionCalldata.offset))
  144. // Extract the ERC7579 Executions
  145. executionBatch.offset := add(ptr, 32)
  146. executionBatch.length := calldataload(ptr)
  147. }
  148. }
  149. /// @dev Executes a `call` to the target with the provided {ExecType}.
  150. function _call(
  151. uint256 index,
  152. ExecType execType,
  153. address target,
  154. uint256 value,
  155. bytes calldata data
  156. ) private returns (bytes memory) {
  157. (bool success, bytes memory returndata) = target.call{value: value}(data);
  158. return _validateExecutionMode(index, execType, success, returndata);
  159. }
  160. /// @dev Executes a `delegatecall` to the target with the provided {ExecType}.
  161. function _delegatecall(
  162. uint256 index,
  163. ExecType execType,
  164. address target,
  165. bytes calldata data
  166. ) private returns (bytes memory) {
  167. (bool success, bytes memory returndata) = target.delegatecall(data);
  168. return _validateExecutionMode(index, execType, success, returndata);
  169. }
  170. /// @dev Validates the execution mode and returns the returndata.
  171. function _validateExecutionMode(
  172. uint256 index,
  173. ExecType execType,
  174. bool success,
  175. bytes memory returndata
  176. ) private returns (bytes memory) {
  177. if (execType == ERC7579Utils.EXECTYPE_DEFAULT) {
  178. Address.verifyCallResult(success, returndata);
  179. } else if (execType == ERC7579Utils.EXECTYPE_TRY) {
  180. if (!success) emit ERC7579TryExecuteFail(index, returndata);
  181. } else {
  182. revert ERC7579UnsupportedExecType(execType);
  183. }
  184. return returndata;
  185. }
  186. }
  187. // Operators
  188. using {eqCallType as ==} for CallType global;
  189. using {eqExecType as ==} for ExecType global;
  190. using {eqModeSelector as ==} for ModeSelector global;
  191. using {eqModePayload as ==} for ModePayload global;
  192. /// @dev Compares two `CallType` values for equality.
  193. function eqCallType(CallType a, CallType b) pure returns (bool) {
  194. return CallType.unwrap(a) == CallType.unwrap(b);
  195. }
  196. /// @dev Compares two `ExecType` values for equality.
  197. function eqExecType(ExecType a, ExecType b) pure returns (bool) {
  198. return ExecType.unwrap(a) == ExecType.unwrap(b);
  199. }
  200. /// @dev Compares two `ModeSelector` values for equality.
  201. function eqModeSelector(ModeSelector a, ModeSelector b) pure returns (bool) {
  202. return ModeSelector.unwrap(a) == ModeSelector.unwrap(b);
  203. }
  204. /// @dev Compares two `ModePayload` values for equality.
  205. function eqModePayload(ModePayload a, ModePayload b) pure returns (bool) {
  206. return ModePayload.unwrap(a) == ModePayload.unwrap(b);
  207. }