diff --git a/src/account/AccountStorage.sol b/src/account/AccountStorage.sol index 7681e294..79393208 100644 --- a/src/account/AccountStorage.sol +++ b/src/account/AccountStorage.sol @@ -76,7 +76,7 @@ function toSetValue(HookConfig hookConfig) pure returns (bytes32) { } function toHookConfig(bytes32 setValue) pure returns (HookConfig) { - return HookConfig.wrap(bytes26(setValue)); + return HookConfig.wrap(bytes25(setValue)); } function toSetValue(bytes4 selector) pure returns (bytes32) { diff --git a/src/account/ModularAccountView.sol b/src/account/ModularAccountView.sol index c432f02f..36150fde 100644 --- a/src/account/ModularAccountView.sol +++ b/src/account/ModularAccountView.sol @@ -8,7 +8,7 @@ import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet import {HookConfigLib} from "../helpers/HookConfigLib.sol"; import {HookConfig, IModularAccount, ModuleEntity} from "../interfaces/IModularAccount.sol"; import {ExecutionDataView, IModularAccountView, ValidationDataView} from "../interfaces/IModularAccountView.sol"; -import {ExecutionData, ValidationData, getAccountStorage} from "./AccountStorage.sol"; +import {ExecutionData, ValidationData, getAccountStorage, toHookConfig} from "./AccountStorage.sol"; abstract contract ModularAccountView is IModularAccountView { using EnumerableSet for EnumerableSet.Bytes32Set; @@ -34,7 +34,7 @@ abstract contract ModularAccountView is IModularAccountView { uint256 executionHooksLen = executionData.executionHooks.length(); data.executionHooks = new HookConfig[](executionHooksLen); for (uint256 i = 0; i < executionHooksLen; ++i) { - data.executionHooks[i] = HookConfig.wrap(bytes26(executionData.executionHooks.at(i))); + data.executionHooks[i] = toHookConfig(executionData.executionHooks.at(i)); } } } @@ -55,7 +55,7 @@ abstract contract ModularAccountView is IModularAccountView { uint256 permissionHooksLen = validationData.permissionHooks.length(); data.permissionHooks = new HookConfig[](permissionHooksLen); for (uint256 i = 0; i < permissionHooksLen; ++i) { - data.permissionHooks[i] = HookConfig.wrap(bytes26(validationData.permissionHooks.at(i))); + data.permissionHooks[i] = toHookConfig(validationData.permissionHooks.at(i)); } bytes32[] memory selectors = validationData.selectors.values(); diff --git a/src/account/ModuleManagerInternals.sol b/src/account/ModuleManagerInternals.sol index 3731264d..9f6ee1a2 100644 --- a/src/account/ModuleManagerInternals.sol +++ b/src/account/ModuleManagerInternals.sol @@ -229,8 +229,8 @@ abstract contract ModuleManagerInternals is IModularAccount { ModuleEntity moduleEntity = validationConfig.moduleEntity(); for (uint256 i = 0; i < hooks.length; ++i) { - HookConfig hookConfig = HookConfig.wrap(bytes26(hooks[i][:26])); - bytes calldata hookData = hooks[i][26:]; + HookConfig hookConfig = HookConfig.wrap(bytes25(hooks[i][:25])); + bytes calldata hookData = hooks[i][25:]; if (hookConfig.isValidationHook()) { _validationData.preValidationHooks.push(hookConfig.moduleEntity()); diff --git a/src/helpers/HookConfigLib.sol b/src/helpers/HookConfigLib.sol index 81eaf0f4..c1c27994 100644 --- a/src/helpers/HookConfigLib.sol +++ b/src/helpers/HookConfigLib.sol @@ -17,18 +17,13 @@ import {HookConfig, ModuleEntity} from "../interfaces/IModularAccount.sol"; // Layout: // 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA________________________ // Address // 0x________________________________________BBBBBBBB________________ // Entity ID -// 0x________________________________________________CC______________ // Type -// 0x__________________________________________________DD____________ // exec hook flags -// +// 0x________________________________________________CC______________ // Hook Flags -// Hook types: -// 0x00 // Exec (selector and validation associated) -// 0x01 // Validation - -// Exec hook flags layout: -// 0b000000__ // unused -// 0b______A_ // hasPre -// 0b_______B // hasPost +// Hook flags layout: +// 0b00000___ // unused +// 0b_____A__ // hasPre (exec only) +// 0b______B_ // hasPost (exec only) +// 0b_______C // hook type (0 for exec, 1 for validation) library HookConfigLib { // Hook type constants @@ -38,14 +33,14 @@ library HookConfigLib { bytes32 internal constant _HOOK_TYPE_VALIDATION = bytes32(uint256(1) << 56); // Exec hook flags constants - // Pre hook has 1 in 2's bit in the 26th byte - bytes32 internal constant _EXEC_HOOK_HAS_PRE = bytes32(uint256(1) << 49); - // Post hook has 1 in 1's bit in the 26th byte - bytes32 internal constant _EXEC_HOOK_HAS_POST = bytes32(uint256(1) << 48); + // Pre hook has 1 in 4's bit in the 25th byte + bytes32 internal constant _EXEC_HOOK_HAS_PRE = bytes32(uint256(1) << 58); + // Post hook has 1 in 2's bit in the 25th byte + bytes32 internal constant _EXEC_HOOK_HAS_POST = bytes32(uint256(1) << 57); function packValidationHook(ModuleEntity _hookFunction) internal pure returns (HookConfig) { return - HookConfig.wrap(bytes26(bytes26(ModuleEntity.unwrap(_hookFunction)) | bytes26(_HOOK_TYPE_VALIDATION))); + HookConfig.wrap(bytes25(bytes25(ModuleEntity.unwrap(_hookFunction)) | bytes25(_HOOK_TYPE_VALIDATION))); } function packValidationHook(address _module, uint32 _entityId) internal pure returns (HookConfig) { @@ -65,11 +60,11 @@ library HookConfigLib { returns (HookConfig) { return HookConfig.wrap( - bytes26( - bytes26(ModuleEntity.unwrap(_hookFunction)) - // | bytes26(_HOOK_TYPE_EXEC) // Can omit because exec type is 0 - | bytes26(_hasPre ? _EXEC_HOOK_HAS_PRE : bytes32(0)) - | bytes26(_hasPost ? _EXEC_HOOK_HAS_POST : bytes32(0)) + bytes25( + bytes25(ModuleEntity.unwrap(_hookFunction)) + // | bytes25(_HOOK_TYPE_EXEC) // Can omit because exec type is 0 + | bytes25(_hasPre ? _EXEC_HOOK_HAS_PRE : bytes32(0)) + | bytes25(_hasPost ? _EXEC_HOOK_HAS_POST : bytes32(0)) ) ); } @@ -80,20 +75,20 @@ library HookConfigLib { returns (HookConfig) { return HookConfig.wrap( - bytes26( + bytes25( // module address stored in the first 20 bytes - bytes26(bytes20(_module)) + bytes25(bytes20(_module)) // entityId stored in the 21st - 24th byte - | bytes26(bytes24(uint192(_entityId))) - // | bytes26(_HOOK_TYPE_EXEC) // Can omit because exec type is 0 - | bytes26(_hasPre ? _EXEC_HOOK_HAS_PRE : bytes32(0)) - | bytes26(_hasPost ? _EXEC_HOOK_HAS_POST : bytes32(0)) + | bytes25(bytes24(uint192(_entityId))) + // | bytes25(_HOOK_TYPE_EXEC) // Can omit because exec type is 0 + | bytes25(_hasPre ? _EXEC_HOOK_HAS_PRE : bytes32(0)) + | bytes25(_hasPost ? _EXEC_HOOK_HAS_POST : bytes32(0)) ) ); } function unpackValidationHook(HookConfig _config) internal pure returns (ModuleEntity _hookFunction) { - bytes26 configBytes = HookConfig.unwrap(_config); + bytes25 configBytes = HookConfig.unwrap(_config); _hookFunction = ModuleEntity.wrap(bytes24(configBytes)); } @@ -102,7 +97,7 @@ library HookConfigLib { pure returns (ModuleEntity _hookFunction, bool _hasPre, bool _hasPost) { - bytes26 configBytes = HookConfig.unwrap(_config); + bytes25 configBytes = HookConfig.unwrap(_config); _hookFunction = ModuleEntity.wrap(bytes24(configBytes)); _hasPre = configBytes & _EXEC_HOOK_HAS_PRE != 0; _hasPost = configBytes & _EXEC_HOOK_HAS_POST != 0; diff --git a/src/interfaces/IModularAccount.sol b/src/interfaces/IModularAccount.sol index 680d1b68..25f43465 100644 --- a/src/interfaces/IModularAccount.sol +++ b/src/interfaces/IModularAccount.sol @@ -24,7 +24,18 @@ type ValidationConfig is bytes25; // 0b______B_ // isSignatureValidation // 0b_______C // isUserOpValidation -type HookConfig is bytes26; +type HookConfig is bytes25; +// HookConfig is a packed representation of a hook function and flags for its configuration. +// Layout: +// 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA________________________ // Address +// 0x________________________________________BBBBBBBB________________ // Entity ID +// 0x________________________________________________CC______________ // Hook Flags +// +// Hook flags layout: +// 0b00000___ // unused +// 0b_____A__ // hasPre (exec only) +// 0b______B_ // hasPost (exec only) +// 0b_______C // hook type (0 for exec, 1 for validation) struct Call { // The target address for the account to call. @@ -82,7 +93,7 @@ interface IModularAccount { /// @param selectors The selectors to install the validation function for. /// @param installData Optional data to be decoded and used by the module to setup initial module state. /// @param hooks Optional hooks to install, associated with the validation function. These may be - /// pre validation hooks or execution hooks. The expected format is a bytes26 HookConfig, followed by the + /// pre validation hooks or execution hooks. The expected format is a bytes25 HookConfig, followed by the /// install data, if any. function installValidation( ValidationConfig validationConfig,