System Design: Designing a Digital Wallet and Ledger System
Designing a digital wallet (like PayPal, Venmo, or AliPay) is a masterclass in data integrity. In fintech, "eventual consistency" is often not enough. You need 100% accuracy, strict ACID compliance, and a verifiable audit trail for every cent moved.
1. Core Requirements
- Wallet Balance: Real-time view of a user's funds.
- Transactions: Transferring money between wallets.
- Ledger: An immutable, append-only record of all financial movements.
- High Availability: Users must be able to pay 24/7.
- Scalability: Handling thousands of transactions per second.
2. Double-Entry Bookkeeping (The Golden Rule)
In professional finance, you never just "update a balance." You record a transaction with at least two entries: a Debit and a Credit.
- The Equation:
Sum(Debits) + Sum(Credits) = 0. - Example: If User A sends 0 to User B:
- Account A: -0 (Debit)
- Account B: +0 (Credit)
- Benefit: This provides a self-verifying audit trail. If the balance doesn't match the sum of ledger entries, you know exactly when and where the error occurred.
3. Storage Architecture: SQL vs. NoSQL
- The Choice: Relational Databases (PostgreSQL/MySQL) are the industry standard for Ledgers.
- Why? They provide native ACID transactions. You can wrap the balance update and the ledger entry in a single database transaction.
- Scaling SQL: Use Sharding (by
user_idoraccount_id) to distribute the load across multiple database nodes.
4. Handling Distributed Transactions (Saga Pattern)
When a transaction spans multiple shards or services (e.g., User A on Shard 1, User B on Shard 2):
- Option A: 2-Phase Commit (2PC): Strong consistency but slow and prone to blocking.
- Option B: Saga Pattern: A sequence of local transactions with compensating actions.
- Reserve 0 in Account A (State:
PENDING). - Credit 0 to Account B.
- Finalize Account A.
- If step 2 fails: Run a compensating transaction to release the 0 back to Account A.
- Reserve 0 in Account A (State:
5. Ensuring Idempotency
In payment systems, "Double Charging" is a nightmare.
- Idempotency Key: Every request from the client must include a unique
request_id. - The Check: Before processing, the server checks the database for that
request_id. If it exists, it returns the cached result of the previous attempt.
6. Real-time Balance Caching
Querying the Ledger for every balance check is too slow.
- The Solution: Store the "Current Balance" in a high-speed cache like Redis.
- Consistency: The SQL database remains the source of truth. Redis is updated after the SQL transaction commits.
Summary
The secret to a robust digital wallet is Immutability. By treating the Ledger as the source of truth and using Double-Entry bookkeeping with strict ACID transactions, you can build a financial system that is both scalable and perfectly accurate.
