With the rise of [ERC-4337](https://eips.ethereum.org/EIPS/eip-4337), we are now witnessing a [transition in wallet security](https://vitalik.eth.limo/general/2023/06/09/three_transitions.html), which will lead to the emergence of the next generation of crypto wallets that utilize account abstraction. We aim to develop a secure ERC-4337 smart contract wallet that ensures permanent user ownership and enables users to enjoy the benefits of account abstraction, such as social recovery, gas sponsorship, batch transactions and much more. Soul Wallet's initial draft version was based on the [Infinitism SimpleAccount](https://github.com/eth-infinitism/account-abstraction/blob/develop/contracts/samples/SimpleAccount.sol). We added social recovery and some additional features, such as a time lock for modifying guardians. However, due to the design of the SimpleAccount, it is challenging to add additional features without updating the logic contract. For example, adding a daily limit feature is difficult because the design doesn't support [hooks](https://docs.openzeppelin.com/contracts/4.x/extending-contracts#using-hooks). This means we would have had to develop a new logic contract and require users to upgrade their contracts to access the daily limit feature. We have refactored the smart contract to ensure that the core code is simple, yet supports modular design, making it easier to expand the functionality of the contract in the future without needing to upgrade the logic contract. Our contract architecture is designed as depicted in the following diagram: ![](https://hackmd.io/_uploads/B1eDNHjd3.png) We designed the smart contract with the following key considerations: - **High Extensibility** - **Permanent User Ownership** - **Secure Wallet Design** ## High Extensibility We have come to realize that a smart contract wallet must be capable of meeting ever-evolving demands and needs, including functionalities that may not have been foreseen during the initial development. While keeping the core contract unchanged, we achieve functionality expansion by introducing modules and plugins. ```mermaid graph LR SoulWallet --- Core & Plugin & Module & Others Core --- ExecutionManager & ModuleManager & PluginManager & FallbackManager Others --- OwnerManager click SoulWallet "https://github.com/proofofsoulprotocol/soul-wallet-contract/tree/v0.6.0.draft" click ExecutionManager "https://github.com/proofofsoulprotocol/soul-wallet-contract/blob/v0.6.0.draft/contracts/base/ExecutionManager.sol" click ModuleManager "https://github.com/proofofsoulprotocol/soul-wallet-contract/blob/v0.6.0.draft/contracts/base/ModuleManager.sol" click PluginManager "https://github.com/proofofsoulprotocol/soul-wallet-contract/blob/b625779002734ea31c66b419c0f7f0dc1229eb39/contracts/base/PluginManager.sol" click FallbackManager "https://github.com/proofofsoulprotocol/soul-wallet-contract/blob/v0.6.0.draft/contracts/base/FallbackManager.sol" click OwnerManager "https://github.com/proofofsoulprotocol/soul-wallet-contract/blob/v0.6.0.draft/contracts/base/OwnerManager.sol" style ExecutionManager fill:#77a5ff style SoulWallet fill:#77a5ff style PluginManager fill:#77a5ff style ModuleManager fill:#77a5ff style FallbackManager fill:#77a5ff style OwnerManager fill:#77a5ff ``` ### Modules The module feature was inspired by the design of the Gnosis Safe contract, which is a whitelisted contract capable of executing transactions on behalf of the smart contract wallet. The module extends the functionality of the contracts by introducing additional access logic for executing transactions. To ensure maximum security, we have implemented fine-grained module access control in the form of a [ModuleManager](https://github.com/proofofsoulprotocol/soul-wallet-contract/blob/v0.6.0.draft/contracts/base/ModuleManager.sol). The ModuleManager is responsible for managing the behavior of modules and determines which selectors can be called by each module. The benefit of this approach is that it provides clarity when adding modules. A modules' ability to invoke specific functions of the contract wallet is predetermined. For example, only the social recovery module can change the signing key, while the daily limit module can not. [SocialRecoveryModule](https://github.com/proofofsoulprotocol/soul-wallet-contract/blob/v0.6.0.draft/contracts/modules/SocialRecoveryModule/SocialRecoveryModule.sol) is an example that demonstrates the ability of modules. It's a global contract, separate from the wallet contract. The wallet can change the guardians in the module by directly calling the `updateGuardians` function of the module. During social recovery, the SocialRecoveryModule verifies guardian signatures and calls the wallet's `resetOwners` function, which is authorized by the wallet. Below is the execution flow for social recovery: ```mermaid flowchart LR Guardians["Guardians"] RecoveryModule["Social recovery Module"] SoulWallet["SoulWallet"] OwnerChanged["OwnerChanged"] Guardians -->|Social recovery| RecoveryModule -->|Permission check| RecoveryModule --> |Change Owner| SoulWallet -->|Authorized module check| SoulWallet --> OwnerChanged ``` We believe such design minimizes the complexity/risk of the core contract, while maxmizing flexibility. In the future, if users desire additional recovery mechanisms (such as recovery by email and [KeyStore recovery](https://vitalik.ca/general/2023/06/09/three_transitions.html)), then the wallet can add a new module with the same `resetOwners` permission but with different verifying logic. Additionally, it is important to note that the `addModule` and `removeModule` functions of the ModuleManager are controled by `onlyModule` modifier and cannot be self-called. This means that even if the signing key is compromised, a potential hacker cannot disable the social recovery module to gain control over the wallet. Actually, in our default wallet setting, the wallet is initiated with a special Module called [SecurityControlModule](https://github.com/proofofsoulprotocol/soul-wallet-contract/blob/v0.6.0.draft/contracts/modules/SecurityControlModule/SecurityControlModule.sol), which is authorized to executed `addModule` and `removeModule` from the wallet with time lock. ### Plugins Unlike modules, which call functions on the smart contract wallet, plugins enable the smart contract wallet to make calls to the plugin contract. Plugins (also known as hooks) can be configured to conduct additional checks on transactions before they are executed. There are three defined hook points in the contract wallet: - `guardHook` - `preHook` - `postHook` The `prehook` and `posthook` are executed before and after the execution of a transaction, while the `guardhook` is executed before signature validation. Below is the typical execution flow of user's transaction: ```mermaid flowchart LR Bundler["Bundler"] EntryPoint["EntryPoint"] SoulWallet["SoulWallet"] Exec["Exec"] Finish["Finish"] Bundler -->|handleOps| EntryPoint -->|guardHook| SoulWallet --> |validateUserOp| SoulWallet -->|preHook| Exec --> |postHook|Finish ``` By adding the `guardHook` during signature validation, we can implement a daily limit plugin that verifies the transaction limit during the validation phase rather than the execution phase. This ensures that if the validation fails, the user doesn't need to pay for the bundler gas fee. ## Permanent User Ownership To support lifelong ownership. the smart contract needs to support Upgradability, Portability and Social Recovery. ### Upgradability: Though the Module and Plugin are already very flexible, our contract is designed to allow for upgrades and support the addition of new features to adapt to the future evolving needs and functionalities of Ethereum users. ### Portability: Our design enables users to switch between wallet providers, without the need to transfer their assets or change their address. We use a minimal proxy contract, and the logic contract employs [diamond storage](https://dev.to/mudgen/how-diamond-storage-works-90e). This ensures that the data storage is not corrupted with another wallet implementation. Therefore, users are safe to migrate their wallet from Soul Wallet to another wallet provider. ### Social Recovery: The contract wallet has [social recovery](https://vitalik.ca/general/2021/01/11/recovery.html) mechanisms, enabling users to regain access to their wallet through predefined guardians in the event of key loss or compromise by hackers. To put it simply, a social recovery wallet must meet the following requirements: 1. A single "signing key" that can be used to authorize transactions. 2. A group of "guardians," when a majority of them collaborate, have the ability to modify the signing key associated with the account. In our implementation of social recovery, we have incorporated the following designs with a special emphasis on security: 1. When using the signing key to add or remove a guardian, the changes do not take immediate effect and require a waiting period. However, during the initial wallet creation, there is no waiting period to set up guardians. 2. The social recovery is implemented through an external module, where guardians are limited to performing only the operation of modifying the signing key and are unable to perform any other actions unrelated to social recovery, such as token transfers. 3. Users can choose to set public guardians or anonymous guardians. In the case of anonymous guardians, only the hash of guardians is stored on the social recovery module, ensuring that there is no direct association between the guardians and the user's address. This link remains hidden until a recovery process is initiated. Through these design considerations, we aim to provide a robust and secure social recovery wallet solution for our users. ## Secure Wallet Design One principal we kept in mind throughout our smart contract design is that users will have permanent ownership and control over their wallet. This means that even in extreme circumstances, our users will not lose control of their wallet. To achieve this goal, we have indeed made certain sacrifices in user experience. However, this trade-off is acceptable because the degree of sacrifice in user experience is determined by the users themselves. 1. **Modules & Plugins Security** Modules and plugins provide wallets with significant extensibility; however, users may grant extensive permissions to modules and plugins, which can potentially lead to security issues. \ If hackers gain control of a user's account, they can add malicious functionality through plugins, potentially disrupting the wallet's Social Recovery process. To mitigate this risk, we have implemented a [time lock mechanism](https://github.com/proofofsoulprotocol/soul-wallet-contract/blob/v0.6.0.draft/contracts/modules/SecurityControlModule/BaseSecurityControlModule.sol) when adding or removing modules and plugins. Similar to the time lock used for wallet upgrades, this mechanism prevents hackers from compromising the account before the user completes the Social Recovery process. Additionally, to improve the user experience, we maintain a [whitelist of trusted modules and plugins](https://github.com/proofofsoulprotocol/soul-wallet-contract/tree/v0.6.0.draft/contracts/trustedContractManager). Modules and plugins included in the whitelist can be immediately added to the wallet without a 48-hour waiting period (the user-defined security time). However, advanced users have the option to opt-out of using our whitelist system if they choose to do so. Below is the execution flow of adding a module: ```mermaid flowchart LR A[SoulWallet] --> |add module/plugin| B[SecurityControlModule] B --> C{trusted module?} C -->|Yes. Add Module| G[Soulwallet] C -->|No| E[wait queue]-->|Add Module| G[Soulwallet] G --> F([Done]) click C "https://github.com/proofofsoulprotocol/soul-wallet-contract/tree/v0.6.0.draft/contracts/modules/SecurityControlModule" click SCM "https://github.com/proofofsoulprotocol/soul-wallet-contract/tree/v0.6.0.draft/contracts/modules/SecurityControlModule" style C fill:#77a5ff style F fill:#55cc55 ``` 2. **Contract Upgrade Security** In general, wallet owners have the freedom to upgrade their contract wallet to a specific version at any time. However, this also means that if a hacker gains control of the wallet, they can perform an upgrade that removes the Social Recovery function, effectively blocking the owner from regaining control. To address this concern, we use modules to perform upgrades. Users need to add and authorize the module before executing upgrades. If a hacker takes control of the wallet, they would need to wait for the specified time period[e.g, 48Hours] to elapse before they can execute the upgrade. Meanwhile, the user will receive real-time security notifications through email or other channels (if opted-in), allowing them have enough time to perform the Social Recovery process and completely remove the hacker from their account. ## Why not use the Gnosis Safe Contract? The Safe contract design is very modular and battle-tested. We borrow and learn a lot from their design. However, Safe is specially utilized for institutional multisig use cases. We want to build an ERC4337 smart contract wallet for everyone, where the most common use case involves a single user and single signature for verification. The primary issue with the Safe contract is that for single signature use cases, it has security concerns. Safe achieves compatibility with ERC-4337 by modifying the fallback and adding new modules. When setting up the Safe with a threshold of 1 for single key usage, that single key has unrestricted access to add/remove modules and perform contract upgrades. In the event of the key being compromised by hackers, they can directly disable specific modules like social recovery, which prevents the user from retrieving their wallet. Alternatively, hackers can directly modify the logic contract by executing a special delegatecall to alter the 0th slot of the Safe. Although we can add a "guard" in the safe design to prevent unauthorized modification of internal storage in a contract through malicious delegatecall, the guard needs to consider and distinguish between different scenarios, such as user-informed contract upgrades (requiring delegatecall) and malicious contract upgrades by hackers. Moreover, the guard module is executed prior to each function call, resulting in significant additional gas overhead. To address these security concerns, we disabled the `delegatecall` in the entire contract, except for the contract [upgrade](https://github.com/proofofsoulprotocol/soul-wallet-contract/blob/b625779002734ea31c66b419c0f7f0dc1229eb39/contracts/base/UpgradeManager.sol#L14)(only allowing dedicated functions can make it easier to ensure security). For sensitive operations like contract upgrades and adding/removing modules, we implemented a time lock mechanism. This ensures that even if the signing key gets compromised by hackers, users still have enough time to respond and initiate social recovery to regain control of their wallet. ## We're building for the entire Ethereum community Soul Wallet is here to make using Ethereum easy and secure. While the contract design is expected to be stable, the [implementation details](https://github.com/proofofsoulprotocol/soul-wallet-contract/tree/v0.6.0.draft) are not final and have not undergone an audit. If you'd like to share feedback, suggest improvements, or explore collaboration opportunities, please get in touch with us at: - Twitter: https://twitter.com/soulwallet_eth - Telegram: https://t.me/+XFUHusXFdTYyODQ9 - Github: https://github.com/proofofsoulprotocol/soul-wallet-contract