Digital Wallet

Stored balances and peer-to-peer transfers

Design a wallet that holds users' money as balances, moves it between wallets instantly, places and releases holds, and takes money in from banks and back out, without ever creating, losing or overspending a cent.

Overview

A digital wallet keeps money for its users as a balance and lets them move it: to a friend, to a shop, back to their bank. Unlike a payment gateway, which forwards card payments to banks, a wallet is itself the record of who owns how much. When Ana sends Ben $25, no bank is involved; the wallet takes $25 off Ana's balance and adds it to Ben's, and the two changes must happen together or not at all.

That makes the wallet a small bank ledger with a very busy front door. The questions an interviewer probes are about concurrency and truth. What stops two payments from spending the same $25? What happens when a transfer and a transfer in the opposite direction lock the same two rows? What does 'balance' mean while a top-up from a bank is still in flight, or a hold is reserving money for a purchase? And what changes when Ana and Ben live on different database shards?

The double-entry ledger itself (entries whose postings sum to zero, reconciliation) is covered in the Payment System topic; this page uses it and focuses on balances, holds and transfers.

Questions to ask first

  • Whose money is it? — Users' funds, held by the wallet provider at a partner bank; the wallet records who owns what
  • One currency? — One currency per wallet; exchange is out of scope
  • Can a balance go negative? — Never through a transfer or hold
  • How fast must a transfer be? — Instant for the sender and receiver; under a second end to end
  • How does money come in and out? — Bank transfers (ACH) that take days and can be returned
  • Scale? — 50 million active wallets, 20 million transfers a day, peak 5 times the average

What you will be able to do

  • Define available, held and pending balances and say which one a transfer may spend.
  • Write a transfer that locks two wallets in a fixed order, cannot overdraw, and is safe to retry.
  • Place, capture and release holds.
  • Handle money arriving from banks days later, and returned weeks later.
  • Keep transfers correct when the two wallets are on different shards, and when one wallet is very hot.

Key concepts

  • Available vs ledger balance
  • Holds
  • Row locks
  • Lock ordering
  • Idempotent transfers
  • Double-entry postings
  • Pending top-ups
  • ACH returns
  • Cross-shard transfer
  • Hot wallets

Functional requirements

  • Show a wallet's available, held and pending balance
  • Send money from one wallet to another; the receiver can spend it at once
  • Place a hold on part of a balance, then capture it (in full or in part) or release it
  • Top up from a linked bank account; cash out to it
  • List a wallet's transactions, newest first

Non-functional requirements

  • A balance never goes below zero through a transfer or a hold
  • Money is never created or lost: every transfer's postings sum to zero
  • A retried transfer request never moves money twice
  • Transfers complete in under 500 ms at p99 (a target we chose)
  • 99.99% availability for transfers (a target we chose); history may lag a few seconds

Interview questions

  • How do you stop a user spending the same money twice?
  • Two opposite transfers deadlock. How do you prevent it?
  • What is the difference between available and pending balance?
  • How do holds work?
  • Ana and Ben are on different shards. How does the transfer stay correct?
  • One merchant receives thousands of payments a second. What breaks, and what do you do?
  • Why keep a balance column at all if the ledger is the truth?
  • How is a wallet different from a payment gateway?

Sign up free to read the full topic

More System Design topics

Start free on Cariara · Coding problems · System design studio