What I would love to see in a wallet

2024 Dec 03 See all posts


What I would love to see in a wallet

Special thanks to Liraz Siri, Yoav Weiss, and ImToken, Metamask and OKX developers for feedback and review.

One critical layer of the Ethereum infrastructure stack, often underappreciated by core L1 researchers and developers, is the wallet. Wallets are the window between a user and the Ethereum world, and a user only benefits from any decentralization, censorship resistance, security, privacy, or other properties that Ethereum and its applications offer to the extent that the wallet itself also has these properties.

Recently, we have seen a lot of progress on improving user experience, security and functionality of Ethereum wallets. The goal of this post is to give my own views of some of the properties that an ideal Ethereum wallet would have. This is not intended to be a complete list; reflecting my cypherpunk leanings, it focuses on security and privacy, and it is almost certainly incomplete on the user experience front. However, I would argue that wishlists are less effective for optimizing user experience than simply deploying and iterating based on feedback, and so I think it is most valuable to focus on the security and privacy properties.

User experience of cross-L2 transactions

There is now an increasingly detailed roadmap for improving cross-L2 user experience, which has a short-term part and a long-term part. Here, I will talk about the short-term part: ideas which are theoretically implementable even today.

The core ideas are (i) built-in cross-L2 sends, and (ii) chain-specific addresses and payment requests. Your wallet should be able to give you an address that (following the style of this draft ERC) looks like this:

0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045@optimism.eth

When someone (or some application) gives you an address of this format, you should be able to paste it into a wallet's "to" field, and click "send". The wallet should automatically process that send in whatever way it can:


Mockup of possible wallet interface with cross-chain address support


The above is for the "you copy-paste an address (or ENS, eg. vitalik.eth@optimism.eth) for someone to pay you" use case. If a dapp is requesting a deposit (eg. see this Polymarket example) then the ideal flow is to extend the web3 API and allow the dapp to make a chain-specific payment request. Your wallet would then be able to satisfy that request in whatever way it needs to. Making the user experience work well would also require standardizing a getAvailableBalance request, and wallets would need to put significant thought into which chains they store users' assets on by default to maximize security and ease of transfers.

Chain-specific payment requests could also be put into QR codes, which mobile wallets could scan. In an in-person (or online) consumer payments scenario, the recipient would make a QR code or web3 API call that says "I want X units of token Y on chain Z, with reference ID or callback W", and the wallet would be free to satisfy that request in whatever way it can. Another option is a claim link protocol, where the user's wallet generates a QR code or URL that contains an authorization to claim a certain quantity of funds from their onchain contract, and it's the recipient's job to figure out how to then move those funds to their own wallet.

Another related topic is gas payments. If you receive assets on an L2 where you do not yet have ETH, and you need to send a transaction on that L2, a wallet should be able to automatically use a protocol (eg. RIP-7755) to pay the gas on a chain where you do have ETH. If the wallet expects you to make more transactions on that L2 in the future, it should also just use a DEX to send over eg. a few million gas worth of ETH, so that future transactions can spend gas there directly (as this is cheaper).

Account security

One way that I conceptualize the account security challenge is that a good wallet should simultaneously be good in two areas: (i) protecting the user from the wallet developer being hacked or malicious, and (ii) protecting the user from their own mistakes.


The typo "mistakles" on the left was unintentional. However, upon seeing it I realized that it's perfectly appropriate for the context, so I decided to keep it.


My preferred solution to this, for over ten years, has been social recovery and multisig wallets, with graded access control. A user's account has two layers of keys: a primary key, and N guardians (eg. N = 5). The primary key is able to do low-value and non-financial operations. A majority of the guardians is required to do either (i) high-value operations, like sending away the entire value in the account, or (ii) change the primary key or any of the guardians. If desired, the primary key can be allowed to do high-value operations with a timelock.

The above is a basic design, and can be augmented. Session keys, and permissions mechanisms like ERC-7715, can help support different balances between convenience and security for different applications. More complicated guardian architectures, such as having multiple timelock durations at different thresholds, can help maximize the chance of successful legitimate account recovery while minimizing the risk of theft.

Who or what should the guardians be?

For an experienced crypto user who is inside a community of experienced crypto users, a viable option is the keys of your friends and family. If you ask each one to provide you with a fresh address, then no one needs to know who they are - in fact, your guardians don't even need to know who each other are. The chance that they will collude without one of them tipping you off is tiny. For most new users, however, this option is not available.

A second option is institutional guardians: firms that specialize in performing the service of only signing a transaction if they get some other confirmation that a request is coming from you: eg. a confirmation code, or for high-value users a video call. People have attempted to make these for a long time, eg. I profiled CryptoCorp in 2013. However, so far such firms have not been very successful.

A third option is multiple personal devices (eg. phone, desktop, hardware wallet). This can work, but also is difficult to set up and manage for inexperienced users. There is also the risk of devices being lost or stolen at the same time, especially if they are at the same location.

Recently, we have started to see more wallets based on passkeys. Passkeys can be backed up on your devices only, making them a type of personal-device solution, or backed up in the cloud, making their security dependent on a complicated hybrid of password security, institutional and trusted hardware assumptions. Realistically, passkeys are a valuable security gain for ordinary users, but they alone are not strong enough to protect a user's life savings.

Fortunately, with ZK-SNARKs, we have a fourth option: ZK-wrapped centralized ID. This genre includes zk-email, Anon Aadhaar, Myna Wallet, and many others. Basically, you can take many forms of (corporate or governmental) centralized ID, and turn it into an Ethereum address, which you can only send transactions from by generating a ZK-SNARK proving possession of the centralized ID.



With this addition, we now have a wide array of options, and ZK-wrapped centralized ID is uniquely "noob-friendly".

For this to work, it needs to be implemented with a streamlined and integrated UI: you should be able to just specify that you want "example@gmail.com" as a guardian, and it should automatically generate the corresponding zk-email Ethereum address under the hood. Advanced users should be able to enter their email (along with perhaps a salt value for privacy, that would be saved in that email) into an open-source third-party application, and confirm that the address generated is correct. The same should be true for any other supported guardian type.


Mockup of possible Safe interface


Note that today, one practical challenge with zk-email specifically is that it depends on DKIM signatures, which use keys that are rotated once every few months, and these keys are not themselves signed by any other authority. This means that zk-email today has some level of trust requirement beyond the provider themselves; this could be reduced if zk-email used TLSNotary inside trusted hardware to verify updated keys, but it's not ideal. Hopefully, email providers will start signing their DKIM keys directly. Today, I would recommend using zk-email for one guardian, but not for a majority of your guardians: do not store funds in a setup where zk-email breaking means that you lose access to your funds.

New users and in-app wallets

New users realistically will not want to have to enter a large number of guardians in their first signup experience. Hence, wallets should offer them a very simple option. One natural route is a 2-of-3 using zk-email on their email address, a key stored locally on the user's device (which could be a passkey), and a backup key held by the provider. As a user becomes more experienced, or accrues more assets, at some point they should be prompted to add more guardians.

Wallets integrated in applications are inevitable, because applications trying to appeal to non-crypto users do not want the confusing user experience of asking their users to download two new applications (the app itself, plus an Ethereum wallet) at the same time. However, a user of many application wallets should be able to link all of their wallets together, so that they only have one "access control thing" to worry about. The simplest way to do this is a hierarchical scheme, where there is a fast "linking" process that allows a user to set their primary wallet to be the guardian of all of their in-app wallets. The Farcaster client Warpcast supports this already:


By default, your Warpcast account's recovery is controlled by the Warpcast team. However, you can "take sovereignty over" your Farcaster account, and change the recovery to your own address.


Protecting users from scams and other external threats

In addition to account security, wallets today do a lot to identify fake addresses, phishing, scams and other external threats, and try to protect their users from such threats. At the same time, many of the countermeasures are still quite primitive: for example, requiring a clickthrough to send ETH or other tokens to any new address, regardless of whether you're sending $100 or $100,000. Here, there is no single magic-bullet solution; it's a series of slow ongoing fixes and improvements to different categories of threats. However, there is a lot of value in continuing to do the hard work to improve here.

Privacy

Now is the time to start taking privacy on Ethereum much more seriously. ZK-SNARK technology is now very advanced, privacy technologies that mitigate regulatory risks without relying on backdoors, such as Privacy Pools, are growing more mature, and secondary infrastructure like Waku and ERC-4337 mempools is slowly becoming more stable. However, up until now, making private transfers on Ethereum has required users to explicitly download and use a "privacy wallet", such as Railway (or Umbra for stealth addresses). This adds great inconvenience and reduces the number of people who are willing to make private transfers. The solution is that private transfers need to be integrated directly into wallets.

