With the rise of ERC-4337, we are now witnessing a transition in wallet security, 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. 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. 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:
We designed the smart contract with the following key considerations:
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.
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. 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 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:
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), 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, which is authorized to executed addModule
and removeModule
from the wallet with time lock.
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:
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.
To support lifelong ownership. the smart contract needs to support Upgradability, Portability and Social Recovery.
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.
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. 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.
The contract wallet has social recovery 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:
In our implementation of social recovery, we have incorporated the following designs with a special emphasis on security:
Through these design considerations, we aim to provide a robust and secure social recovery wallet solution for our users.
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.
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(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.
Soul Wallet is here to make using Ethereum easy and secure.
While the contract design is expected to be stable, the implementation details 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: