From c8f1ff5b61bed879c26dd2d5824c8019f98bd55a Mon Sep 17 00:00:00 2001 From: zer0dot Date: Fri, 11 Oct 2024 15:28:01 -0400 Subject: [PATCH] feat: refactor execution install functions into external lib --- src/account/ModularAccountBase.sol | 6 +- src/account/ModuleManagerInternals.sol | 194 +---------------- src/account/SemiModularAccountBase.sol | 13 +- src/libraries/ExecutionInstallLib.sol | 197 ++++++++++++++++++ src/libraries/KnownSelectorsLib.sol | 30 --- .../SemiModularKnownSelectorsLib.sol | 16 -- test/libraries/KnowSelectors.t.sol | 35 ---- test/libraries/KnowSelectorsLib.t.sol | 40 ++++ 8 files changed, 255 insertions(+), 276 deletions(-) create mode 100644 src/libraries/ExecutionInstallLib.sol delete mode 100644 src/libraries/SemiModularKnownSelectorsLib.sol delete mode 100644 test/libraries/KnowSelectors.t.sol create mode 100644 test/libraries/KnowSelectorsLib.t.sol diff --git a/src/account/ModularAccountBase.sol b/src/account/ModularAccountBase.sol index eaf76384a..97730293e 100644 --- a/src/account/ModularAccountBase.sol +++ b/src/account/ModularAccountBase.sol @@ -38,6 +38,8 @@ import {ModularAccountView} from "./ModularAccountView.sol"; import {ModuleManagerInternals} from "./ModuleManagerInternals.sol"; import {TokenReceiver} from "./TokenReceiver.sol"; +import {ExecutionInstallLib} from "../libraries/ExecutionInstallLib.sol"; + abstract contract ModularAccountBase is IModularAccount, ModularAccountView, @@ -281,7 +283,7 @@ abstract contract ModularAccountBase is ExecutionManifest calldata manifest, bytes calldata moduleInstallData ) external override wrapNativeFunction { - _installExecution(module, manifest, moduleInstallData); + ExecutionInstallLib.installExecution(module, manifest, moduleInstallData); } /// @inheritdoc IModularAccount @@ -291,7 +293,7 @@ abstract contract ModularAccountBase is ExecutionManifest calldata manifest, bytes calldata moduleUninstallData ) external override wrapNativeFunction { - _uninstallExecution(module, manifest, moduleUninstallData); + ExecutionInstallLib.uninstallExecution(module, manifest, moduleUninstallData); } /// @inheritdoc IModularAccount diff --git a/src/account/ModuleManagerInternals.sol b/src/account/ModuleManagerInternals.sol index 61e9d48cd..40305811b 100644 --- a/src/account/ModuleManagerInternals.sol +++ b/src/account/ModuleManagerInternals.sol @@ -2,30 +2,23 @@ pragma solidity ^0.8.26; import {IExecutionHookModule} from "@erc6900/reference-implementation/interfaces/IExecutionHookModule.sol"; -import { - ExecutionManifest, - ManifestExecutionHook -} from "@erc6900/reference-implementation/interfaces/IExecutionModule.sol"; import { HookConfig, IModularAccount, ModuleEntity, ValidationConfig } from "@erc6900/reference-implementation/interfaces/IModularAccount.sol"; -import {IModule} from "@erc6900/reference-implementation/interfaces/IModule.sol"; import {IValidationHookModule} from "@erc6900/reference-implementation/interfaces/IValidationHookModule.sol"; import {IValidationModule} from "@erc6900/reference-implementation/interfaces/IValidationModule.sol"; import {HookConfigLib} from "@erc6900/reference-implementation/libraries/HookConfigLib.sol"; import {ModuleEntityLib} from "@erc6900/reference-implementation/libraries/ModuleEntityLib.sol"; import {ValidationConfigLib} from "@erc6900/reference-implementation/libraries/ValidationConfigLib.sol"; -import {ERC165Checker} from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol"; import {MAX_PRE_VALIDATION_HOOKS} from "../helpers/Constants.sol"; -import {ExecutionLib} from "../libraries/ExecutionLib.sol"; -import {KnownSelectorsLib} from "../libraries/KnownSelectorsLib.sol"; +import {ExecutionInstallLib} from "../libraries/ExecutionInstallLib.sol"; import {LinkedListSet, LinkedListSetLib} from "../libraries/LinkedListSetLib.sol"; import {MemManagementLib} from "../libraries/MemManagementLib.sol"; -import {AccountStorage, ExecutionData, ValidationData, getAccountStorage, toSetValue} from "./AccountStorage.sol"; +import {ValidationData, getAccountStorage, toSetValue} from "./AccountStorage.sol"; abstract contract ModuleManagerInternals is IModularAccount { using LinkedListSetLib for LinkedListSet; @@ -38,7 +31,6 @@ abstract contract ModuleManagerInternals is IModularAccount { error ExecutionFunctionAlreadySet(bytes4 selector); error IModuleFunctionNotAllowed(bytes4 selector); error InterfaceNotSupported(address module); - error NativeFunctionNotAllowed(bytes4 selector); error NullModule(); error ExecutionHookAlreadySet(HookConfig hookConfig); error ModuleInstallCallbackFailed(address module, bytes revertReason); @@ -49,51 +41,6 @@ abstract contract ModuleManagerInternals is IModularAccount { // Storage update operations - function _setExecutionFunction( - bytes4 selector, - bool skipRuntimeValidation, - bool allowGlobalValidation, - address module - ) internal { - ExecutionData storage _executionData = getAccountStorage().executionData[selector]; - - if (_executionData.module != address(0)) { - revert ExecutionFunctionAlreadySet(selector); - } - - // Make sure incoming execution function does not collide with any native functions (data are stored on the - // account implementation contract) - if (_isNativeFunction(selector)) { - revert NativeFunctionNotAllowed(selector); - } - - // Make sure incoming execution function is not a function in IModule - if (KnownSelectorsLib.isIModuleFunction(selector)) { - revert IModuleFunctionNotAllowed(selector); - } - - // Also make sure it doesn't collide with functions defined by ERC-4337 - // and called by the entry point. This prevents a malicious module from - // sneaking in a function with the same selector as e.g. - // `validatePaymasterUserOp` and turning the account into their own - // personal paymaster. - if (KnownSelectorsLib.isErc4337Function(selector)) { - revert Erc4337FunctionNotAllowed(selector); - } - - _executionData.module = module; - _executionData.skipRuntimeValidation = skipRuntimeValidation; - _executionData.allowGlobalValidation = allowGlobalValidation; - } - - function _removeExecutionFunction(bytes4 selector) internal { - ExecutionData storage _executionData = getAccountStorage().executionData[selector]; - - _executionData.module = address(0); - _executionData.skipRuntimeValidation = false; - _executionData.allowGlobalValidation = false; - } - function _removeValidationFunction(ModuleEntity validationFunction) internal { ValidationData storage _validationData = getAccountStorage().validationData[validationFunction]; @@ -102,123 +49,6 @@ abstract contract ModuleManagerInternals is IModularAccount { _validationData.isUserOpValidation = false; } - function _addExecHooks(LinkedListSet storage hooks, HookConfig hookConfig) internal { - if (!hooks.tryAdd(toSetValue(hookConfig))) { - revert ExecutionHookAlreadySet(hookConfig); - } - } - - function _removeExecHooks(LinkedListSet storage hooks, HookConfig hookConfig) internal { - // Todo: use predecessor - hooks.tryRemove(toSetValue(hookConfig)); - } - - function _installExecution( - address module, - ExecutionManifest calldata manifest, - bytes calldata moduleInstallData - ) internal { - AccountStorage storage _storage = getAccountStorage(); - - if (module == address(0)) { - revert NullModule(); - } - - // Update components according to the manifest. - uint256 length = manifest.executionFunctions.length; - for (uint256 i = 0; i < length; ++i) { - bytes4 selector = manifest.executionFunctions[i].executionSelector; - bool skipRuntimeValidation = manifest.executionFunctions[i].skipRuntimeValidation; - bool allowGlobalValidation = manifest.executionFunctions[i].allowGlobalValidation; - _setExecutionFunction(selector, skipRuntimeValidation, allowGlobalValidation, module); - } - - length = manifest.executionHooks.length; - for (uint256 i = 0; i < length; ++i) { - ManifestExecutionHook memory mh = manifest.executionHooks[i]; - ExecutionData storage executionData = _storage.executionData[mh.executionSelector]; - HookConfig hookConfig = HookConfigLib.packExecHook({ - _module: module, - _entityId: mh.entityId, - _hasPre: mh.isPreHook, - _hasPost: mh.isPostHook - }); - _addExecHooks(executionData.executionHooks, hookConfig); - } - - length = manifest.interfaceIds.length; - for (uint256 i = 0; i < length; ++i) { - _storage.supportedIfaces[manifest.interfaceIds[i]] += 1; - } - - _onInstall(module, moduleInstallData, type(IModule).interfaceId); - - emit ExecutionInstalled(module, manifest); - } - - function _uninstallExecution(address module, ExecutionManifest calldata manifest, bytes calldata uninstallData) - internal - { - AccountStorage storage _storage = getAccountStorage(); - - // Remove components according to the manifest, in reverse order (by component type) of their installation. - - uint256 length = manifest.executionHooks.length; - for (uint256 i = 0; i < length; ++i) { - ManifestExecutionHook memory mh = manifest.executionHooks[i]; - ExecutionData storage execData = _storage.executionData[mh.executionSelector]; - HookConfig hookConfig = HookConfigLib.packExecHook({ - _module: module, - _entityId: mh.entityId, - _hasPre: mh.isPreHook, - _hasPost: mh.isPostHook - }); - _removeExecHooks(execData.executionHooks, hookConfig); - } - - length = manifest.executionFunctions.length; - for (uint256 i = 0; i < length; ++i) { - bytes4 selector = manifest.executionFunctions[i].executionSelector; - _removeExecutionFunction(selector); - } - - length = manifest.interfaceIds.length; - for (uint256 i = 0; i < length; ++i) { - _storage.supportedIfaces[manifest.interfaceIds[i]] -= 1; - } - - // Clear the module storage for the account. - bool onUninstallSuccess = _onUninstall(module, uninstallData); - - emit ExecutionUninstalled(module, onUninstallSuccess, manifest); - } - - function _onInstall(address module, bytes calldata data, bytes4 interfaceId) internal { - if (data.length > 0) { - if (!ERC165Checker.supportsERC165InterfaceUnchecked(module, interfaceId)) { - revert InterfaceNotSupported(module); - } - // solhint-disable-next-line no-empty-blocks - try IModule(module).onInstall(data) {} - catch { - bytes memory revertReason = ExecutionLib.collectReturnData(); - revert ModuleInstallCallbackFailed(module, revertReason); - } - } - } - - function _onUninstall(address module, bytes calldata data) internal returns (bool onUninstallSuccess) { - onUninstallSuccess = true; - if (data.length > 0) { - // Clear the module storage for the account. - // solhint-disable-next-line no-empty-blocks - try IModule(module).onUninstall(data) {} - catch { - onUninstallSuccess = false; - } - } - } - function _installValidation( ValidationConfig validationConfig, bytes4[] calldata selectors, @@ -244,15 +74,17 @@ abstract contract ModuleManagerInternals is IModularAccount { revert PreValidationHookDuplicate(); } - _onInstall(hookConfig.module(), hookData, type(IValidationHookModule).interfaceId); + ExecutionInstallLib.onInstall( + hookConfig.module(), hookData, type(IValidationHookModule).interfaceId + ); continue; } // Hook is an execution hook _validationData.executionHookCount += 1; - _addExecHooks(_validationData.executionHooks, hookConfig); + ExecutionInstallLib.addExecHooks(_validationData.executionHooks, hookConfig); - _onInstall(hookConfig.module(), hookData, type(IExecutionHookModule).interfaceId); + ExecutionInstallLib.onInstall(hookConfig.module(), hookData, type(IExecutionHookModule).interfaceId); } for (uint256 i = 0; i < selectors.length; ++i) { @@ -266,7 +98,7 @@ abstract contract ModuleManagerInternals is IModularAccount { _validationData.isSignatureValidation = validationConfig.isSignatureValidation(); _validationData.isUserOpValidation = validationConfig.isUserOpValidation(); - _onInstall(validationConfig.module(), installData, type(IValidationModule).interfaceId); + ExecutionInstallLib.onInstall(validationConfig.module(), installData, type(IValidationModule).interfaceId); emit ValidationInstalled(validationConfig.module(), validationConfig.entityId()); } @@ -295,14 +127,14 @@ abstract contract ModuleManagerInternals is IModularAccount { for (uint256 i = 0; i < validationHooks.length; ++i) { bytes calldata hookData = hookUninstallDatas[hookIndex]; (address hookModule,) = ModuleEntityLib.unpack(validationHooks[i].moduleEntity()); - onUninstallSuccess = onUninstallSuccess && _onUninstall(hookModule, hookData); + onUninstallSuccess = onUninstallSuccess && ExecutionInstallLib.onUninstall(hookModule, hookData); hookIndex++; } for (uint256 i = 0; i < execHooks.length; ++i) { bytes calldata hookData = hookUninstallDatas[hookIndex]; address hookModule = execHooks[i].module(); - onUninstallSuccess = onUninstallSuccess && _onUninstall(hookModule, hookData); + onUninstallSuccess = onUninstallSuccess && ExecutionInstallLib.onUninstall(hookModule, hookData); hookIndex++; } } @@ -318,12 +150,8 @@ abstract contract ModuleManagerInternals is IModularAccount { _validationData.selectors.clear(); (address module, uint32 entityId) = ModuleEntityLib.unpack(validationFunction); - onUninstallSuccess = onUninstallSuccess && _onUninstall(module, uninstallData); + onUninstallSuccess = onUninstallSuccess && ExecutionInstallLib.onUninstall(module, uninstallData); emit ValidationUninstalled(module, entityId, onUninstallSuccess); } - - function _isNativeFunction(bytes4 selector) internal pure virtual returns (bool) { - return KnownSelectorsLib.isNativeFunction(selector); - } } diff --git a/src/account/SemiModularAccountBase.sol b/src/account/SemiModularAccountBase.sol index ecf9fb05a..16026d534 100644 --- a/src/account/SemiModularAccountBase.sol +++ b/src/account/SemiModularAccountBase.sol @@ -1,6 +1,9 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.26; +import {DIRECT_CALL_VALIDATION_ENTITYID, FALLBACK_VALIDATION} from "../helpers/Constants.sol"; +import {SignatureType} from "../helpers/SignatureType.sol"; +import {ModularAccountBase} from "./ModularAccountBase.sol"; import {IModularAccount, ModuleEntity} from "@erc6900/reference-implementation/interfaces/IModularAccount.sol"; import {ModuleEntityLib} from "@erc6900/reference-implementation/libraries/ModuleEntityLib.sol"; import {IEntryPoint} from "@eth-infinitism/account-abstraction/interfaces/IEntryPoint.sol"; @@ -9,11 +12,6 @@ import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol"; import {SignatureChecker} from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol"; -import {DIRECT_CALL_VALIDATION_ENTITYID, FALLBACK_VALIDATION} from "../helpers/Constants.sol"; -import {SignatureType} from "../helpers/SignatureType.sol"; -import {SemiModularKnownSelectorsLib} from "../libraries/SemiModularKnownSelectorsLib.sol"; -import {ModularAccountBase} from "./ModularAccountBase.sol"; - abstract contract SemiModularAccountBase is ModularAccountBase { using MessageHashUtils for bytes32; using ModuleEntityLib for ModuleEntity; @@ -230,9 +228,4 @@ abstract contract SemiModularAccountBase is ModularAccountBase { } return res; } - - // Overrides ModuleManagerInternals - function _isNativeFunction(bytes4 selector) internal pure override returns (bool) { - return SemiModularKnownSelectorsLib.isNativeFunction(selector); - } } diff --git a/src/libraries/ExecutionInstallLib.sol b/src/libraries/ExecutionInstallLib.sol new file mode 100644 index 000000000..8952d044f --- /dev/null +++ b/src/libraries/ExecutionInstallLib.sol @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.8.26; + +import { + ExecutionManifest, + ManifestExecutionHook +} from "@erc6900/reference-implementation/interfaces/IExecutionModule.sol"; +import {HookConfig, IModularAccount} from "@erc6900/reference-implementation/interfaces/IModularAccount.sol"; +import {IModule} from "@erc6900/reference-implementation/interfaces/IModule.sol"; +import {HookConfigLib} from "@erc6900/reference-implementation/libraries/HookConfigLib.sol"; +import {ERC165Checker} from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol"; + +import {AccountStorage, ExecutionData, getAccountStorage, toSetValue} from "../account/AccountStorage.sol"; +import {ExecutionLib} from "./ExecutionLib.sol"; +import {KnownSelectorsLib} from "./KnownSelectorsLib.sol"; +import {LinkedListSet, LinkedListSetLib} from "./LinkedListSetLib.sol"; + +/// @title ExecutionInstallLib +/// @author Alchemy +/// +/// @notice This is a hybrid external-internal library which externally handles execution function installation, +/// while holding some common internal module installation-related functions. +library ExecutionInstallLib { + using LinkedListSetLib for LinkedListSet; + + error NullModule(); + error InterfaceNotSupported(address module); + error ModuleInstallCallbackFailed(address module, bytes revertReason); + error ExecutionFunctionAlreadySet(bytes4 selector); + error IModuleFunctionNotAllowed(bytes4 selector); + error Erc4337FunctionNotAllowed(bytes4 selector); + error ExecutionHookAlreadySet(HookConfig hookConfig); + + // External Functions + + function installExecution( + address module, + ExecutionManifest calldata manifest, + bytes calldata moduleInstallData + ) external { + AccountStorage storage _storage = getAccountStorage(); + + if (module == address(0)) { + revert NullModule(); + } + + // Update components according to the manifest. + uint256 length = manifest.executionFunctions.length; + for (uint256 i = 0; i < length; ++i) { + bytes4 selector = manifest.executionFunctions[i].executionSelector; + bool skipRuntimeValidation = manifest.executionFunctions[i].skipRuntimeValidation; + bool allowGlobalValidation = manifest.executionFunctions[i].allowGlobalValidation; + _setExecutionFunction(selector, skipRuntimeValidation, allowGlobalValidation, module); + } + + length = manifest.executionHooks.length; + for (uint256 i = 0; i < length; ++i) { + ManifestExecutionHook memory mh = manifest.executionHooks[i]; + ExecutionData storage executionData = _storage.executionData[mh.executionSelector]; + HookConfig hookConfig = HookConfigLib.packExecHook({ + _module: module, + _entityId: mh.entityId, + _hasPre: mh.isPreHook, + _hasPost: mh.isPostHook + }); + addExecHooks(executionData.executionHooks, hookConfig); + } + + length = manifest.interfaceIds.length; + for (uint256 i = 0; i < length; ++i) { + _storage.supportedIfaces[manifest.interfaceIds[i]] += 1; + } + + onInstall(module, moduleInstallData, type(IModule).interfaceId); + + emit IModularAccount.ExecutionInstalled(module, manifest); + } + + function uninstallExecution(address module, ExecutionManifest calldata manifest, bytes calldata uninstallData) + external + { + AccountStorage storage _storage = getAccountStorage(); + + // Remove components according to the manifest, in reverse order (by component type) of their installation. + + uint256 length = manifest.executionHooks.length; + for (uint256 i = 0; i < length; ++i) { + ManifestExecutionHook memory mh = manifest.executionHooks[i]; + ExecutionData storage execData = _storage.executionData[mh.executionSelector]; + HookConfig hookConfig = HookConfigLib.packExecHook({ + _module: module, + _entityId: mh.entityId, + _hasPre: mh.isPreHook, + _hasPost: mh.isPostHook + }); + _removeExecHooks(execData.executionHooks, hookConfig); + } + + length = manifest.executionFunctions.length; + for (uint256 i = 0; i < length; ++i) { + bytes4 selector = manifest.executionFunctions[i].executionSelector; + _removeExecutionFunction(selector); + } + + length = manifest.interfaceIds.length; + for (uint256 i = 0; i < length; ++i) { + _storage.supportedIfaces[manifest.interfaceIds[i]] -= 1; + } + + // Clear the module storage for the account. + bool onUninstallSuccess = onUninstall(module, uninstallData); + + emit IModularAccount.ExecutionUninstalled(module, onUninstallSuccess, manifest); + } + + // Internal Functions + + function addExecHooks(LinkedListSet storage hooks, HookConfig hookConfig) internal { + if (!hooks.tryAdd(toSetValue(hookConfig))) { + revert ExecutionHookAlreadySet(hookConfig); + } + } + + function onInstall(address module, bytes calldata data, bytes4 interfaceId) internal { + if (data.length > 0) { + if (!ERC165Checker.supportsERC165InterfaceUnchecked(module, interfaceId)) { + revert InterfaceNotSupported(module); + } + // solhint-disable-next-line no-empty-blocks + try IModule(module).onInstall(data) {} + catch { + bytes memory revertReason = ExecutionLib.collectReturnData(); + revert ModuleInstallCallbackFailed(module, revertReason); + } + } + } + + function onUninstall(address module, bytes calldata data) internal returns (bool onUninstallSuccess) { + onUninstallSuccess = true; + if (data.length > 0) { + // Clear the module storage for the account. + // solhint-disable-next-line no-empty-blocks + try IModule(module).onUninstall(data) {} + catch { + onUninstallSuccess = false; + } + } + } + + // Private Functions + + function _setExecutionFunction( + bytes4 selector, + bool skipRuntimeValidation, + bool allowGlobalValidation, + address module + ) private { + ExecutionData storage _executionData = getAccountStorage().executionData[selector]; + + if (_executionData.module != address(0)) { + revert ExecutionFunctionAlreadySet(selector); + } + + // Note that there is no check for native function selectors. Installing a function with a colliding + // selector will lead to the installed function being unreachable. + + // Make sure incoming execution function is not a function in IModule + if (KnownSelectorsLib.isIModuleFunction(selector)) { + revert IModuleFunctionNotAllowed(selector); + } + + // Also make sure it doesn't collide with functions defined by ERC-4337 and called by the entry point. This + // prevents a malicious module from sneaking in a function with the same selector as e.g. + // `validatePaymasterUserOp` and turning the account into their own personal paymaster. + if (KnownSelectorsLib.isErc4337Function(selector)) { + revert Erc4337FunctionNotAllowed(selector); + } + + _executionData.module = module; + _executionData.skipRuntimeValidation = skipRuntimeValidation; + _executionData.allowGlobalValidation = allowGlobalValidation; + } + + function _removeExecutionFunction(bytes4 selector) private { + ExecutionData storage _executionData = getAccountStorage().executionData[selector]; + + _executionData.module = address(0); + _executionData.skipRuntimeValidation = false; + _executionData.allowGlobalValidation = false; + } + + function _removeExecHooks(LinkedListSet storage hooks, HookConfig hookConfig) private { + // Todo: use predecessor + hooks.tryRemove(toSetValue(hookConfig)); + } +} diff --git a/src/libraries/KnownSelectorsLib.sol b/src/libraries/KnownSelectorsLib.sol index 3142bab73..f7b7479a7 100644 --- a/src/libraries/KnownSelectorsLib.sol +++ b/src/libraries/KnownSelectorsLib.sol @@ -1,17 +1,11 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.26; -import {IAccount} from "@eth-infinitism/account-abstraction/interfaces/IAccount.sol"; import {IAggregator} from "@eth-infinitism/account-abstraction/interfaces/IAggregator.sol"; import {IPaymaster} from "@eth-infinitism/account-abstraction/interfaces/IPaymaster.sol"; -import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol"; -import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; -import {ModularAccountBase} from "../account/ModularAccountBase.sol"; import {IExecutionHookModule} from "@erc6900/reference-implementation/interfaces/IExecutionHookModule.sol"; import {IExecutionModule} from "@erc6900/reference-implementation/interfaces/IExecutionModule.sol"; -import {IModularAccount} from "@erc6900/reference-implementation/interfaces/IModularAccount.sol"; -import {IModularAccountView} from "@erc6900/reference-implementation/interfaces/IModularAccountView.sol"; import {IModule} from "@erc6900/reference-implementation/interfaces/IModule.sol"; import {IValidationHookModule} from "@erc6900/reference-implementation/interfaces/IValidationHookModule.sol"; import {IValidationModule} from "@erc6900/reference-implementation/interfaces/IValidationModule.sol"; @@ -19,30 +13,6 @@ import {IValidationModule} from "@erc6900/reference-implementation/interfaces/IV /// @dev Library to help to check if a selector is a know function selector of the modular account or ERC-4337 /// contract. library KnownSelectorsLib { - function isNativeFunction(bytes4 selector) internal pure returns (bool) { - return - // check against IAccount methods - selector == IAccount.validateUserOp.selector - // check against IModularAccount methods - || selector == IModularAccount.installExecution.selector - || selector == IModularAccount.uninstallExecution.selector - || selector == IModularAccount.installValidation.selector - || selector == IModularAccount.uninstallValidation.selector || selector == IModularAccount.execute.selector - || selector == IModularAccount.executeBatch.selector - || selector == IModularAccount.executeWithRuntimeValidation.selector - || selector == IModularAccount.accountId.selector - // check against IERC165 methods - || selector == IERC165.supportsInterface.selector - // check against UUPSUpgradeable methods - || selector == UUPSUpgradeable.proxiableUUID.selector - || selector == UUPSUpgradeable.upgradeToAndCall.selector - // check against IModularAccountView methods - || selector == IModularAccountView.getExecutionData.selector - || selector == IModularAccountView.getValidationData.selector - // check against ModularAccount methods - || selector == ModularAccountBase.performCreate.selector; - } - function isErc4337Function(bytes4 selector) internal pure returns (bool) { return selector == IAggregator.validateSignatures.selector || selector == IAggregator.validateUserOpSignature.selector diff --git a/src/libraries/SemiModularKnownSelectorsLib.sol b/src/libraries/SemiModularKnownSelectorsLib.sol deleted file mode 100644 index 1217d270e..000000000 --- a/src/libraries/SemiModularKnownSelectorsLib.sol +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.26; - -import {SemiModularAccountBase} from "../account/SemiModularAccountBase.sol"; -import {KnownSelectorsLib} from "./KnownSelectorsLib.sol"; - -/// @dev Library to help to check if a selector is a know function selector of the SemiModularAccountBase or -/// ModularAccount contract -library SemiModularKnownSelectorsLib { - function isNativeFunction(bytes4 selector) internal pure returns (bool) { - return KnownSelectorsLib.isNativeFunction(selector) - || selector == SemiModularAccountBase.updateFallbackSignerData.selector - || selector == SemiModularAccountBase.getFallbackSignerData.selector - || selector == SemiModularAccountBase.replaySafeHash.selector; - } -} diff --git a/test/libraries/KnowSelectors.t.sol b/test/libraries/KnowSelectors.t.sol deleted file mode 100644 index 9008cdb3a..000000000 --- a/test/libraries/KnowSelectors.t.sol +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.26; - -import {IModule} from "@erc6900/reference-implementation/interfaces/IModule.sol"; -import {IAccount} from "@eth-infinitism/account-abstraction/interfaces/IAccount.sol"; -import {IPaymaster} from "@eth-infinitism/account-abstraction/interfaces/IPaymaster.sol"; -import {Test} from "forge-std/src/Test.sol"; - -import {ModularAccountBase} from "../../src/account/ModularAccountBase.sol"; -import {SemiModularAccountBase} from "../../src/account/SemiModularAccountBase.sol"; -import {KnownSelectorsLib} from "../../src/libraries/KnownSelectorsLib.sol"; -import {SemiModularKnownSelectorsLib} from "../../src/libraries/SemiModularKnownSelectorsLib.sol"; - -contract KnownSelectorsTest is Test { - function test_isNativeFunction() public pure { - assertTrue(KnownSelectorsLib.isNativeFunction(IAccount.validateUserOp.selector)); - assertTrue(KnownSelectorsLib.isNativeFunction(ModularAccountBase.installValidation.selector)); - } - - function test_sma_isNativeFunction() public pure { - assertTrue(SemiModularKnownSelectorsLib.isNativeFunction(IAccount.validateUserOp.selector)); - assertTrue( - SemiModularKnownSelectorsLib.isNativeFunction(SemiModularAccountBase.getFallbackSignerData.selector) - ); - assertTrue(SemiModularKnownSelectorsLib.isNativeFunction(ModularAccountBase.installValidation.selector)); - } - - function test_isErc4337Function() public pure { - assertTrue(KnownSelectorsLib.isErc4337Function(IPaymaster.validatePaymasterUserOp.selector)); - } - - function test_isIModuleFunction() public pure { - assertTrue(KnownSelectorsLib.isIModuleFunction(IModule.moduleId.selector)); - } -} diff --git a/test/libraries/KnowSelectorsLib.t.sol b/test/libraries/KnowSelectorsLib.t.sol new file mode 100644 index 000000000..6bb714f4e --- /dev/null +++ b/test/libraries/KnowSelectorsLib.t.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.26; + +import {IExecutionHookModule} from "@erc6900/reference-implementation/interfaces/IExecutionHookModule.sol"; +import {IModule} from "@erc6900/reference-implementation/interfaces/IModule.sol"; +import {IValidationHookModule} from "@erc6900/reference-implementation/interfaces/IValidationHookModule.sol"; +import {IValidationModule} from "@erc6900/reference-implementation/interfaces/IValidationModule.sol"; + +import {IAccount} from "@eth-infinitism/account-abstraction/interfaces/IAccount.sol"; +import {IAggregator} from "@eth-infinitism/account-abstraction/interfaces/IAggregator.sol"; +import {IPaymaster} from "@eth-infinitism/account-abstraction/interfaces/IPaymaster.sol"; +import {Test} from "forge-std/src/Test.sol"; + +import {KnownSelectorsLib} from "../../src/libraries/KnownSelectorsLib.sol"; + +contract KnownSelectorsLibTest is Test { + function test_isErc4337Function() public pure { + assertTrue(KnownSelectorsLib.isErc4337Function(IAggregator.validateSignatures.selector)); + assertTrue(KnownSelectorsLib.isErc4337Function(IAggregator.validateUserOpSignature.selector)); + assertTrue(KnownSelectorsLib.isErc4337Function(IAggregator.aggregateSignatures.selector)); + assertTrue(KnownSelectorsLib.isErc4337Function(IPaymaster.validatePaymasterUserOp.selector)); + assertTrue(KnownSelectorsLib.isErc4337Function(IPaymaster.postOp.selector)); + + assertFalse(KnownSelectorsLib.isErc4337Function(IAccount.validateUserOp.selector)); + } + + function test_isIModuleFunction() public pure { + assertTrue(KnownSelectorsLib.isIModuleFunction(IModule.onInstall.selector)); + assertTrue(KnownSelectorsLib.isIModuleFunction(IModule.onUninstall.selector)); + assertTrue(KnownSelectorsLib.isIModuleFunction(IModule.moduleId.selector)); + assertTrue(KnownSelectorsLib.isIModuleFunction(IValidationHookModule.preUserOpValidationHook.selector)); + assertTrue(KnownSelectorsLib.isIModuleFunction(IValidationModule.validateUserOp.selector)); + assertTrue(KnownSelectorsLib.isIModuleFunction(IValidationHookModule.preRuntimeValidationHook.selector)); + assertTrue(KnownSelectorsLib.isIModuleFunction(IValidationModule.validateRuntime.selector)); + assertTrue(KnownSelectorsLib.isIModuleFunction(IExecutionHookModule.preExecutionHook.selector)); + assertTrue(KnownSelectorsLib.isIModuleFunction(IExecutionHookModule.postExecutionHook.selector)); + + assertFalse(KnownSelectorsLib.isIModuleFunction(IPaymaster.postOp.selector)); + } +}