A simple implementation is as follows. A wallet could store some portion of a user's assets as a "private balance" in a privacy pool. When a user makes a transfer, it would automatically withdraw from the privacy pool first. If a user needs to receive funds, the wallet could automatically generate a stealth address.

Additionally, a wallet could automatically generate a new address for each application that a user participates in (eg. a defi protocol). Deposits would come from the privacy pool, and withdrawals would go straight into the privacy pool. This allows a user's activity in any one application to be unlinked from their activity in other applications.



One advantage of this technique is that it is a natural pathway to not just privacy-preserving asset transfer, but also privacy-preserving identity. Identity happens onchain already: any application that uses proof-of-personhood gating (eg. Gitcoin Grants), any token-gated chat, the Ethereum Follow Protocol, and much more are all onchain identity. We want this ecosystem to also be privacy-preserving. This means that a user's activity onchain should not be collected in one place: each item should be stored separately, and the user's wallet should be the only thing with a "global view" that sees all of your attestations at the same time. A natively many-accounts-per-user ecosystem helps accomplish this, as do offchain attestation protocols like EAS and Zupass.

This represents a pragmatic vision for Ethereum privacy in the medium-term future. It can be implemented today, although there are features that can be introduced at L1 and L2 to make privacy-preserving transfers more efficient and reliable. Some privacy advocates argue that the only acceptable thing is total privacy of everything: encrypting the entire EVM. I would argue that this may be ideal as a long-term outcome, but it requires a much more fundamental rethink of programming models, and it's currently not at the level of maturity where it's ready to go and deploy across Ethereum. We do need privacy-by-default to get sufficiently large anonymity sets. However, focusing first on making (i) transfers between accounts, and (ii) identity and identity-adjacent use cases like attestations private is a pragmatic first step that is far easier to implement, and which wallets can get started on today.

Ethereum wallets need to also become data wallets

One consequence of any effective privacy solution, whether for payments or for identity or other use cases, is that it creates a need for the user to store offchain data. This was obvious in Tornado Cash, which required users to save each individual "note" representing a 0.1-100 ETH deposit. More modern privacy protocols sometimes save the data encrypted onchain, and use a single private key to decrypt it. This is risky, because if the key is ever leaked, or if quantum computers ever become viable, the data all becomes public. Offchain attestations like EAS and Zupass have an even more obvious need for offchain data storage.

Wallets need to become not just software to store onchain access permissions, but also software to store your private data. This is something that the non-crypto world is increasingly recognizing as well, eg. see Tim Berners-Lee's recent work in personal data stores. All of the problems that we need to solve around robustly guaranteeing control of access permissions, we also need to solve around robustly guaranteeing accessibility and non-leakage of data. Perhaps the solutions could be overlaid together: if you have N guardians, use M-of-N secret sharing between those same N guardians to store your data. Data is inherently harder to secure, because you can't revoke someone's share of it, but we should come up with decentralized custody solutions that are as secure as we can.

Secure chain access

Today, wallets trust their RPC providers to tell them any information about a chain. This is a vulnerability in two ways:

  1. The RPC provider could attempt to steal money by feeding them false information, eg. about market prices
  2. The RPC provider could extract private information about what applications and other accounts a user is interacting with

Ideally, we want to plug both of these holes. To plug the first, we need standardized light clients for L1 and L2s, which directly verify the blockchain consensus. Helios already does this for L1, and has been doing some preliminary work to support some specific L2s. To properly cover all L2s, what we need is a standard by which a config contract representing an L2 (also used for chain-specific addresses) can declare a function, perhaps in a manner similar to ERC-3668, containing the logic for obtaining recent state roots, and verifying proofs of state and receipts against those state roots. This way we could have a universal light client, allowing wallets to securely verify any state or events on L1 and L2.

For privacy, today the only realistic approach is to run your own full node. However, now that L2s are entering the picture, running a full node of everything is getting increasingly hard. The equivalent to a light client here is private information retrieval (PIR). PIR involves a server holding a copy of all the data, and a client sending the server an encrypted request. The server performs a computation over all the data, which returns the client's desired data, encrypted to the client's key, without revealing to the server which piece of data the client accessed.



