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
18 changes: 1 addition & 17 deletions src/account/AccountLoupe.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,7 @@ import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeab
import {EnumerableMap} from "@openzeppelin/contracts/utils/structs/EnumerableMap.sol";
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

import {
AccountStorage,
getAccountStorage,
getPermittedCallKey,
HookGroup,
toFunctionReferenceArray
} from "./AccountStorage.sol";
import {AccountStorage, getAccountStorage, HookGroup, toFunctionReferenceArray} from "./AccountStorage.sol";
import {FunctionReference} from "../helpers/FunctionReferenceLib.sol";
import {IAccountLoupe} from "../interfaces/IAccountLoupe.sol";
import {IPluginManager} from "../interfaces/IPluginManager.sol";
Expand Down Expand Up @@ -53,16 +47,6 @@ abstract contract AccountLoupe is IAccountLoupe {
execHooks = _getHooks(getAccountStorage().selectorData[selector].executionHooks);
}

/// @inheritdoc IAccountLoupe
function getPermittedCallHooks(address callingPlugin, bytes4 selector)
external
view
returns (ExecutionHooks[] memory execHooks)
{
bytes24 key = getPermittedCallKey(callingPlugin, selector);
execHooks = _getHooks(getAccountStorage().permittedCalls[key].permittedCallHooks);
}

/// @inheritdoc IAccountLoupe
function getPreValidationHooks(bytes4 selector)
external
Expand Down
17 changes: 1 addition & 16 deletions src/account/AccountStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,12 @@ struct PluginData {
FunctionReference[] dependencies;
// Tracks the number of times this plugin has been used as a dependency function
uint256 dependentCount;
StoredInjectedHook[] injectedHooks;
}

// A version of IPluginManager.InjectedHook used to track injected hooks in storage.
// Omits the hookApplyData field, which is not needed for storage, and flattens the struct.
struct StoredInjectedHook {
// The plugin that provides the hook
address providingPlugin;
// Either a plugin-defined execution function, or the native function executeFromPluginExternal
bytes4 selector;
// Contents of the InjectedHooksInfo struct
uint8 preExecHookFunctionId;
bool isPostHookUsed;
uint8 postExecHookFunctionId;
}

// Represents data associated with a plugin's permission to use `executeFromPlugin`
// to interact with another plugin installed on the account.
struct PermittedCallData {
bool callPermitted;
HookGroup permittedCallHooks;
}

// Represents data associated with a plugin's permission to use `executeFromPluginExternal`
Expand All @@ -52,7 +37,7 @@ struct PermittedExternalCallData {
mapping(bytes4 => bool) permittedSelectors;
}

