Skip to content

Commit

Permalink
feat: [v0.8-develop] merge plugin manager contracts 2/N (#102)
Browse files Browse the repository at this point in the history
  • Loading branch information
adamegyed authored Jul 23, 2024
1 parent ce001a8 commit c41cc7c
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 181 deletions.
148 changes: 0 additions & 148 deletions src/account/ModuleManager2.sol

This file was deleted.

181 changes: 156 additions & 25 deletions src/account/ModuleManagerInternals.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,35 @@ import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet

import {KnownSelectors} from "../helpers/KnownSelectors.sol";
import {ModuleEntityLib} from "../helpers/ModuleEntityLib.sol";
import {ValidationConfigLib} from "../helpers/ValidationConfigLib.sol";
import {ExecutionHook} from "../interfaces/IAccountLoupe.sol";
import {IModule, ManifestExecutionHook, ManifestValidation, ModuleManifest} from "../interfaces/IModule.sol";
import {IModuleManager, ModuleEntity} from "../interfaces/IModuleManager.sol";
import {AccountStorage, SelectorData, getAccountStorage, toSetValue} from "./AccountStorage.sol";
import {IModuleManager, ModuleEntity, ValidationConfig} from "../interfaces/IModuleManager.sol";
import {AccountStorage, SelectorData, ValidationData, getAccountStorage, toSetValue} from "./AccountStorage.sol";

abstract contract ModuleManagerInternals is IModuleManager {
using EnumerableSet for EnumerableSet.Bytes32Set;
using ModuleEntityLib for ModuleEntity;
using ValidationConfigLib for ValidationConfig;

// Index marking the start of the data for the validation function.
uint8 internal constant _RESERVED_VALIDATION_DATA_INDEX = 255;

// Magic value for the Entity ID of direct call validation.
uint32 internal constant _SELF_PERMIT_VALIDATION_FUNCTIONID = type(uint32).max;

error ArrayLengthMismatch();
error Erc4337FunctionNotAllowed(bytes4 selector);
error ExecutionFunctionAlreadySet(bytes4 selector);
error IModuleFunctionNotAllowed(bytes4 selector);
error NativeFunctionNotAllowed(bytes4 selector);
error NullModule();
error PermissionAlreadySet(ModuleEntity validationFunction, ExecutionHook hook);
error ModuleInstallCallbackFailed(address module, bytes revertReason);
error ModuleInterfaceNotSupported(address module);
error ModuleNotInstalled(address module);
error ValidationFunctionAlreadySet(bytes4 selector, ModuleEntity validationFunction);
error PreValidationHookLimitExceeded();
error ValidationAlreadySet(bytes4 selector, ModuleEntity validationFunction);

// Storage update operations

Expand Down Expand Up @@ -71,39 +81,35 @@ abstract contract ModuleManagerInternals is IModuleManager {
_selectorData.allowGlobalValidation = false;
}

function _addValidationFunction(address module, ManifestValidation memory mv) internal {
AccountStorage storage _storage = getAccountStorage();
function _addValidationFunction(ValidationConfig validationConfig, bytes4[] memory selectors) internal {
ValidationData storage _validationData =
getAccountStorage().validationData[validationConfig.moduleEntity()];

ModuleEntity validationFunction = ModuleEntityLib.pack(module, mv.entityId);

if (mv.isDefault) {
_storage.validationData[validationFunction].isGlobal = true;
if (validationConfig.isGlobal()) {
_validationData.isGlobal = true;
}

if (mv.isSignatureValidation) {
_storage.validationData[validationFunction].isSignatureValidation = true;
if (validationConfig.isSignatureValidation()) {
_validationData.isSignatureValidation = true;
}

// Add the validation function to the selectors.
uint256 length = mv.selectors.length;
uint256 length = selectors.length;
for (uint256 i = 0; i < length; ++i) {
bytes4 selector = mv.selectors[i];
_storage.validationData[validationFunction].selectors.add(toSetValue(selector));
_validationData.selectors.add(toSetValue(selectors[i]));
}
}

function _removeValidationFunction(address module, ManifestValidation memory mv) internal {
AccountStorage storage _storage = getAccountStorage();

ModuleEntity validationFunction = ModuleEntityLib.pack(module, mv.entityId);
function _removeValidationFunction(ModuleEntity validationFunction) internal {
ValidationData storage _validationData = getAccountStorage().validationData[validationFunction];

_storage.validationData[validationFunction].isGlobal = false;
_storage.validationData[validationFunction].isSignatureValidation = false;
_validationData.isGlobal = false;
_validationData.isSignatureValidation = false;

// Clear the selectors
while (_storage.validationData[validationFunction].selectors.length() > 0) {
bytes32 selector = _storage.validationData[validationFunction].selectors.at(0);
_storage.validationData[validationFunction].selectors.remove(selector);
uint256 length = _validationData.selectors.length();
for (uint256 i = 0; i < length; ++i) {
_validationData.selectors.remove(_validationData.selectors.at(0));
}
}

Expand Down Expand Up @@ -161,7 +167,11 @@ abstract contract ModuleManagerInternals is IModuleManager {
for (uint256 i = 0; i < length; ++i) {
// Todo: limit this to only "direct runtime call" validation path (old EFP),
// and add a way for the user to specify permission/pre-val hooks here.
_addValidationFunction(module, manifest.validationFunctions[i]);
ManifestValidation memory mv = manifest.validationFunctions[i];

ValidationConfig validationConfig =
ValidationConfigLib.pack(module, mv.entityId, mv.isGlobal, mv.isSignatureValidation);
_addValidationFunction(validationConfig, mv.selectors);
}

length = manifest.executionHooks.length;
Expand Down Expand Up @@ -204,7 +214,9 @@ abstract contract ModuleManagerInternals is IModuleManager {

length = manifest.validationFunctions.length;
for (uint256 i = 0; i < length; ++i) {
_removeValidationFunction(module, manifest.validationFunctions[i]);
ModuleEntity validationFunction =
ModuleEntityLib.pack(module, manifest.validationFunctions[i].entityId);
_removeValidationFunction(validationFunction);
}

length = manifest.executionFunctions.length;
Expand All @@ -228,4 +240,123 @@ abstract contract ModuleManagerInternals is IModuleManager {

emit ModuleUninstalled(module, onUninstallSuccess);
}

function _installValidation(
ValidationConfig validationConfig,
bytes4[] memory selectors,
bytes calldata installData,
bytes memory preValidationHooks,
bytes memory permissionHooks
) internal {
ValidationData storage _validationData =
getAccountStorage().validationData[validationConfig.moduleEntity()];

if (preValidationHooks.length > 0) {
(ModuleEntity[] memory preValidationFunctions, bytes[] memory initDatas) =
abi.decode(preValidationHooks, (ModuleEntity[], bytes[]));

for (uint256 i = 0; i < preValidationFunctions.length; ++i) {
ModuleEntity preValidationFunction = preValidationFunctions[i];

_validationData.preValidationHooks.push(preValidationFunction);

if (initDatas[i].length > 0) {
(address preValidationPlugin,) = ModuleEntityLib.unpack(preValidationFunction);
IModule(preValidationPlugin).onInstall(initDatas[i]);
}
}

// Avoid collision between reserved index and actual indices
if (_validationData.preValidationHooks.length > _RESERVED_VALIDATION_DATA_INDEX) {
revert PreValidationHookLimitExceeded();
}
}

if (permissionHooks.length > 0) {
(ExecutionHook[] memory permissionFunctions, bytes[] memory initDatas) =
abi.decode(permissionHooks, (ExecutionHook[], bytes[]));

for (uint256 i = 0; i < permissionFunctions.length; ++i) {
ExecutionHook memory permissionFunction = permissionFunctions[i];

if (!_validationData.permissionHooks.add(toSetValue(permissionFunction))) {
revert PermissionAlreadySet(validationConfig.moduleEntity(), permissionFunction);
}

if (initDatas[i].length > 0) {
(address executionPlugin,) = ModuleEntityLib.unpack(permissionFunction.hookFunction);
IModule(executionPlugin).onInstall(initDatas[i]);
}
}
}

for (uint256 i = 0; i < selectors.length; ++i) {
bytes4 selector = selectors[i];
if (!_validationData.selectors.add(toSetValue(selector))) {
revert ValidationAlreadySet(selector, validationConfig.moduleEntity());
}
}

if (validationConfig.entityId() != _SELF_PERMIT_VALIDATION_FUNCTIONID) {
// Only allow global validations and signature validations if they're not direct-call validations.

_validationData.isGlobal = validationConfig.isGlobal();
_validationData.isSignatureValidation = validationConfig.isSignatureValidation();
if (installData.length > 0) {
IModule(validationConfig.module()).onInstall(installData);
}
}
}

function _uninstallValidation(
ModuleEntity validationFunction,
bytes calldata uninstallData,
bytes calldata preValidationHookUninstallData,
bytes calldata permissionHookUninstallData
) internal {
ValidationData storage _validationData = getAccountStorage().validationData[validationFunction];

_removeValidationFunction(validationFunction);

{
bytes[] memory preValidationHookUninstallDatas = abi.decode(preValidationHookUninstallData, (bytes[]));

// Clear pre validation hooks
ModuleEntity[] storage preValidationHooks = _validationData.preValidationHooks;
for (uint256 i = 0; i < preValidationHooks.length; ++i) {
ModuleEntity preValidationFunction = preValidationHooks[i];
if (preValidationHookUninstallDatas[0].length > 0) {
(address preValidationPlugin,) = ModuleEntityLib.unpack(preValidationFunction);
IModule(preValidationPlugin).onUninstall(preValidationHookUninstallDatas[0]);
}
}
delete _validationData.preValidationHooks;
}

{
bytes[] memory permissionHookUninstallDatas = abi.decode(permissionHookUninstallData, (bytes[]));

// Clear permission hooks
EnumerableSet.Bytes32Set storage permissionHooks = _validationData.permissionHooks;
uint256 permissionHookLen = permissionHooks.length();
for (uint256 i = 0; i < permissionHookLen; ++i) {
bytes32 permissionHook = permissionHooks.at(0);
permissionHooks.remove(permissionHook);
address permissionHookPlugin = address(uint160(bytes20(permissionHook)));
IModule(permissionHookPlugin).onUninstall(permissionHookUninstallDatas[i]);
}
}

// Clear selectors
uint256 selectorLen = _validationData.selectors.length();
for (uint256 i = 0; i < selectorLen; ++i) {
bytes32 selectorSetValue = _validationData.selectors.at(0);
_validationData.selectors.remove(selectorSetValue);
}

if (uninstallData.length > 0) {
(address plugin,) = ModuleEntityLib.unpack(validationFunction);
IModule(plugin).onUninstall(uninstallData);
}
}
}
Loading

0 comments on commit c41cc7c

Please sign in to comment.