What do you mean by “transaction validity switching”? Is this a security concern the ERC-7521 validation function would run into too?
I’m referring to what I tried to explain previously here: ERC-6900: Modular Smart Contract Accounts and Plugins - #33 by adamegyed
An ERC-6900 modular account maintains a mapping from function selector → plugin address for execution functions. For validation functions, it also maintains this mapping, even though they all go through the single external function validateUserOp
. So, to “switch” which validation function to actually run during the call to validateUserOp
, it decodes the function selector from the first 4 bytes of userOp.callData
, then does a mapping lookup, then runs the validation function.
If validateUserOp
were itself implemented as a plugin’s execution function, it could work. However, it would then run into a problem, having to pick 1 of these 2 options:
- The plugin implements
validateUserOp
with a single “logical” validation function, like checking an owner’s ECDSA signature.- This limits the flexibility of modular accounts.
- The plugin itself has to re-implement modularity and do the same type of switching as what the account currently does.
- This makes it harder to do account management and to enforce consistency guarantees.
So, to avoid either of these options, we chose to make validateUserOp
a native account function with switching. But like you said, this also limits flexibility for other validity functions. So, I’m currently trying to find a way to possibly genericize the switching process to be able to apply it to other functions as well.
Hope this can be helpful, and let me know if there’s something else I can clarify.
So it’s thought that wallets will want different validation logic based on the calldata of the userOp? I’m confused because the reference implementation for 4337 has an example wallet that always uses the same validation logic. I’m also confused because the first 4 bytes of a userOp will almost always be the same (again, in the 4337 reference implementation , userOps are almost always calling the wallets “execute” of “executeBatch” function).
the reference implementation for 4337 has an example wallet that always uses the same validation logic.
The example wallet from reference 4337 implementation is not meant to be Modular. It is just a SimpleAccount(.sol).
the first 4 bytes of a userOp will almost always be the same
Yes, it can be like this. However, in 6900 it is expected that there will be plenty of execution methods called on MSCA and then forwarded by the fallback function to the plug-in which contains the implementation of this method. So, the first 4 bytes of userOp.callData
can be different from execute
or executeBatch
selector.
Has the team heard of a fancy use case where signature verification depends on the calldata?
Also, I can’t really see use cases for wanting to hit a function other than execute
or executeBatch
. Granted, those functions wouldn’t be able to do script like things that need memory, but that could be solved with executeDelegate
and executeDelegateBatch
calls. I would say that’s actually preferable to the alternative of requiring a user to install some script function to their wallet. The user can just elect to use scripts (via a delegate call) at sign time instead.
fancy use case where signature verification depends on the calldata
For example, if there is a method performRecurringPayment(...)
in the plugin,
This method can be called by anyone and we do not even need MSCA’s owner sig to validate such an userOp.
So if the userOp.callData[0:4]
is performRecurringPayment.selector
we want not just some other signature verification algorithm, but no signature verification at all. In this case validation function will verify has the period passed or not and maybe something else.
btw, I’m not a part of the 6900 team. They could have better use case examples.
I think IPluginManager.installPlugin
and IPluginManager.uninstallPlugin
are not enough for the ERC-6900 spec.
Consider this situation, if an account has only one plugin. At the same time, this plugin is responsible for selector IPluginManager.installPlugin
.
If I want to switch to a new plugin. Maybe I should uninstall the old plugin (IPluginManager. uninstallPlugin
) and install the new plugin (IPluginManager.installPlugin
).
Uninstalling the old plugin is fine. However, I cannot install new plugin through IPluginManager.installPlugin
for there is no plugin responsible for the selector IPluginManager.installPlugin
after uninstalling the old plugin.
I think maybe we can unify the interfaces like this.
function updatePlugin(
UninstallPluginParams pluginToUninstall
InstallPluginParams pluginToInstall,
)
If pluginToUninstall
is empty, just install pluginToInstall
.
If pluginToUninstall
is not empty, uninstall pluginToUninstall
first and then install pluginToInstall
.
[details=“Summary”]
This text will be hidden
[/details[quote=“cejay, post:15, topic:13885, full:true”]
“EIP: Modular Smart Contract Accounts and Plugins” is generally feasible!
But I think there are several points that may need attention:
-
add/remove Hook plugins may need to be divided into two parts:
For example: 1. add plugin → 2. wait for a security time delay (e.g. 48 hours) → 3. user confirms that the plugin has been added.At least the implementation in soulwallet is like this, this is mainly for security reasons, for full context see the previous discussion with the author of ‘EIP-2535 Diamonds’ mudgen at here . So for us only PluginAdd function is not enough, at least a PluginPreAdd similar process is needed, and this process for monitoring purposes, will also emit event -
validateUserOp because it will be called at high frequency, so we need to consider the ‘gas efficiency’, in our consideration for the time being will be validateUserOp logic fixed in the contract (rather than through the plugin way to achieve), later if user need to upgrade the logic of validateUserOp, the user can update the ‘proxy contract’->‘logic contract’ address pointer(lower gas).
-
I think MSCA implicitly aims to create a set of standards that any standard-compliant SCA can use any standard-compatible frontEnd (users don’t need to rely on ‘ONE’ frontEnd only), while the signature assembly and verification process often differs from one SCA to another (gas efficiency first|stability first|code readability first… etc.), I’m thinking that this area could be a major challenge for MSCA implementation.
[/quote]
]
Hi all, we have some updates to share regarding ERC-6900. We have made some minor changes to the spec to improve clarity and consistency, and updated the reference implementation to be fully compliant with the ERC specification. We’ve also identified necessary areas to work on for stabilizing and simplifying the standard, and opened an agenda signup for the next community call.
Spec updates and fixes
We’ve addressed some small issues and added simplifications to the existing standard. This makes it easier to dive into the spec and the reference implementation and use modular account features. It is not comprehensive of all planned improvements discussed below.
Change log
- Renamed
Execution
toCall
. - Added the missing struct definition for
ManifestExternalCallPermission
. - Added a native token spending permission flag into the manifest.
- Moved view-only fields in the manifest out into a separate
pluginMetadata
function, since they don’t affect the installation procedure but occupy space. - Renamed
IPluginLoupe
toIAccountLoupe
for clarity on what is being inspected. - Added extra fields to the plugin installation events, to allow full reconstruction of account state by offchain entities.
- Relaxed rules to allow overlapping hook definitions.
- Other small cleanups and fixes pertaining to the EIP → ERC repo migration.
The standard and the reference implementation have been updated to reflect these changes. The reference implementation’s git tag has been advanced to v0.2.0
.
Updated ERC PR: Update ERC-6900: spec update 6 by fangting-alchemy · Pull Request #116 · ethereum/ERCs · GitHub
Reference implementation: GitHub - erc6900/reference-implementation at v0.2.0
Ongoing work to stabilize and simplify the standard
For a standard to provide value, the upside of conforming to it must outweigh the added costs. We’ve received feedback that ERC-6900 shifts too much of the burden onto account implementers, which risks fragmentation of plugin development. We’ve put together a list of specific steps we can take to consolidate aspects of the standard. This can help reduce the overhead of implementing a 6900-compliant account and make it easier to reason about.
- Multiple validation function support
- As discussed in the previous community call, many workflows could be simplified if there was a way for multiple validation functions to be applied over the same execution function. Some proposals were discussed around adding extra data into
userOp.signature
, but this data is inaccessible during validation. If we can create a generalized calldata format to pass validation context, we can easily allow for multiple validation functions on the same selector.
- As discussed in the previous community call, many workflows could be simplified if there was a way for multiple validation functions to be applied over the same execution function. Some proposals were discussed around adding extra data into
- Replace Plugin Operation
- Uninstalling and reinstalling plugins through
executeBatch
relies on some fragile assumptions for how the account should behave. If we introduce a standardizedreplacePlugin
method, these issues can be avoided. The current blocker has been the handling of dependencies, which add significant overhead to what the replace plugin operation needs to do to prevent inconsistent account state (described more below).
- Uninstalling and reinstalling plugins through
- Consolidate user-supplied install config
- Currently, ERC-6900 supports dependencies and injected hooks as ways to supplement the install config in a plugin manifest. These allow for wider cross-plugin compatibility and for stricter permissions, respectively. But, they come with large complexity costs on the implementation side, due to added tracking outside of the manifest. If we can simplify & consolidate these into a single user-supplied config, we can reduce complexity and make plugin replace operations feasible.
- De-enshrine
validateUserOp
- The special status of
validateUserOp
in ERC-6900 is key to allowing custom account security settings and automations. However, with proposed changes to ERC-4337’sUserOperation
struct and RIP-7560’svalidateTransaction
, we do not want to be stuck re-enshrining more special functions. We need to define a strategy for functions to have implementation-switching as needed to have modular validation functions.
- The special status of
We’ve opened these specific topics (and more!) as GitHub issues here, to track design progress and allow for easier discussion. Big thanks to community feedback from previous call, posts here, and others working on modular accounts for helping improve the standard and bring us closer to interoperability.
Community call agenda
We’ve also opened a public agenda for the community calls for anyone to sign up with a topic they’d like to discuss here. And, we’ve added some starting topics about the planned changes.
As always, we appreciate feedback in all forms. Feel free to leave comments here, open issues on GitHub, or bring up topics in the community calls.
Great point. There are a couple of solutions we are exploring that tackle this problem.
One is very similar to the solution you’ve described: [Improvement] Replace plugin operation · Issue #13 · erc6900/resources · GitHub
The other is a change that would allow more than one validation function to be installed for a given selector. This would, for example, allow one to install a new ownership plugin before uninstalling the old one: [Improvement] Multiple validation function support · Issue #4 · erc6900/resources · GitHub
Note that multiple validation function support would not help in a strict plugin upgrade scenario if the new plugin shares the same execution selectors as the older version. And as such, these solutions are not mutually exclusive.
If you have more ideas here, would love to hear your thoughts in the issues above!
Hi all, thank you to those who have been attending and contributing via our community calls and standard improvement issues! We have a new spec update that includes changes that came out of these discussions:
- The removal of permitted call hooks and injected hooks during plugin installation
- Disallowing use of hooks as dependencies
These changes will help to simplify the standard and account implementation, and improve security around state held in plugins. Please take a look at the issues linked above for more context and description of the changes.
Spec updates and fixes
Change log
- IPluginManager
- Removed structs
InjectedHook
,InjectedHooksInfo
- Removed the
injectedHooks
parameter from eventPluginInstalled
- Removed the
injectedHooks
parameter from functioninstallPlugin
- Removed the
hookUnapplyData
parameter from functionuninstallPlugin
- Renamed the
callbacksSucceeded
param of thePluginUninstalled
event toonUninstallSucceeded
, as there are no longer multiple callbacks for uninstalls - Renamed
pluginInitData
param ofinstallPlugin
topluginInstallData
to be more consistent with thepluginUninstallData
param ofuninstallPlugin
FunctionReference
type declaration has been moved fromIAccountLoupe
toIPluginManager
, since the former is an optional interfaceinstallPlugin
’s comment for thedependencies
param is now explicit about eachFunctionReference
being a validation function
- Removed structs
- IAccountLoupe
- Removed function
getPermittedCallHooks
- Removed function
- IPlugin
- Removed function
onHookApply
andonHookUnapply
- Removed member
permittedCallHooks
from structPluginManifest
- Removed function
- PluginManifest
- Added a note for
canSpendNativeToken
to clarify that the plugin can spend up to the amount that it sends to the account in the same call even if this value isfalse
- Updated comment for
dependencyInterfaceIds
to no longer include hooks
- Added a note for
- Calls to
installPlugin
- Included instruction to store the plugin’s native token spending permission
- Included instruction to store interface IDs for the manifest’s
interfaceIds
- Included instruction to also emit dependencies in the
PluginInstall
event
- Calls to
uninstallPlugin
- Removed reference to hook dependencies
- Included instruction to remove the plugin’s native token spending permission
- Included instruction to remove interface IDs
- Included note that if there is more than one instance of the same hook installed on a given function or if the same interface ID is added to the account by more than one plugin, they must persist until the last plugin that added them is uninstalled
- Included instruction to emit the
PluginUninstalled
event
- Calls to execution functions
- Added clarity around how duplicate hooks (identical
FunctionReference
s that are applied to the same function) should be handled during execution - Added more clarity around how hooks should be executed
- Added clarity around how duplicate hooks (identical
- Simplified the plugin execution flow diagram and the description of the install and uninstall behaviors accordingly
- Consistency improvements across comments
- Fixed typos
The standard and the reference implementation have been updated to reflect these changes. The reference implementation’s git tag has been advanced to v0.7.0
.
Updated ERC PR: Update ERC-6900: 0.7.0 by jaypaik · Pull Request #219 · ethereum/ERCs · GitHub
Reference implementation: GitHub - erc6900/reference-implementation at v0.7.0