// Represets a set of pre- and post- hooks. Used to store both execution hooks and permitted call hooks.
// Represets a set of pre- and post- hooks.
struct HookGroup {
EnumerableMap.Bytes32ToUintMap preHooks;
// bytes21 key = pre hook function reference
Expand Down
197 changes: 6 additions & 191 deletions src/account/PluginManagerInternals.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,9 @@ import {
AccountStorage,
getAccountStorage,
SelectorData,
PermittedCallData,
getPermittedCallKey,
HookGroup,
PermittedExternalCallData,
StoredInjectedHook
PermittedExternalCallData
} from "./AccountStorage.sol";
import {FunctionReference, FunctionReferenceLib} from "../helpers/FunctionReferenceLib.sol";
import {IPluginManager} from "../interfaces/IPluginManager.sol";
Expand Down Expand Up @@ -45,8 +43,6 @@ abstract contract PluginManagerInternals is IPluginManager {
error PluginNotInstalled(address plugin);
error RuntimeValidationFunctionAlreadySet(bytes4 selector, FunctionReference validationFunction);
error UserOpValidationFunctionAlreadySet(bytes4 selector, FunctionReference validationFunction);
error PluginApplyHookCallbackFailed(address providingPlugin, bytes revertReason);
error PluginUnapplyHookCallbackFailed(address providingPlugin, bytes revertReason);

modifier notNullFunction(FunctionReference functionReference) {
if (functionReference.isEmpty()) {
Expand Down Expand Up @@ -157,30 +153,6 @@ abstract contract PluginManagerInternals is IPluginManager {
accountStorage.permittedCalls[key].callPermitted = false;
}

function _addPermittedCallHooks(
bytes4 selector,
address plugin,
FunctionReference preExecHook,
FunctionReference postExecHook
) internal notNullPlugin(plugin) {
bytes24 permittedCallKey = getPermittedCallKey(plugin, selector);
PermittedCallData storage _permittedCalldata = getAccountStorage().permittedCalls[permittedCallKey];

_addHooks(_permittedCalldata.permittedCallHooks, preExecHook, postExecHook);
}

function _removePermittedCallHooks(
bytes4 selector,
address plugin,
FunctionReference preExecHook,
FunctionReference postExecHook
) internal notNullPlugin(plugin) {
bytes24 permittedCallKey = getPermittedCallKey(plugin, selector);
PermittedCallData storage _permittedCallData = getAccountStorage().permittedCalls[permittedCallKey];

_removeHooks(_permittedCallData.permittedCallHooks, preExecHook, postExecHook);
}

function _addHooks(HookGroup storage hooks, FunctionReference preExecHook, FunctionReference postExecHook)
internal
{
Expand Down Expand Up @@ -263,8 +235,7 @@ abstract contract PluginManagerInternals is IPluginManager {
address plugin,
bytes32 manifestHash,
bytes memory pluginInitData,
FunctionReference[] memory dependencies,
InjectedHook[] memory injectedHooks
FunctionReference[] memory dependencies
) internal {
AccountStorage storage _storage = getAccountStorage();

Expand Down Expand Up @@ -376,44 +347,6 @@ abstract contract PluginManagerInternals is IPluginManager {
}
}

length = injectedHooks.length;
// manually set arr length
StoredInjectedHook[] storage optionalHooksLengthArr = _storage.pluginData[plugin].injectedHooks;
assembly ("memory-safe") {
sstore(optionalHooksLengthArr.slot, length)
}

for (uint256 i = 0; i < length;) {
InjectedHook memory hook = injectedHooks[i];
_storage.pluginData[plugin].injectedHooks[i] = StoredInjectedHook({
providingPlugin: hook.providingPlugin,
selector: hook.selector,
preExecHookFunctionId: hook.injectedHooksInfo.preExecHookFunctionId,
isPostHookUsed: hook.injectedHooksInfo.isPostHookUsed,
postExecHookFunctionId: hook.injectedHooksInfo.postExecHookFunctionId
});

// Increment the dependent count for the plugin providing the hook.
_storage.pluginData[hook.providingPlugin].dependentCount += 1;

if (!_storage.plugins.contains(hook.providingPlugin)) {
revert MissingPluginDependency(hook.providingPlugin);
}

_addPermittedCallHooks(
hook.selector,
plugin,
FunctionReferenceLib.pack(hook.providingPlugin, hook.injectedHooksInfo.preExecHookFunctionId),
hook.injectedHooksInfo.isPostHookUsed
? FunctionReferenceLib.pack(hook.providingPlugin, hook.injectedHooksInfo.postExecHookFunctionId)
: FunctionReferenceLib._EMPTY_FUNCTION_REFERENCE
);

unchecked {
++i;
}
}

length = manifest.userOpValidationFunctions.length;
for (uint256 i = 0; i < length;) {
ManifestAssociatedFunction memory mv = manifest.userOpValidationFunctions[i];
Expand Down Expand Up @@ -500,30 +433,6 @@ abstract contract PluginManagerInternals is IPluginManager {
}
}

length = manifest.permittedCallHooks.length;
for (uint256 i = 0; i < length;) {
_addPermittedCallHooks(
manifest.permittedCallHooks[i].executionSelector,
plugin,
_resolveManifestFunction(
manifest.permittedCallHooks[i].preExecHook,
plugin,
dependencies,
ManifestAssociatedFunctionType.PRE_HOOK_ALWAYS_DENY
),
_resolveManifestFunction(
manifest.permittedCallHooks[i].postExecHook,
plugin,
dependencies,
ManifestAssociatedFunctionType.NONE
)
);

unchecked {
++i;
}
}

length = manifest.interfaceIds.length;
for (uint256 i = 0; i < length;) {
_storage.supportedIfaces[manifest.interfaceIds[i]] += 1;
Expand All @@ -532,40 +441,19 @@ abstract contract PluginManagerInternals is IPluginManager {
}
}

// call onHookApply after all setup, but before calling plugin onInstall
length = injectedHooks.length;

for (uint256 i = 0; i < length;) {
InjectedHook memory hook = injectedHooks[i];
// not inlined in function call to avoid stack too deep error
bytes memory onHookApplyData = injectedHooks[i].hookApplyData;
/* solhint-disable no-empty-blocks */
try IPlugin(hook.providingPlugin).onHookApply(plugin, hook.injectedHooksInfo, onHookApplyData) {}
catch (bytes memory revertReason) {
revert PluginApplyHookCallbackFailed(hook.providingPlugin, revertReason);
}
/* solhint-enable no-empty-blocks */
unchecked {
++i;
}
}

// Initialize the plugin storage for the account.
// solhint-disable-next-line no-empty-blocks
try IPlugin(plugin).onInstall(pluginInitData) {}
catch (bytes memory revertReason) {
revert PluginInstallCallbackFailed(plugin, revertReason);
}

emit PluginInstalled(plugin, manifestHash, dependencies, injectedHooks);
emit PluginInstalled(plugin, manifestHash, dependencies);
}

function _uninstallPlugin(
address plugin,
PluginManifest memory manifest,
bytes memory uninstallData,
bytes[] calldata hookUnapplyData
) internal {
function _uninstallPlugin(address plugin, PluginManifest memory manifest, bytes memory uninstallData)
internal
{
AccountStorage storage _storage = getAccountStorage();

// Check if the plugin exists.
Expand Down Expand Up @@ -602,30 +490,6 @@ abstract contract PluginManagerInternals is IPluginManager {
// Remove components according to the manifest, in reverse order (by component type) of their installation.
// If any expected components are missing, revert.

length = manifest.permittedCallHooks.length;
for (uint256 i = 0; i < length;) {
_removePermittedCallHooks(
manifest.permittedCallHooks[i].executionSelector,
plugin,
_resolveManifestFunction(
manifest.permittedCallHooks[i].preExecHook,
plugin,
dependencies,
ManifestAssociatedFunctionType.PRE_HOOK_ALWAYS_DENY
),
_resolveManifestFunction(
manifest.permittedCallHooks[i].postExecHook,
plugin,
dependencies,
ManifestAssociatedFunctionType.NONE
)
);

unchecked {
++i;
}
}

length = manifest.executionHooks.length;
for (uint256 i = 0; i < length;) {
ManifestExecutionHook memory mh = manifest.executionHooks[i];
Expand Down Expand Up @@ -749,27 +613,6 @@ abstract contract PluginManagerInternals is IPluginManager {
}
}

length = _storage.pluginData[plugin].injectedHooks.length;
for (uint256 i = 0; i < length;) {
StoredInjectedHook memory hook = _storage.pluginData[plugin].injectedHooks[i];

// Decrement the dependent count for the plugin providing the hook.
_storage.pluginData[hook.providingPlugin].dependentCount -= 1;

_removePermittedCallHooks(
hook.selector,
plugin,
FunctionReferenceLib.pack(hook.providingPlugin, hook.preExecHookFunctionId),
hook.isPostHookUsed
? FunctionReferenceLib.pack(hook.providingPlugin, hook.postExecHookFunctionId)
: FunctionReferenceLib._EMPTY_FUNCTION_REFERENCE
);

unchecked {
++i;
}
}

length = manifest.permittedExecutionSelectors.length;
for (uint256 i = 0; i < length;) {
_disableExecFromPlugin(manifest.permittedExecutionSelectors[i], plugin, _storage);
Expand All @@ -796,34 +639,6 @@ abstract contract PluginManagerInternals is IPluginManager {
}
}

length = _storage.pluginData[plugin].injectedHooks.length;
bool hasUnapplyHookData = hookUnapplyData.length != 0;
if (hasUnapplyHookData && hookUnapplyData.length != length) {
revert ArrayLengthMismatch();
}

for (uint256 i = 0; i < length;) {
StoredInjectedHook memory hook = _storage.pluginData[plugin].injectedHooks[i];

/* solhint-disable no-empty-blocks */
try IPlugin(hook.providingPlugin).onHookUnapply(
plugin,
InjectedHooksInfo({
preExecHookFunctionId: hook.preExecHookFunctionId,
isPostHookUsed: hook.isPostHookUsed,
postExecHookFunctionId: hook.postExecHookFunctionId
}),
hasUnapplyHookData ? hookUnapplyData[i] : bytes("")
) {} catch (bytes memory revertReason) {
revert PluginUnapplyHookCallbackFailed(hook.providingPlugin, revertReason);
}
/* solhint-enable no-empty-blocks */

unchecked {
++i;
}
}

// Remove the plugin metadata from the account.
delete _storage.pluginData[plugin];

Expand Down
Loading