Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/account/AccountStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
6 changes: 3 additions & 3 deletions src/account/ModularAccountView.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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));
}
}
}
Expand All @@ -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();
Expand Down
4 changes: 2 additions & 2 deletions src/account/ModuleManagerInternals.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
53 changes: 24 additions & 29 deletions src/helpers/HookConfigLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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) {
Expand All @@ -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))
)
);
}
Expand All @@ -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));
}

Expand All @@ -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;
Expand Down
15 changes: 13 additions & 2 deletions src/interfaces/IModularAccount.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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,
Expand Down