Good question This is something we chose to “bake in” to the standard to allow the account to be a single source of truth for the modular account config.
One of the core parts of the standard is allowing for multiple types of transaction validity to coexist at the same time in an account. To do this, the logic of validateUserOp
switches and is routed differently based on what function is being called, as specified by the selector in the first 4 bytes of userOp.callData
sent to validateUserOp
. If the switching behavior of validateUserOp
is implemented as a plugin, then the relationship between the function selector and which validation function to run would have to be implemented within the plugin, and the “modular account config” would end up being in 2 locations.
If we only wanted one logical component to run during validateUserOp
, then it would simple to make a plugin that just defines the function with its single implementation. But, since we want to allow different types of user ops to be validated differently, and for this validation logic to live in separate contracts that can be added or removed, then the plugin defining validateUserOp
must now manage the execution → validation function mapping and the overall state of installed / uninstalled plugins. The reason validateUserOp
is given special treatment and required to be a native function for 6900 is to consolidate the installation management and modular features, so plugin developers don’t have to re-invent modularity.
Would love to hear more of your thoughts too – is this something you’re interested in for supporting other validity checking functions?