Crypto Wallet Interface
Wallet integration, token swap and liquidity pool interfaces — and an early lesson in building UI where the backend is a public blockchain that fails in ways a REST API never does.
- Client
- Web3 product
- Year
- 2021—2022
- Role
- Web Developer
- Team
- Small product team
Context
A swap interface looks like a form with two inputs. It is not. Prices move between render and confirmation, wallets behave differently from one another, and a transaction can sit pending for minutes before failing for reasons the UI has to explain.
The existing codebase had grown quickly and needed restructuring alongside the feature work.
Constraints
- Wallet variability
- Different wallet providers expose different behaviour for the same operation.
- Prices move
- Quoted rates go stale between quote and confirmation, which is a UI problem before it is a chain problem.
- Legacy code
- Refactoring for maintainability had to happen while features continued shipping.
Architecture
A React SPA over a wallet abstraction layer, with price feeds polled independently of the swap form so a stale quote never silently becomes a submitted transaction.
- Wallet interaction sits behind one interface, so provider differences are handled in a single place rather than at every call site.
- Slippage tolerance is explicit user state rather than a hidden default — the user sets the bound they are willing to accept.
- Transaction history is treated as its own view of chain state, not as a log of what the UI happened to do.
Key decisions
One wallet abstraction layer
Provider quirks are contained in a single module instead of leaking into every component that touches the chain.
An extra indirection to step through when debugging a provider-specific failure.
Slippage as visible user state
The user sets and sees the bound they are accepting, rather than discovering a hidden default after a bad fill.
More surface area in the UI, and a setting that inexperienced users can get wrong.
Refactor the legacy codebase alongside feature work
Incremental restructuring kept delivery moving without stopping for a rewrite that would never have been approved.
Two conventions coexisted in the codebase for a while, which is its own kind of cost.
Outcome
Swap and liquidity pool interfaces shipped with wallet integration, live pricing, slippage control and transaction history.
What I’d revisit
Transaction state deserved an explicit state machine. Modelling pending, confirmed, failed and dropped as ad-hoc booleans is exactly how a UI ends up claiming something succeeded when it did not.
The error taxonomy for chain failures was thin. Users saw generic messages where the underlying failures were distinct and, in several cases, actionable.
Diagrams are drawn from scratch and module names describe the domain. No client assets, interfaces or internal naming appear here.