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:
- If you already have enough coins of the needed type on the
destination chain, send the coins directly
- If you have coins of the needed type on another chain (or
multiple other chains), use a protocol like ERC-7683
(effectively a cross-chain DEX) to send the coins
- If you have coins of a different type on the same or other chains,
use decentralized exchanges to convert them into the
right type of coin on the right chain and send them. This should require
explicit permission from the user: the user would see how much of what
they are paying, and how much the recipient is getting.
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:
- The RPC provider could attempt to steal money by
feeding them false information, eg. about market prices
- 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:
- Brute force: improvements in algorithms, or
specialized hardware, could potentially make PIR fast enough to run.
These techniques may depend on pre-processing: servers
could store encrypted-and-shuffled data for each client, and clients
could query that data. The main challenge in the Ethereum setting is
adapting these techniques to datasets that change rapidly (as the state
does). This makes real-time computational costs lower, but may well make
total computational and storage costs higher.
- Weaken the privacy requirement: for example, each
lookup could only have 1 million "mixins", so the server would know a
million possible values that the client could have accessed, but not any
finer granularity
- Multi-server PIR: PIR algorithms are often much
faster if you use multiple servers with a 1-of-N honesty assumption
between those servers.
- Anonymity instead of confidentiality: instead of
hiding the contents of the request, the request could be sent
through a mixnet, hiding the sender of the request. However,
doing this effectively inevitably increases latency, worsening the user
experience.
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:
- 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.
- 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.
- 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:
- AI, which could lead to us moving away from a
point-and-click-and-type paradigm to a paradigm of "say what you want to
do, and the bot figures it out"
- Brain-computer interfaces, both "mild" approaches
like eye tracking as well as more direct and even invasive techniques
(see: first
Neuralink patient this year)
- Clients engaging in active defense: the Brave
browser actively protects users
against ads, trackers and many other undesirable objects. Many
browsers, plugins and crypto wallets have entire teams actively working
to protect users against all kinds of security and privacy threats.
These kinds of "active guardians" will become only more powerful in the
coming decade.
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.
What I would love to see in a wallet
2024 Dec 03 See all postsSpecial 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 tokenY
on chainZ
, with reference ID or callbackW
", 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:
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:
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 thatL = hash(s, 1)
andN = hash(s, 2)
for some (never-revealed) secret that they control. The nullifierN
gets published, making sure that future spends of the same leaf fail, without ever revealingL
. This depends on the user keepings
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.