Skip to content

Commit

Permalink
feat: [v0.8-develop, experimental] Merge validation function assignme…
Browse files Browse the repository at this point in the history
…nts (#40)
  • Loading branch information
adam-alchemy authored Apr 15, 2024
1 parent d666f50 commit f6e335c
Show file tree
Hide file tree
Showing 26 changed files with 141 additions and 364 deletions.
4 changes: 1 addition & 3 deletions src/account/AccountLoupe.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,7 @@ abstract contract AccountLoupe is IAccountLoupe {
config.plugin = _storage.selectorData[selector].plugin;
}

config.userOpValidationFunction = _storage.selectorData[selector].userOpValidation;

config.runtimeValidationFunction = _storage.selectorData[selector].runtimeValidation;
config.validationFunction = _storage.selectorData[selector].validation;
}

/// @inheritdoc IAccountLoupe
Expand Down
4 changes: 2 additions & 2 deletions src/account/AccountStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ struct SelectorData {
// The plugin that implements this execution function.
// If this is a native function, the address must remain address(0).
address plugin;
FunctionReference userOpValidation;
FunctionReference runtimeValidation;
// User operation validation and runtime validation share a function reference.
FunctionReference validation;
// The pre validation hooks for this function selector.
EnumerableMap.Bytes32ToUintMap preUserOpValidationHooks;
EnumerableMap.Bytes32ToUintMap preRuntimeValidationHooks;
Expand Down
79 changes: 13 additions & 66 deletions src/account/PluginManagerInternals.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ abstract contract PluginManagerInternals is IPluginManager {
error PluginInstallCallbackFailed(address plugin, bytes revertReason);
error PluginInterfaceNotSupported(address plugin);
error PluginNotInstalled(address plugin);
error RuntimeValidationFunctionAlreadySet(bytes4 selector, FunctionReference validationFunction);
error UserOpValidationFunctionAlreadySet(bytes4 selector, FunctionReference validationFunction);
error ValidationFunctionAlreadySet(bytes4 selector, FunctionReference validationFunction);

modifier notNullFunction(FunctionReference functionReference) {
if (functionReference.isEmpty()) {
Expand Down Expand Up @@ -76,48 +75,26 @@ abstract contract PluginManagerInternals is IPluginManager {
_selectorData.plugin = address(0);
}

function _addUserOpValidationFunction(bytes4 selector, FunctionReference validationFunction)
function _addValidationFunction(bytes4 selector, FunctionReference validationFunction)
internal
notNullFunction(validationFunction)
{
SelectorData storage _selectorData = getAccountStorage().selectorData[selector];

if (!_selectorData.userOpValidation.isEmpty()) {
revert UserOpValidationFunctionAlreadySet(selector, validationFunction);
if (!_selectorData.validation.isEmpty()) {
revert ValidationFunctionAlreadySet(selector, validationFunction);
}

_selectorData.userOpValidation = validationFunction;
_selectorData.validation = validationFunction;
}

function _removeUserOpValidationFunction(bytes4 selector, FunctionReference validationFunction)
function _removeValidationFunction(bytes4 selector, FunctionReference validationFunction)
internal
notNullFunction(validationFunction)
{
SelectorData storage _selectorData = getAccountStorage().selectorData[selector];

_selectorData.userOpValidation = FunctionReferenceLib._EMPTY_FUNCTION_REFERENCE;
}

function _addRuntimeValidationFunction(bytes4 selector, FunctionReference validationFunction)
internal
notNullFunction(validationFunction)
{
SelectorData storage _selectorData = getAccountStorage().selectorData[selector];

if (!_selectorData.runtimeValidation.isEmpty()) {
revert RuntimeValidationFunctionAlreadySet(selector, validationFunction);
}

_selectorData.runtimeValidation = validationFunction;
}

function _removeRuntimeValidationFunction(bytes4 selector, FunctionReference validationFunction)
internal
notNullFunction(validationFunction)
{
SelectorData storage _selectorData = getAccountStorage().selectorData[selector];

_selectorData.runtimeValidation = FunctionReferenceLib._EMPTY_FUNCTION_REFERENCE;
_selectorData.validation = FunctionReferenceLib._EMPTY_FUNCTION_REFERENCE;
}

function _addExecHooks(bytes4 selector, FunctionReference preExecHook, FunctionReference postExecHook)
Expand Down Expand Up @@ -319,25 +296,10 @@ abstract contract PluginManagerInternals is IPluginManager {
}
}

length = manifest.userOpValidationFunctions.length;
for (uint256 i = 0; i < length;) {
ManifestAssociatedFunction memory mv = manifest.userOpValidationFunctions[i];
_addUserOpValidationFunction(
mv.executionSelector,
_resolveManifestFunction(
mv.associatedFunction, plugin, dependencies, ManifestAssociatedFunctionType.NONE
)
);

unchecked {
++i;
}
}

length = manifest.runtimeValidationFunctions.length;
length = manifest.validationFunctions.length;
for (uint256 i = 0; i < length;) {
ManifestAssociatedFunction memory mv = manifest.runtimeValidationFunctions[i];
_addRuntimeValidationFunction(
ManifestAssociatedFunction memory mv = manifest.validationFunctions[i];
_addValidationFunction(
mv.executionSelector,
_resolveManifestFunction(
mv.associatedFunction,
Expand Down Expand Up @@ -521,10 +483,10 @@ abstract contract PluginManagerInternals is IPluginManager {
}
}

length = manifest.runtimeValidationFunctions.length;
length = manifest.validationFunctions.length;
for (uint256 i = 0; i < length;) {
ManifestAssociatedFunction memory mv = manifest.runtimeValidationFunctions[i];
_removeRuntimeValidationFunction(
ManifestAssociatedFunction memory mv = manifest.validationFunctions[i];
_removeValidationFunction(
mv.executionSelector,
_resolveManifestFunction(
mv.associatedFunction,
Expand All @@ -539,21 +501,6 @@ abstract contract PluginManagerInternals is IPluginManager {
}
}

length = manifest.userOpValidationFunctions.length;
for (uint256 i = 0; i < length;) {
ManifestAssociatedFunction memory mv = manifest.userOpValidationFunctions[i];
_removeUserOpValidationFunction(
mv.executionSelector,
_resolveManifestFunction(
mv.associatedFunction, plugin, dependencies, ManifestAssociatedFunctionType.NONE
)
);

unchecked {
++i;
}
}

// remove external call permissions

if (manifest.permitAnyExternalAddress) {
Expand Down
7 changes: 4 additions & 3 deletions src/account/UpgradeableModularAccount.sol
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ contract UpgradeableModularAccount is
}
bytes4 selector = bytes4(userOp.callData);

FunctionReference userOpValidationFunction = getAccountStorage().selectorData[selector].userOpValidation;
FunctionReference userOpValidationFunction = getAccountStorage().selectorData[selector].validation;

validationData = _doUserOpValidation(selector, userOpValidationFunction, userOp, userOpHash);
}
Expand Down Expand Up @@ -395,7 +395,8 @@ contract UpgradeableModularAccount is
validationData = currentValidationData;
}
} else {
// _RUNTIME_VALIDATION_ALWAYS_ALLOW and _PRE_HOOK_ALWAYS_DENY is not permitted here.
// _PRE_HOOK_ALWAYS_DENY is not permitted here.
// If this is _RUNTIME_VALIDATION_ALWAYS_ALLOW, the call should revert.
revert InvalidConfiguration();
}
}
Expand All @@ -405,7 +406,7 @@ contract UpgradeableModularAccount is
if (msg.sender == address(_ENTRY_POINT)) return;

AccountStorage storage _storage = getAccountStorage();
FunctionReference runtimeValidationFunction = _storage.selectorData[msg.sig].runtimeValidation;
FunctionReference runtimeValidationFunction = _storage.selectorData[msg.sig].validation;
// run all preRuntimeValidation hooks
EnumerableMap.Bytes32ToUintMap storage preRuntimeValidationHooks =
getAccountStorage().selectorData[msg.sig].preRuntimeValidationHooks;
Expand Down
3 changes: 1 addition & 2 deletions src/interfaces/IAccountLoupe.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ interface IAccountLoupe {
/// @notice Config for an execution function, given a selector.
struct ExecutionFunctionConfig {
address plugin;
FunctionReference userOpValidationFunction;
FunctionReference runtimeValidationFunction;
FunctionReference validationFunction;
}

/// @notice Pre and post hooks for a given selector.
Expand Down
3 changes: 1 addition & 2 deletions src/interfaces/IPlugin.sol
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,7 @@ struct PluginManifest {
// plugin MUST still be able to spend up to the balance that it sends to the account in the same call.
bool canSpendNativeToken;
ManifestExternalCallPermission[] permittedExternalCalls;
ManifestAssociatedFunction[] userOpValidationFunctions;
ManifestAssociatedFunction[] runtimeValidationFunctions;
ManifestAssociatedFunction[] validationFunctions;
ManifestAssociatedFunction[] preUserOpValidationHooks;
ManifestAssociatedFunction[] preRuntimeValidationHooks;
ManifestExecutionHook[] executionHooks;
Expand Down
20 changes: 10 additions & 10 deletions src/plugins/TokenReceiverPlugin.sol
Original file line number Diff line number Diff line change
Expand Up @@ -79,27 +79,27 @@ contract TokenReceiverPlugin is BasePlugin, IERC721Receiver, IERC777Recipient, I
manifest.executionFunctions[3] = this.onERC1155BatchReceived.selector;

// Only runtime validationFunction is needed since callbacks come from token contracts only
ManifestFunction memory alwaysAllowFunction = ManifestFunction({
ManifestFunction memory alwaysAllowRuntime = ManifestFunction({
functionType: ManifestAssociatedFunctionType.RUNTIME_VALIDATION_ALWAYS_ALLOW,
functionId: 0, // Unused.
dependencyIndex: 0 // Unused.
});
manifest.runtimeValidationFunctions = new ManifestAssociatedFunction[](4);
manifest.runtimeValidationFunctions[0] = ManifestAssociatedFunction({
manifest.validationFunctions = new ManifestAssociatedFunction[](4);
manifest.validationFunctions[0] = ManifestAssociatedFunction({
executionSelector: this.tokensReceived.selector,
associatedFunction: alwaysAllowFunction
associatedFunction: alwaysAllowRuntime
});
manifest.runtimeValidationFunctions[1] = ManifestAssociatedFunction({
manifest.validationFunctions[1] = ManifestAssociatedFunction({
executionSelector: this.onERC721Received.selector,
associatedFunction: alwaysAllowFunction
associatedFunction: alwaysAllowRuntime
});
manifest.runtimeValidationFunctions[2] = ManifestAssociatedFunction({
manifest.validationFunctions[2] = ManifestAssociatedFunction({
executionSelector: this.onERC1155Received.selector,
associatedFunction: alwaysAllowFunction
associatedFunction: alwaysAllowRuntime
});
manifest.runtimeValidationFunctions[3] = ManifestAssociatedFunction({
manifest.validationFunctions[3] = ManifestAssociatedFunction({
executionSelector: this.onERC1155BatchReceived.selector,
associatedFunction: alwaysAllowFunction
associatedFunction: alwaysAllowRuntime
});

manifest.interfaceIds = new bytes4[](3);
Expand Down
3 changes: 1 addition & 2 deletions src/plugins/owner/ISingleOwnerPlugin.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import {UserOperation} from "@eth-infinitism/account-abstraction/interfaces/User

interface ISingleOwnerPlugin {
enum FunctionId {
RUNTIME_VALIDATION_OWNER_OR_SELF,
USER_OP_VALIDATION_OWNER
VALIDATION_OWNER_OR_SELF
}

/// @notice This event is emitted when ownership of the account changes.
Expand Down
82 changes: 22 additions & 60 deletions src/plugins/owner/SingleOwnerPlugin.sol
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ contract SingleOwnerPlugin is BasePlugin, ISingleOwnerPlugin, IERC1271 {
view
override
{
if (functionId == uint8(FunctionId.RUNTIME_VALIDATION_OWNER_OR_SELF)) {
if (functionId == uint8(FunctionId.VALIDATION_OWNER_OR_SELF)) {
// Validate that the sender is the owner of the account or self.
if (sender != _owners[msg.sender] && sender != msg.sender) {
revert NotAuthorized();
Expand All @@ -125,7 +125,7 @@ contract SingleOwnerPlugin is BasePlugin, ISingleOwnerPlugin, IERC1271 {
override
returns (uint256)
{
if (functionId == uint8(FunctionId.USER_OP_VALIDATION_OWNER)) {
if (functionId == uint8(FunctionId.VALIDATION_OWNER_OR_SELF)) {
// Validate the user op signature against the owner.
(address signer,) = (userOpHash.toEthSignedMessageHash()).tryRecover(userOp.signature);
if (signer == address(0) || signer != _owners[msg.sender]) {
Expand All @@ -145,87 +145,49 @@ contract SingleOwnerPlugin is BasePlugin, ISingleOwnerPlugin, IERC1271 {
manifest.executionFunctions[1] = this.isValidSignature.selector;
manifest.executionFunctions[2] = this.owner.selector;

ManifestFunction memory ownerUserOpValidationFunction = ManifestFunction({
ManifestFunction memory ownerValidationFunction = ManifestFunction({
functionType: ManifestAssociatedFunctionType.SELF,
functionId: uint8(FunctionId.USER_OP_VALIDATION_OWNER),
functionId: uint8(FunctionId.VALIDATION_OWNER_OR_SELF),
dependencyIndex: 0 // Unused.
});
manifest.userOpValidationFunctions = new ManifestAssociatedFunction[](7);
manifest.userOpValidationFunctions[0] = ManifestAssociatedFunction({
manifest.validationFunctions = new ManifestAssociatedFunction[](8);
manifest.validationFunctions[0] = ManifestAssociatedFunction({
executionSelector: this.transferOwnership.selector,
associatedFunction: ownerUserOpValidationFunction
associatedFunction: ownerValidationFunction
});
manifest.userOpValidationFunctions[1] = ManifestAssociatedFunction({
manifest.validationFunctions[1] = ManifestAssociatedFunction({
executionSelector: IStandardExecutor.execute.selector,
associatedFunction: ownerUserOpValidationFunction
associatedFunction: ownerValidationFunction
});
manifest.userOpValidationFunctions[2] = ManifestAssociatedFunction({
manifest.validationFunctions[2] = ManifestAssociatedFunction({
executionSelector: IStandardExecutor.executeBatch.selector,
associatedFunction: ownerUserOpValidationFunction
associatedFunction: ownerValidationFunction
});
manifest.userOpValidationFunctions[3] = ManifestAssociatedFunction({
manifest.validationFunctions[3] = ManifestAssociatedFunction({
executionSelector: IPluginManager.installPlugin.selector,
associatedFunction: ownerUserOpValidationFunction
associatedFunction: ownerValidationFunction
});
manifest.userOpValidationFunctions[4] = ManifestAssociatedFunction({
manifest.validationFunctions[4] = ManifestAssociatedFunction({
executionSelector: IPluginManager.uninstallPlugin.selector,
associatedFunction: ownerUserOpValidationFunction
associatedFunction: ownerValidationFunction
});
manifest.userOpValidationFunctions[5] = ManifestAssociatedFunction({
manifest.validationFunctions[5] = ManifestAssociatedFunction({
executionSelector: UUPSUpgradeable.upgradeTo.selector,
associatedFunction: ownerUserOpValidationFunction
associatedFunction: ownerValidationFunction
});
manifest.userOpValidationFunctions[6] = ManifestAssociatedFunction({
manifest.validationFunctions[6] = ManifestAssociatedFunction({
executionSelector: UUPSUpgradeable.upgradeToAndCall.selector,
associatedFunction: ownerUserOpValidationFunction
associatedFunction: ownerValidationFunction
});

ManifestFunction memory ownerOrSelfRuntimeValidationFunction = ManifestFunction({
functionType: ManifestAssociatedFunctionType.SELF,
functionId: uint8(FunctionId.RUNTIME_VALIDATION_OWNER_OR_SELF),
dependencyIndex: 0 // Unused.
});
ManifestFunction memory alwaysAllowFunction = ManifestFunction({
ManifestFunction memory alwaysAllowRuntime = ManifestFunction({
functionType: ManifestAssociatedFunctionType.RUNTIME_VALIDATION_ALWAYS_ALLOW,
functionId: 0, // Unused.
dependencyIndex: 0 // Unused.
});
manifest.runtimeValidationFunctions = new ManifestAssociatedFunction[](9);
manifest.runtimeValidationFunctions[0] = ManifestAssociatedFunction({
executionSelector: this.transferOwnership.selector,
associatedFunction: ownerOrSelfRuntimeValidationFunction
});
manifest.runtimeValidationFunctions[1] = ManifestAssociatedFunction({
executionSelector: this.owner.selector,
associatedFunction: alwaysAllowFunction
});
manifest.runtimeValidationFunctions[2] = ManifestAssociatedFunction({
executionSelector: IStandardExecutor.execute.selector,
associatedFunction: ownerOrSelfRuntimeValidationFunction
});
manifest.runtimeValidationFunctions[3] = ManifestAssociatedFunction({
executionSelector: IStandardExecutor.executeBatch.selector,
associatedFunction: ownerOrSelfRuntimeValidationFunction
});
manifest.runtimeValidationFunctions[4] = ManifestAssociatedFunction({
executionSelector: IPluginManager.installPlugin.selector,
associatedFunction: ownerOrSelfRuntimeValidationFunction
});
manifest.runtimeValidationFunctions[5] = ManifestAssociatedFunction({
executionSelector: IPluginManager.uninstallPlugin.selector,
associatedFunction: ownerOrSelfRuntimeValidationFunction
});
manifest.runtimeValidationFunctions[6] = ManifestAssociatedFunction({
executionSelector: UUPSUpgradeable.upgradeTo.selector,
associatedFunction: ownerOrSelfRuntimeValidationFunction
});
manifest.runtimeValidationFunctions[7] = ManifestAssociatedFunction({
executionSelector: UUPSUpgradeable.upgradeToAndCall.selector,
associatedFunction: ownerOrSelfRuntimeValidationFunction
});
manifest.runtimeValidationFunctions[8] = ManifestAssociatedFunction({
manifest.validationFunctions[7] = ManifestAssociatedFunction({
executionSelector: this.isValidSignature.selector,
associatedFunction: alwaysAllowFunction
associatedFunction: alwaysAllowRuntime
});

return manifest;
Expand Down
Loading

0 comments on commit f6e335c

Please sign in to comment.