Skip to content

Commit

Permalink
feat: pack hook config (#169)
Browse files Browse the repository at this point in the history
  • Loading branch information
adamegyed authored Aug 29, 2024
1 parent 3ca2c30 commit e531ee4
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 37 deletions.
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

0 comments on commit e531ee4

Please sign in to comment.