The Narrative We Told Ourselves
For years, the crypto community had a ready-made answer whenever adoption numbers disappointed: they just don’t get it yet. Normies weren’t ready. Regulators were in the way. The bear market killed momentum. Give it one more cycle.
But cycles came and went. Ethereum went from $80 to $4,800 and back. NFTs had their moment in the cultural spotlight. DeFi summer happened. BlackRock filed for a spot ETF. Billions poured in from institutions. And yet — your parents still don’t use a dApp. Your non-tech friends still can’t explain what a wallet is. Mass adoption remains a perpetually future event.
The numbers make this embarrassing. At the peak of the 2021 bull run, there were roughly 10 million monthly active MetaMask users. That sounds like a lot until you remember the internet has 5 billion users. Email, the technology it most closely competes with for “store of value for digital assets,” reached 1 billion users within 15 years of becoming commercially viable. Crypto has been commercially viable since at least 2017. It has a fraction of that penetration, and most of those users are speculators, not people who use it to actually do things.
I’ve been building and using smart contracts long enough to know the uncomfortable truth: the technology was never the problem. The experience of using it was.
A New User’s First Hour in Web3
Let’s be honest about what we actually ask someone to do when they “just try” Web3. Not in theory. Step by step.
- Install a wallet extension. Not an app — a browser extension that controls a financial account. Immediately, you’ve filtered out everyone on mobile-only devices or anyone who doesn’t trust browser extensions with their money (a reasonable instinct).
- Write down a 12-word seed phrase on paper. They’re told — in the same breath as the congratulations for setting up an account — that if they lose this piece of paper, their funds are gone forever and no one can help them. No customer support. No password reset. No bank to call. This is the onboarding experience. This is the first impression.
- Find a centralized exchange. To do anything useful, they need tokens. That means Coinbase, Kraken, or Binance. More account creation.
- Complete KYC. Upload a passport or driver’s license. Wait 24–72 hours for verification. This alone kills momentum for anyone who wanted to try something quickly.
- Buy ETH and withdraw it. Now they’re asked to copy-paste a 42-character hex address (
0x71C7656EC7ab88b098defB751B7401B5f6d8976F) into a withdrawal form. One wrong character and the funds are gone. No confirmation screen will tell them the destination is wrong — it’ll just be wrong. - Add the right network. If they want to use an L2 to avoid $40 gas fees, they need to manually add a custom RPC endpoint to MetaMask. This involves finding the right chain ID, RPC URL, and block explorer URL. From a forum post, usually.
- Bridge assets. Now they need to move ETH from mainnet to the L2. Another interface. Another approval. Another wait. Another fee.
- Finally interact with a dApp. And now the dApp asks them to connect their wallet and sign a transaction they don’t understand.
That’s the happy path. No phishing attacks, no failed transactions, no gas estimation errors. Eight steps of genuine friction before they’ve done a single thing of value.
Traditional finance’s UX is not great. But it is predictable. You open an app, log in with a password you can reset, see your balance in dollars, tap a button. That predictability is doing more work than we ever gave it credit for.
The Confirmation Dialog Problem
Every single interaction in Web3 ends with a cryptic confirmation popup. This isn’t a minor inconvenience — it’s a fundamental breakdown in the trust model.
MetaMask’s default transaction confirmation shows you: a contract address, an estimated gas fee in ETH (sometimes also in USD if you’re lucky), a hex-encoded calldata field, and a button that says “Confirm.” For a first-time user, this is an anxiety attack dressed up as a dialog box. They have no idea what they’re approving, what it costs in real money, or what happens if they click the wrong thing.
EIP-712 was supposed to fix this. It introduced typed structured data signing, which means wallets can decode a signature request and show you something human-readable: “You are listing NFT #4821 for sale at 0.5 ETH on OpenSea.” That’s genuinely better. OpenSea uses it. Some DeFi protocols use it.
But most dApps don’t. And even the ones that do can’t prevent malicious contracts from providing a clean-looking EIP-712 message that still drains your wallet — because the message is defined by the dApp, not verified by anyone. The wallet shows you what the dApp tells it to show you. There’s no equivalent of HTTPS certificate verification for transaction intent. A MetaMask prompt from a phishing site looks identical to one from a legitimate dApp.
Compare this to how Stripe handles a payment confirmation: clear amount, merchant name, last four digits of the card being charged, and what you’re buying. Stripe’s entire model is built around making payment confidence feel effortless — and they have legal and technical accountability if something goes wrong. Web3 wallets still feel like submitting a pull request to production with no tests and no reviewer. The interface was designed by developers, for developers, and it never fully grew up past that.
“Just Use a Hardware Wallet” Doesn’t Scale
The standard response to security concerns in Web3 is to recommend more complexity: use a hardware wallet, use a multisig, never click links in Discord, revoke token approvals regularly on Revoke.cash. All solid advice for the already-initiated. Completely useless as an adoption strategy.
We built a financial system where the security model assumes users will become their own bank — their own IT department, their own fraud department, their own backup and recovery team. A Ledger device costs $79. It requires firmware updates. It has its own interface. If you lose the device and the seed phrase backup simultaneously, your funds are gone. This is what we recommend to new users.
The real-world results are predictable. Monkey Drainer, a phishing-as-a-service operation shut down in early 2023, had stolen an estimated $13 million in NFTs and ETH across thousands of wallets before its operator voluntarily closed shop. Inferno Drainer, its successor, reportedly extracted over $80 million before shutting down in late 2023. Pink Drainer followed with another $85 million. These weren’t sophisticated zero-day exploits. They were websites that looked like legitimate dApps and asked users to sign a transaction. That’s it. The attack surface was the UX itself.
The phishing attacks that devastated Web3 users weren’t primarily technical failures. They were UX failures. When your interface looks exactly like a malicious copy of itself, you have a design problem. When users can’t visually distinguish between signing into a dApp and approving a setApprovalForAll() call that grants an unknown contract unlimited access to their entire NFT collection, you have a design problem. The word “Approve” appears in both flows. The visual weight of the two dialogs is nearly identical. A user who has signed ten legitimate transactions has learned nothing that would protect them from the eleventh being malicious.
Layer 2s Helped. But They Also Fragmented Everything.
The scaling solutions came, and they are genuine engineering achievements. Arbitrum’s fraud proof system. Optimism’s OP Stack and the Superchain vision. Base, built on OP Stack and backed by Coinbase’s distribution. zkSync’s ZK rollup with validity proofs. Polygon’s AggLayer. Each of these moved real throughput off mainnet, dropped gas fees from $30–$80 per swap to fractions of a cent, and made DeFi economically viable for regular transaction sizes again.
They also turned “which chain are you on?” into a standard opening question between Web3 users. As of 2024, there are over 50 EVM-compatible L2s and sidechains with meaningful liquidity. For anyone outside the ecosystem, this introduced a compounding layer of confusion: you need the right tokens, on the right chain, bridged correctly, with the right wallet settings, and in many cases an RPC endpoint manually configured. Bridges — the infrastructure connecting these chains — became one of the largest single attack surfaces in all of crypto. The Ronin bridge lost $625 million. The Wormhole bridge lost $320 million. The Nomad bridge lost $190 million. These weren’t fringe protocols; they were core infrastructure that users were funneled through.
Even ignoring the hacks: the UX of bridging is genuinely terrible. You select a source chain, a destination chain, an asset, and an amount. You wait for a finality period that ranges from minutes to hours depending on the bridge mechanism. Your funds disappear from one chain and reappear on another, and if anything goes wrong in between — wrong chain selected, bridge contract paused, liquidity unavailable on the destination — your path to resolution is a Discord server and a support ticket.
The L2 ecosystem solved throughput. It created a fragmentation problem that made the onboarding problem meaningfully worse, and it created a new class of billion-dollar attack surfaces in the process.
What Good UX Would Actually Look Like
Not pessimistic about Web3. Impatient with it. The path forward is clear, even if it’s uncomfortable:
Abstract the wallet. Email or passkey login that generates a self-custodied wallet under the hood. ERC-4337 (account abstraction) makes this possible without sacrificing self-custody — the private key never leaves the device, but the user never sees it either. Coinbase’s Smart Wallet and Privy are the closest production implementations of this. Both let you onboard with a passkey and have an actual on-chain account in under 30 seconds. This is what the whole ecosystem should look like. Very few apps have shipped it seriously.
Denominate everything in fiat. Gas fees in dollars, always. Not gwei. Not ETH fractions. The chain’s native token is an implementation detail — treat it like one. When someone pays $0.04 to swap tokens, show them $0.04. Don’t show them 0.000016 ETH and expect them to do math. Uniswap’s mobile app has done this reasonably well. Most dApps have not.
Make recovery human. Social recovery (Argent pioneered this on-chain — designate trusted contacts who can collectively authorize a wallet recovery), guardian-based recovery, time-locked recovery with an email fallback. The primitives exist. Safe’s smart account model supports all of these. A system where “I forgot my password” ends in permanent loss of funds is not a system designed for humans. It’s a system designed by engineers who find the current model intellectually interesting.
Predictable costs. EIP-1559 replaced the first-price auction with a base fee plus priority fee, which made gas estimation far more reliable. But “reliable” is not the same as “predictable to a non-technical user.” Paymasters (another ERC-4337 feature) allow dApps to sponsor gas on behalf of users entirely — eliminating the concept of gas fees from the end-user experience for common actions. Several L2 dApps have started doing this for their core flows. It should be standard.
Chain-agnostic asset view. One interface that shows all your assets across all chains without requiring you to know which chain each one lives on. Zerion and Rainbow Wallet both do this reasonably well today. It should be table stakes, not a differentiator. The user should never need to think about which chain their USDC is on.
Simulation before confirmation. Tenderly, Blowfish, and a handful of others offer transaction simulation — run the transaction against a fork of current chain state and show the user exactly what will change: “You will send 1 ETH. You will receive 3,241 USDC. Contract 0x… will be granted no ongoing approvals.” This is how every wallet confirmation should work, everywhere. It exists. It’s not being used at scale.
Something I Built: create-rainbow-app
Talking about UX problems without trying to fix them felt hypocritical, so I built something.
create-rainbow-app is a CLI tool that scaffolds a production-ready Web3 dApp from scratch. The first two hours of every new dApp project are always the same: bootstrap Next.js, install RainbowKit, wire up wagmi, configure providers, set up shadcn/ui, write the Web3 provider wrapper, drop in a wagmi config, add an ABI directory. It’s the same boilerplate every time, and every Web3 developer rewrites it from scratch every time.
bun create rainbow-app@latest my-dapp
# or
npx create-rainbow-app@latest my-dapp
The CLI is fully interactive. It walks you through four choices via arrow-key prompts before writing a single file:
- Router — App Router (recommended) or Pages Router
- Linter — ESLint or Biome
- React Compiler — opt in or out
- Git — initialize a repo or skip
From those answers it runs create-next-app with the right flags (--ts, --tailwind, --src-dir, your linter choice, your router choice), then immediately layers the Web3 stack on top. Here’s exactly what gets written:
Installed packages
@rainbow-me/rainbowkit— wallet connection UI, ConnectButton, chain switching modalwagmi v2— hooks for reading/writing contracts, watching events, managing wallet stateviem v2— the underlying transport and ABI encoding layer@tanstack/react-query— required peer dep for wagmi’s async state managementshadcn/ui— initialized withButtonas the seed component; Tailwind-based, fully unstyled to customize
Generated file structure
src/
├── wagmi.ts # wagmi config with RainbowKit connector, chains pre-wired
├── abi/
│ └── demo.json # placeholder ABI to show the pattern
├── lib/
│ └── fonts.ts # font setup extracted into its own module
└── provider/
└── web3provider.tsx # wraps WagmiProvider + QueryClientProvider + RainbowKitProvider
For App Router, layout.tsx is updated to import and wrap the tree in Web3Provider. For Pages Router, _app.tsx gets the same treatment. Either way, the first bun dev starts with wallet connection already working — no manual wiring required.
The package auto-detects your environment: Bun is used if available, Yarn as the fallback. It also writes an AGENTS.md to the project root — a context file for AI coding assistants that describes the stack and project structure so tools like Copilot or Cursor start with accurate context rather than guessing.
It doesn’t solve the end-user UX problems argued about above. But it solves a real developer UX problem: the setup tax every Web3 project pays before a single line of product code gets written. If scaffolding a dApp takes 30 seconds instead of two hours, more developers actually start. More starts means more shots at someone shipping the wallet abstraction layer, the transaction simulation UX, the fiat-denominated gas display — all the things this ecosystem still needs someone to build properly.
Find it on npm and GitHub. MIT licensed — use it, fork it, improve it.
The Bottom Line
Blockchain technology is genuinely interesting. Smart contracts are a real primitive that enables things that weren’t possible before — programmable escrow, on-chain governance, permissionless liquidity pools, verifiable provenance. The trustless, permissionless nature of well-designed protocols has real value that isn’t available anywhere else.
But we spent a decade optimizing the protocol layer and basically ignored the interface layer. Consensus mechanisms got more efficient. Cryptography got faster. Block times dropped. Gas costs fell by orders of magnitude. And the UX in 2024 is only marginally better than it was in 2018. We rationalized bad UX as a feature — if you can’t handle the complexity, this isn’t for you — when really it was just incomplete work.
The next wave of Web3 adoption won’t be driven by the next bull run or the next killer app. It’ll come when signing a transaction feels as easy as tapping “pay” on your phone. When recovering a wallet is as stress-free as resetting a password. When the underlying chain is as invisible to users as the AWS region their bank runs on. When a $0.03 gas fee is shown as $0.03 and not as 0.0000089 ETH (12 gwei).
The tools to build that experience exist today: ERC-4337 for account abstraction, paymasters for gas sponsorship, passkeys for key management, transaction simulation for confirmation clarity, chain-abstraction layers for hiding the multi-chain mess. None of this requires new cryptography or new consensus research. It requires product thinking and the discipline to prioritize the experience of people who aren’t already true believers.
Until that work gets done seriously, we’re still building for ourselves. And we shouldn’t act surprised that only we showed up.
Building something that actually fixes the UX? I’d genuinely like to hear about it.