|
| 1 | += Account Modules |
| 2 | + |
| 3 | +Smart accounts built with https://eips.ethereum.org/EIPS/eip-7579[ERC-7579] provide a standardized way to extend account functionality through modules (i.e. smart contract instances). This architecture allows accounts to support various features that are compatible with a wide variety of account implementations. See https://erc7579.com/modules[compatible modules]. |
| 4 | + |
| 5 | +== ERC-7579 |
| 6 | + |
| 7 | +ERC-7579 defines a standardized interface for modular smart accounts. This standard enables accounts to install, uninstall, and interact with modules that extend their capabilities in a composable manner with different account implementations. |
| 8 | + |
| 9 | +=== Accounts |
| 10 | + |
| 11 | +OpenZeppelin offers an implementation of an xref:api:account.adoc#AccountERC7579[`AccountERC7579`] contract that allows installing modules compliant with this standard. There's also an xref:api:account.adoc#AccountERC7579Hooked[`AccountERC7579Hooked`] variant that supports installation of hooks. Like xref:accounts.adoc#handling_initialization[most accounts], an instance should define an initializer function where the first module that controls the account will be set: |
| 12 | + |
| 13 | +[source,solidity] |
| 14 | +---- |
| 15 | +include::api:example$account/MyAccountERC7579.sol[] |
| 16 | +---- |
| 17 | + |
| 18 | +NOTE: For simplicity, the xref:api:account.adoc#AccountERC7579Hooked[`AccountERC7579Hooked`] only supports a single hook. A common workaround is to install a https://github.com/rhinestonewtf/core-modules/blob/7afffccb44d73dbaca2481e7b92bce0621ea6449/src/HookMultiPlexer/HookMultiPlexer.sol[single hook with a multiplexer pattern] to extend the functionality to multiple hooks. |
| 19 | + |
| 20 | +=== Modules |
| 21 | + |
| 22 | +Functionality is added to accounts through encapsulated functionality deployed as smart contracts called _modules_. The standard defines four primary module types: |
| 23 | + |
| 24 | +* *Validator modules (type 1)*: Handle signature verification and user operation validation |
| 25 | +* *Executor modules (type 2)*: Execute operations on behalf of the account |
| 26 | +* *Fallback modules (type 3)*: Handle fallback calls for specific function selectors |
| 27 | +* *Hook modules (type 4)*: Execute logic before and after operations |
| 28 | + |
| 29 | +Modules can implement multiple types simultaneously, which means you could combine an executor module with hooks to enforce behaviors on an account, such as maintaining ERC-20 approvals or preventing the removal of certain permissions. |
| 30 | + |
| 31 | +See https://erc7579.com/modules[popular module implementations]. |
| 32 | + |
| 33 | +==== Building Custom Modules |
| 34 | + |
| 35 | +The library provides _standard composable modules_ as building blocks with an internal API for developers. By combining these components, you can create a rich set of variants without including unnecessary features. |
| 36 | + |
| 37 | +A good starting point is the xref:api:account.adoc#ERC7579Executor[`ERC7579Executor`] or xref:api:account.adoc#ERC7579Validator[`ERC7579Validator`], which include an opinionated base layer easily combined with other abstract modules. Hooks and fallback handlers are more straightforward to implement directly from interfaces: |
| 38 | + |
| 39 | +[source,solidity] |
| 40 | +---- |
| 41 | +include::api:example$account/modules/MyERC7579Modules.sol[] |
| 42 | +---- |
| 43 | + |
| 44 | +TIP: Explore these abstract ERC-7579 modules in the xref:api:account.adoc#modules[API Reference]. |
| 45 | + |
| 46 | +==== Execution Modes |
| 47 | + |
| 48 | +ERC-7579 supports various execution modes, which are encoded as a `bytes32` value. The https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/account/utils/draft-ERC7579Utils.sol[`ERC7579Utils`] library provides utility functions to work with these modes: |
| 49 | + |
| 50 | +[source,solidity] |
| 51 | +---- |
| 52 | +// Parts of an execution mode |
| 53 | +type Mode is bytes32; |
| 54 | +type CallType is bytes1; |
| 55 | +type ExecType is bytes1; |
| 56 | +type ModeSelector is bytes4; |
| 57 | +type ModePayload is bytes22; |
| 58 | +---- |
| 59 | + |
| 60 | +===== Call Types |
| 61 | + |
| 62 | +Call types determine the kind of execution: |
| 63 | + |
| 64 | +[%header,cols="1,1,3"] |
| 65 | +|=== |
| 66 | +|Type |Value |Description |
| 67 | +|`CALLTYPE_SINGLE` |`0x00` |A single `call` execution |
| 68 | +|`CALLTYPE_BATCH` |`0x01` |A batch of `call` executions |
| 69 | +|`CALLTYPE_DELEGATECALL` |`0xFF` |A `delegatecall` execution |
| 70 | +|=== |
| 71 | + |
| 72 | +===== Execution Types |
| 73 | + |
| 74 | +Execution types determine how failures are handled: |
| 75 | + |
| 76 | +[%header,cols="1,1,3"] |
| 77 | +|=== |
| 78 | +|Type |Value |Description |
| 79 | +|`EXECTYPE_DEFAULT` |`0x00` |Reverts on failure |
| 80 | +|`EXECTYPE_TRY` |`0x01` |Does not revert on failure, emits an event instead |
| 81 | +|=== |
| 82 | + |
| 83 | +==== Execution Data Format |
| 84 | + |
| 85 | +The execution data format varies depending on the call type: |
| 86 | + |
| 87 | +* For single calls: `abi.encodePacked(target, value, callData)` |
| 88 | +* For batched calls: `abi.encode(Execution[])` where `Execution` is a struct containing `target`, `value`, and `callData` |
| 89 | +* For delegate calls: `abi.encodePacked(target, callData)` |
| 90 | + |
| 91 | +== Examples |
| 92 | + |
| 93 | +=== Social Recovery |
| 94 | + |
| 95 | +Social recovery allows an account to be recovered when access is lost by relying on trusted parties ("guardians") who verify the user's identity and help restore access. |
| 96 | + |
| 97 | +Social recovery is not a single solution but a design space with multiple configuration options: |
| 98 | + |
| 99 | +* Delay configuration |
| 100 | +* Expiration settings |
| 101 | +* Different guardian types |
| 102 | +* Cancellation windows |
| 103 | +* Confirmation requirements |
| 104 | + |
| 105 | +To support _different guardian types_, we can leverage ERC-7913 as discussed in the xref:multisig.adoc#beyond_standard_signature_verification[multisig] section. For ERC-7579 modules, this is implemented through the xref:api:account.adoc#ERC7579Multisig[`ERC7579Multisig`] validator. |
| 106 | + |
| 107 | +Combined with an xref:api:account.adoc#ERC7579Executor[`ERC7579Executor`], it provides a basic foundation that can be extended with more sophisticated features: |
| 108 | + |
| 109 | +[source,solidity] |
| 110 | +---- |
| 111 | +include::api:example$account/modules/MyERC7579SocialRecovery.sol[] |
| 112 | +---- |
| 113 | + |
| 114 | +For enhanced security, you can extend this foundation with scheduling, delays, and cancellations using xref:api:account.adoc#ERC7579DelayedExecutor[`ERC7579DelayedExecutor`]. This allows guardians to schedule recovery operations with a time delay, providing a security window to detect and cancel suspicious recovery attempts before they execute: |
| 115 | + |
| 116 | +[source,solidity] |
| 117 | +---- |
| 118 | +include::api:example$account/modules/MyERC7579DelayedSocialRecovery.sol[] |
| 119 | +---- |
| 120 | + |
| 121 | +NOTE: The delayed executor's signature validation doesn't require a nonce since operations are uniquely identified by their xref:api:account.adoc#ERC7579DelayedExecutor-hashOperation-address-bytes32-bytes32-bytes-[operation id] and cannot be scheduled twice. |
| 122 | + |
| 123 | +These implementations demonstrate how to build progressively more secure social recovery mechanisms, from basic multi-signature recovery to time-delayed recovery with cancellation capabilities. |
| 124 | + |
| 125 | +For additional functionality, developers can use: |
| 126 | + |
| 127 | +* xref:api:account.adoc#ERC7579MultisigWeighted[`ERC7579MultisigWeighted`] to assign different weights to signers |
| 128 | +* xref:api:account.adoc#ERC7579MultisigConfirmation[`ERC7579MultisigConfirmation`] to implement a confirmation system that verifies signatures when adding signers |
0 commit comments