To keep the server honest, the individual database items would themselves be Merkle branches, so the client could verify them using their light client.

PIR is very computationally expensive. There are several routes around this problem:

Figuring out the right combination of techniques to maximize privacy while maintaining practicality in the Ethereum context is an open research problem, and I welcome cryptographers trying their hand at it.

Ideal keystore wallets

Aside from transfers and state access, one other important workflow that needs to work smoothly in a cross-L2 context is changing an account's validation configuration: whether changing its keys (eg. recovery), or a deeper change to the account's entire logic. Here, there are three tiers of solutions, in increasing order of how difficult they are:

  1. Replayed updates: when a user changes their configuration, a message authorizing this change is replayed on every chain where the wallet detects that a user has assets. Potentially, the message format and validation rules can be made chain-independent, so it can be automatically replayed on as many chains as possible.
  2. Keystores on L1: the config information lives on L1, and the wallet on L2 reads it with an L1SLOAD or REMOTESTATICCALL. This way, updating the config needs to be done only on L1, and the config becomes effective automatically.
  3. Keystores on L2: the config information lives on L2, and the wallet on L2 reads it with a ZK-SNARK. This is the same as (2), except keystore updates can be cheaper, though on the other hand reads are more expensive.



Solution (3) is particularly powerful because it stacks well with privacy. In a normal "privacy solution", a user has a secret s , a "leaf value" L is published on chain, and a user proves that L = hash(s, 1) and N = hash(s, 2) for some (never-revealed) secret that they control. The nullifier N gets published, making sure that future spends of the same leaf fail, without ever revealing L. This depends on the user keeping s safe. A recovery-friendly privacy solution would instead say: s is a location (eg. address and storage slot) onchain, and the user must prove a state query: L = hash(sload(s), 1) .

Dapp security

The weakest link in a user's security is often the dapp. Most of the time, a user interacts with an application by going to a website, which implicitly downloads the user interface code in real-time from a server and then executes it in-browser. If the server is hacked, or if the DNS is hacked, the user will get a fake copy of the interface, which could trick the user into doing arbitrary things. Wallet features like transaction simulations are very helpful in mitigating the risks, but they are far from perfect.

Ideally, we would move the ecosystem to on-chain content versioning: a user would access a dapp via its ENS name, which would contain the IPFS hash of the interface. An onchain transaction from a multisig or DAO would be needed to update the interface. Wallets would show users if they're interacting with a more-secure onchain interface, or a less-secure web2 interface. Wallets can also show users if they're interacting with a secure chain (eg. stage 1+, multiple security audits).

For privacy-conscious users, wallets can also add a paranoid mode, which requires users to clickthrough accept HTTP requests, and not just web3 operations:


Mockup of possible interface for paranoid mode


A more advanced approach would be to move beyond HTML + Javascript, and write the business logic of dapps in a dedicated language, perhaps a relatively thin overlay over Solidity or Vyper. Browsers could then automatically generate a UI for any needed functionality. OKContract is doing this already.

Another direction is cryptoeconomic info-defense: dapp developers, security firms, chain deployers and others can put up a bond that would get paid out to affected users if a dapp was hacked or otherwise harmed users by acting in a highly misleading way, as determined by some onchain adjudication DAO. The wallet could show a user a score that is based on the size of the bond.

The longer-term future

The above was all in the context of conventional interfaces, which involve pointing and clicking on things and entering things into text fields. However, we are also on the cusp of paradigms changing much more deeply:

These three trends together will lead to much deeper rethinking of how interfaces work. Through natural language input, eye tracking, or eventually more direct BCI, together with knowledge of your history (perhaps including text messages, as long as all data is processed locally), a "wallet" could get a clear intuitive idea of what you want to do. AI could then translate that intuition into a concrete "action plan": a series of onchain and offchain interactions that accomplish what you want. This could greatly reduce the need for third-party user interfaces entirely. If a user does interact with a third-party application (or another user), the AI should think adversarially on the user's behalf, and identify any threats and suggest action plans for avoiding them. Ideally, there would be an open ecosystem of these AIs, produced by different groups with different biases and incentive structures.

These more radical ideas depend on technology that is extremely immature today, and so I would not put my assets today into a wallet that relies on them. However, something like this seems to be pretty clearly the future, and so it's worth starting to more actively explore in that direction.