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
15 changes: 9 additions & 6 deletions src/account/UpgradeableModularAccount.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet
import {FunctionReferenceLib} from "../helpers/FunctionReferenceLib.sol";
import {_coalescePreValidation, _coalesceValidation} from "../helpers/ValidationDataHelpers.sol";
import {IPlugin, PluginManifest} from "../interfaces/IPlugin.sol";
import {IValidation} from "../interfaces/IValidation.sol";
import {IValidationHook} from "../interfaces/IValidationHook.sol";
import {IExecutionHook} from "../interfaces/IExecutionHook.sol";
import {IPluginExecutor} from "../interfaces/IPluginExecutor.sol";
import {FunctionReference, IPluginManager} from "../interfaces/IPluginManager.sol";
import {IStandardExecutor, Call} from "../interfaces/IStandardExecutor.sol";
Expand Down Expand Up @@ -364,7 +367,7 @@ contract UpgradeableModularAccount is
FunctionReference preUserOpValidationHook = toFunctionReference(key);

(address plugin, uint8 functionId) = preUserOpValidationHook.unpack();
currentValidationData = IPlugin(plugin).preUserOpValidationHook(functionId, userOp, userOpHash);
currentValidationData = IValidationHook(plugin).preUserOpValidationHook(functionId, userOp, userOpHash);

if (uint160(currentValidationData) > 1) {
// If the aggregator is not 0 or 1, it is an unexpected value
Expand All @@ -376,7 +379,7 @@ contract UpgradeableModularAccount is
// Run the user op validationFunction
{
(address plugin, uint8 functionId) = userOpValidationFunction.unpack();
currentValidationData = IPlugin(plugin).userOpValidationFunction(functionId, userOp, userOpHash);
currentValidationData = IValidation(plugin).validateUserOp(functionId, userOp, userOpHash);

if (preUserOpValidationHooksLength != 0) {
// If we have other validation data we need to coalesce with
Expand Down Expand Up @@ -408,7 +411,7 @@ contract UpgradeableModularAccount is

(address plugin, uint8 functionId) = preRuntimeValidationHook.unpack();
// solhint-disable-next-line no-empty-blocks
try IPlugin(plugin).preRuntimeValidationHook(functionId, msg.sender, msg.value, msg.data) {}
try IValidationHook(plugin).preRuntimeValidationHook(functionId, msg.sender, msg.value, msg.data) {}
catch (bytes memory revertReason) {
revert PreRuntimeValidationHookFailed(plugin, functionId, revertReason);
}
Expand All @@ -419,7 +422,7 @@ contract UpgradeableModularAccount is
if (!runtimeValidationFunction.isEmptyOrMagicValue()) {
(address plugin, uint8 functionId) = runtimeValidationFunction.unpack();
// solhint-disable-next-line no-empty-blocks
try IPlugin(plugin).runtimeValidationFunction(functionId, msg.sender, msg.value, msg.data) {}
try IValidation(plugin).validateRuntime(functionId, msg.sender, msg.value, msg.data) {}
catch (bytes memory revertReason) {
revert RuntimeValidationFunctionReverted(plugin, functionId, revertReason);
}
Expand Down Expand Up @@ -475,7 +478,7 @@ contract UpgradeableModularAccount is
returns (bytes memory preExecHookReturnData)
{
(address plugin, uint8 functionId) = preExecHook.unpack();
try IPlugin(plugin).preExecutionHook(functionId, msg.sender, msg.value, data) returns (
try IExecutionHook(plugin).preExecutionHook(functionId, msg.sender, msg.value, data) returns (
bytes memory returnData
) {
preExecHookReturnData = returnData;
Expand All @@ -500,7 +503,7 @@ contract UpgradeableModularAccount is

(address plugin, uint8 functionId) = postHookToRun.postExecHook.unpack();
// solhint-disable-next-line no-empty-blocks
try IPlugin(plugin).postExecutionHook(functionId, postHookToRun.preExecHookReturnData) {}
try IExecutionHook(plugin).postExecutionHook(functionId, postHookToRun.preExecHookReturnData) {}
catch (bytes memory revertReason) {
revert PostExecHookReverted(plugin, functionId, revertReason);
}
Expand Down
25 changes: 25 additions & 0 deletions src/interfaces/IExecutionHook.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.25;

import {IPlugin} from "./IPlugin.sol";

interface IExecutionHook is IPlugin {
/// @notice Run the pre execution hook specified by the `functionId`.
/// @dev To indicate the entire call should revert, the function MUST revert.
/// @param functionId An identifier that routes the call to different internal implementations, should there be
/// more than one.
/// @param sender The caller address.
/// @param value The call value.
/// @param data The calldata sent.
/// @return Context to pass to a post execution hook, if present. An empty bytes array MAY be returned.
function preExecutionHook(uint8 functionId, address sender, uint256 value, bytes calldata data)
external
returns (bytes memory);

/// @notice Run the post execution hook specified by the `functionId`.
/// @dev To indicate the entire call should revert, the function MUST revert.
/// @param functionId An identifier that routes the call to different internal implementations, should there be
/// more than one.
/// @param preExecHookData The context returned by its associated pre execution hook.
function postExecutionHook(uint8 functionId, bytes calldata preExecHookData) external;
}
64 changes: 2 additions & 62 deletions src/interfaces/IPlugin.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.25;

import {PackedUserOperation} from "@eth-infinitism/account-abstraction/interfaces/PackedUserOperation.sol";
import {IERC165} from "@openzeppelin/contracts/interfaces/IERC165.sol";

// Forge formatter will displace the first comment for the enum field out of the enum itself,
// so annotating here to prevent that.
Expand Down Expand Up @@ -96,7 +96,7 @@ struct PluginManifest {
ManifestExecutionHook[] executionHooks;
}

interface IPlugin {
interface IPlugin is IERC165 {
/// @notice Initialize plugin data for the modular account.
/// @dev Called by the modular account during `installPlugin`.
/// @param data Optional bytes array to be decoded and used by the plugin to setup initial plugin data for the
Expand All @@ -109,66 +109,6 @@ interface IPlugin {
/// account.
function onUninstall(bytes calldata data) external;

/// @notice Run the pre user operation validation hook specified by the `functionId`.
/// @dev Pre user operation validation hooks MUST NOT return an authorizer value other than 0 or 1.
/// @param functionId An identifier that routes the call to different internal implementations, should there be
/// more than one.
/// @param userOp The user operation.
/// @param userOpHash The user operation hash.
/// @return Packed validation data for validAfter (6 bytes), validUntil (6 bytes), and authorizer (20 bytes).
function preUserOpValidationHook(uint8 functionId, PackedUserOperation calldata userOp, bytes32 userOpHash)
external
returns (uint256);

/// @notice Run the user operation validationFunction specified by the `functionId`.
/// @param functionId An identifier that routes the call to different internal implementations, should there be
/// more than one.
/// @param userOp The user operation.
/// @param userOpHash The user operation hash.
/// @return Packed validation data for validAfter (6 bytes), validUntil (6 bytes), and authorizer (20 bytes).
function userOpValidationFunction(uint8 functionId, PackedUserOperation calldata userOp, bytes32 userOpHash)
external
returns (uint256);

/// @notice Run the pre runtime validation hook specified by the `functionId`.
/// @dev To indicate the entire call should revert, the function MUST revert.
/// @param functionId An identifier that routes the call to different internal implementations, should there be
/// more than one.
/// @param sender The caller address.
/// @param value The call value.
/// @param data The calldata sent.
function preRuntimeValidationHook(uint8 functionId, address sender, uint256 value, bytes calldata data)
external;

/// @notice Run the runtime validationFunction specified by the `functionId`.
/// @dev To indicate the entire call should revert, the function MUST revert.
/// @param functionId An identifier that routes the call to different internal implementations, should there be
/// more than one.
/// @param sender The caller address.
/// @param value The call value.
/// @param data The calldata sent.
function runtimeValidationFunction(uint8 functionId, address sender, uint256 value, bytes calldata data)
external;

/// @notice Run the pre execution hook specified by the `functionId`.
/// @dev To indicate the entire call should revert, the function MUST revert.
/// @param functionId An identifier that routes the call to different internal implementations, should there be
/// more than one.
/// @param sender The caller address.
/// @param value The call value.
/// @param data The calldata sent.
/// @return Context to pass to a post execution hook, if present. An empty bytes array MAY be returned.
function preExecutionHook(uint8 functionId, address sender, uint256 value, bytes calldata data)
external
returns (bytes memory);

/// @notice Run the post execution hook specified by the `functionId`.
/// @dev To indicate the entire call should revert, the function MUST revert.
/// @param functionId An identifier that routes the call to different internal implementations, should there be
/// more than one.
/// @param preExecHookData The context returned by its associated pre execution hook.
function postExecutionHook(uint8 functionId, bytes calldata preExecHookData) external;

/// @notice Describe the contents and intended configuration of the plugin.
/// @dev This manifest MUST stay constant over time.
/// @return A manifest describing the contents and intended configuration of the plugin.
Expand Down
27 changes: 27 additions & 0 deletions src/interfaces/IValidation.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.25;

import {PackedUserOperation} from "@eth-infinitism/account-abstraction/interfaces/PackedUserOperation.sol";

import {IPlugin} from "./IPlugin.sol";

interface IValidation is IPlugin {
/// @notice Run the user operation validationFunction specified by the `functionId`.
/// @param functionId An identifier that routes the call to different internal implementations, should there be
/// more than one.
/// @param userOp The user operation.
/// @param userOpHash The user operation hash.
/// @return Packed validation data for validAfter (6 bytes), validUntil (6 bytes), and authorizer (20 bytes).
function validateUserOp(uint8 functionId, PackedUserOperation calldata userOp, bytes32 userOpHash)
external
returns (uint256);

/// @notice Run the runtime validationFunction specified by the `functionId`.
/// @dev To indicate the entire call should revert, the function MUST revert.
/// @param functionId An identifier that routes the call to different internal implementations, should there be
/// more than one.
/// @param sender The caller address.
/// @param value The call value.
/// @param data The calldata sent.
function validateRuntime(uint8 functionId, address sender, uint256 value, bytes calldata data) external;
}
29 changes: 29 additions & 0 deletions src/interfaces/IValidationHook.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.25;

import {PackedUserOperation} from "@eth-infinitism/account-abstraction/interfaces/PackedUserOperation.sol";

import {IPlugin} from "./IPlugin.sol";

interface IValidationHook is IPlugin {
/// @notice Run the pre user operation validation hook specified by the `functionId`.
/// @dev Pre user operation validation hooks MUST NOT return an authorizer value other than 0 or 1.
/// @param functionId An identifier that routes the call to different internal implementations, should there be
/// more than one.
/// @param userOp The user operation.
/// @param userOpHash The user operation hash.
/// @return Packed validation data for validAfter (6 bytes), validUntil (6 bytes), and authorizer (20 bytes).
function preUserOpValidationHook(uint8 functionId, PackedUserOperation calldata userOp, bytes32 userOpHash)
external
returns (uint256);

/// @notice Run the pre runtime validation hook specified by the `functionId`.
/// @dev To indicate the entire call should revert, the function MUST revert.
/// @param functionId An identifier that routes the call to different internal implementations, should there be
/// more than one.
/// @param sender The caller address.
/// @param value The call value.
/// @param data The calldata sent.
function preRuntimeValidationHook(uint8 functionId, address sender, uint256 value, bytes calldata data)
external;
}
125 changes: 3 additions & 122 deletions src/plugins/BasePlugin.sol
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.25;

import {PackedUserOperation} from "@eth-infinitism/account-abstraction/interfaces/PackedUserOperation.sol";
import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import {ERC165, IERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";

import {IPlugin, PluginManifest, PluginMetadata} from "../interfaces/IPlugin.sol";
import {IPlugin} from "../interfaces/IPlugin.sol";

/// @title Base contract for plugins
/// @dev Implements ERC-165 to support IPlugin's interface, which is a requirement
Expand All @@ -13,124 +12,6 @@ import {IPlugin, PluginManifest, PluginMetadata} from "../interfaces/IPlugin.sol
abstract contract BasePlugin is ERC165, IPlugin {
error NotImplemented();

/// @notice Initialize plugin data for the modular account.
/// @dev Called by the modular account during `installPlugin`.
/// @param data Optional bytes array to be decoded and used by the plugin to setup initial plugin data for the
/// modular account.
function onInstall(bytes calldata data) external virtual {
(data);
revert NotImplemented();
}

/// @notice Clear plugin data for the modular account.
/// @dev Called by the modular account during `uninstallPlugin`.
/// @param data Optional bytes array to be decoded and used by the plugin to clear plugin data for the modular
/// account.
function onUninstall(bytes calldata data) external virtual {
(data);
revert NotImplemented();
}

/// @notice Run the pre user operation validation hook specified by the `functionId`.
/// @dev Pre user operation validation hooks MUST NOT return an authorizer value other than 0 or 1.
/// @param functionId An identifier that routes the call to different internal implementations, should there be
/// more than one.
/// @param userOp The user operation.
/// @param userOpHash The user operation hash.
/// @return Packed validation data for validAfter (6 bytes), validUntil (6 bytes), and authorizer (20 bytes).
function preUserOpValidationHook(uint8 functionId, PackedUserOperation calldata userOp, bytes32 userOpHash)
external
virtual
returns (uint256)
{
(functionId, userOp, userOpHash);
revert NotImplemented();
}

/// @notice Run the user operation validationFunction specified by the `functionId`.
/// @param functionId An identifier that routes the call to different internal implementations, should there be
/// more than one.
/// @param userOp The user operation.
/// @param userOpHash The user operation hash.
/// @return Packed validation data for validAfter (6 bytes), validUntil (6 bytes), and authorizer (20 bytes).
function userOpValidationFunction(uint8 functionId, PackedUserOperation calldata userOp, bytes32 userOpHash)
external
virtual
returns (uint256)
{
(functionId, userOp, userOpHash);
revert NotImplemented();
}

/// @notice Run the pre runtime validation hook specified by the `functionId`.
/// @dev To indicate the entire call should revert, the function MUST revert.
/// @param functionId An identifier that routes the call to different internal implementations, should there be
/// more than one.
/// @param sender The caller address.
/// @param value The call value.
/// @param data The calldata sent.
function preRuntimeValidationHook(uint8 functionId, address sender, uint256 value, bytes calldata data)
external
virtual
{
(functionId, sender, value, data);
revert NotImplemented();
}

/// @notice Run the runtime validationFunction specified by the `functionId`.
/// @dev To indicate the entire call should revert, the function MUST revert.
/// @param functionId An identifier that routes the call to different internal implementations, should there be
/// more than one.
/// @param sender The caller address.
/// @param value The call value.
/// @param data The calldata sent.
function runtimeValidationFunction(uint8 functionId, address sender, uint256 value, bytes calldata data)
external
virtual
{
(functionId, sender, value, data);
revert NotImplemented();
}

/// @notice Run the pre execution hook specified by the `functionId`.
/// @dev To indicate the entire call should revert, the function MUST revert.
/// @param functionId An identifier that routes the call to different internal implementations, should there be
/// more than one.
/// @param sender The caller address.
/// @param value The call value.
/// @param data The calldata sent.
/// @return Context to pass to a post execution hook, if present. An empty bytes array MAY be returned.
function preExecutionHook(uint8 functionId, address sender, uint256 value, bytes calldata data)
external
virtual
returns (bytes memory)
{
(functionId, sender, value, data);
revert NotImplemented();
}

/// @notice Run the post execution hook specified by the `functionId`.
/// @dev To indicate the entire call should revert, the function MUST revert.
/// @param functionId An identifier that routes the call to different internal implementations, should there be
/// more than one.
/// @param preExecHookData The context returned by its associated pre execution hook.
function postExecutionHook(uint8 functionId, bytes calldata preExecHookData) external virtual {
(functionId, preExecHookData);
revert NotImplemented();
}

/// @notice Describe the contents and intended configuration of the plugin.
/// @dev This manifest MUST stay constant over time.
/// @return A manifest describing the contents and intended configuration of the plugin.
function pluginManifest() external pure virtual returns (PluginManifest memory) {
revert NotImplemented();
}

/// @notice Describe the metadata of the plugin.
/// @dev This metadata MUST stay constant over time.
/// @return A metadata struct describing the plugin.
function pluginMetadata() external pure virtual returns (PluginMetadata memory);

/// @dev Returns true if this contract implements the interface defined by
/// `interfaceId`. See the corresponding
/// https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
Expand All @@ -143,7 +24,7 @@ abstract contract BasePlugin is ERC165, IPlugin {
/// making calls to plugins.
/// @param interfaceId The interface ID to check for support.
/// @return True if the contract supports `interfaceId`.
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return interfaceId == type(IPlugin).interfaceId || super.supportsInterface(interfaceId);
}
}
Loading