Deposit and Withdrawal System Development
Deposit and withdrawal system is most security-critical part of crypto exchange. Real user funds are stored and moved here. Every error is direct financial loss. Let's discuss architecture emphasizing security and fault resilience.
Deposit Architecture
Generating Deposit Addresses
Each user gets unique deposit address for each network. Two approaches:
HD Wallet (Hierarchical Deterministic): From one master-seed deterministic key tree is generated per BIP-32/BIP-44. For Bitcoin: m/44'/0'/0'/0/{user_index}. For Ethereum: m/44'/60'/0'/0/{user_index}.
Master-seed stored in HSM (Hardware Security Module) or encrypted vault (HashiCorp Vault). Public keys for address generation in database, private keys for signing only in HSM.
Shared address + memo: One address for entire exchange, user specifies memo/tag on send. Used for Ripple (XRP), Stellar (XLM), Cosmos. Cheaper to maintain, but memo error = fund loss.
Monitoring Incoming Transactions
Deposit monitoring service subscribes to blockchain events:
-
EVM chains:
eth_subscribe("logs")via WebSocket + polling fallback -
Bitcoin:
zmqpubrawtxfrom Bitcoin Core + periodic scans - TRON: TronGrid WebSocket or TronScan API polling
Confirmations and Finality
Minimum required confirmations depend on network and amount:
| Network | Min Confirmations | Reason |
|---|---|---|
| Bitcoin | 3–6 | Reorg probability |
| Ethereum | 12–20 (or finalized) | Post-merge finality |
| Polygon PoS | 100–256 | Checkpoint finality |
| BSC | 15–20 | PoSA, more centralized |
| TRON | 19 | Solid consensus |
| Solana | 32 (finalized) | Tower BFT |
After reaching confirmation threshold deposit credited. Until then — pending status. Show user pending deposits with progress indicator.
Reorg handling: store block_hash with block_number. On reorg detection (hash changed), mark affected transactions as reorged and restart monitoring.
Consolidation (Sweeping)
Deposit addresses — thousands or millions. Storing ETH on each address expensive and unsafe. Need automatic consolidation to master hot wallet.
For ERC20 tokens task complicated: need ETH on deposit address for gas. Solutions:
- Gas station: send ETH before sweep, then sweep tokens
- Gasless sweep via EIP-2612/permit: if token supports permit, exchange pays gas
- Batch sweep via multicall: one call collects funds from multiple addresses
Withdrawal Architecture
Queue and Approvals
Withdrawal passes several stages:
REQUESTED → VALIDATED → APPROVED → SIGNING → BROADCASTING → PENDING → CONFIRMED
VALIDATED: balance check, limit checks, AML/KYC. If passed — reserve funds.
APPROVED: for large amounts — manual review by operator or multi-sig (M-of-N approvals).
SIGNING: transaction signing in HSM or cold wallet system. Never sign on server where approval logic lives — separation of duties.
BROADCASTING: send transaction to network. Can't cancel after this (theoretically).
Gas Management
Exchange pays withdrawal gas. Need gas management system:
- Monitor
eth_gasPrice/ EIP-1559baseFee+maxPriorityFee - Gas budget: account for gas cost in withdrawal fee or separate charge
- RBF (Replace By Fee) for stuck Bitcoin transactions
-
EIP-1559 bump: on stuck Ethereum transaction — send with same nonce, increased
maxFeePerGas
Notifications and Statuses
User must see withdrawal state in real time:
- WebSocket push on every status change
- Email/Telegram notifications at key stages (approval, send, confirmation)
- Transaction hash with explorer link immediately after broadcast
Security
Critical Checks
Whitelist addresses: require adding new address 24–48 hours before withdrawal to it. On add — email confirmation + 2FA. Prevents instant withdrawal on account compromise.
Anti-phishing: display anti-phishing code in emails and UI (user sets it).
Withdrawal limits: daily limits by KYC level. Exceeding triggers manual review.
Velocity checks: multiple withdrawals in short time → temporary block and notification.
Hot/Warm/Cold Wallet Segregation
- Hot wallet: small operational reserve (10–20% daily withdrawal volume), always online, automatic withdrawals
- Warm wallet: multi-sig (2-of-3 or 3-of-5 hardware keys), tops up hot wallet daily
- Cold wallet: offline storage, only for large reserves, manual access procedure
Distribution: 5–10% hot, 15–20% warm, 70–80% cold.
Anomaly Monitoring
type WithdrawalGuard struct {
limits map[UserID]DayLimits
velocities map[UserID][]time.Time
}
func (g *WithdrawalGuard) Check(req WithdrawalRequest) error {
// 1. Daily limit
if g.limits[req.UserID].Used + req.Amount > g.limits[req.UserID].Max {
return ErrDayLimitExceeded
}
// 2. Velocity: max 5 withdrawals per 10 minutes
recent := g.getRecentWithdrawals(req.UserID, 10*time.Minute)
if len(recent) >= 5 {
return ErrVelocityLimitExceeded
}
// 3. New address — only if quarantine passed
if !g.isWhitelistedAddress(req.UserID, req.Address) {
return ErrAddressNotWhitelisted
}
return nil
}
Infrastructure and Reliability
Own node vs API provider: own full node gives reliability and independence. API providers (Alchemy, QuickNode, Infura) — convenience but dependency. For production: multiple providers + own node, automatic failover.
Idempotency: each withdrawal request has unique withdrawal_id. Reprocessing same ID doesn't create duplicate transaction. Critical for recovery after failures.
Transaction monitoring: after broadcast — periodic transaction status check. If not in mempool after N minutes — consider dropped, resend with correct nonce.
Development Timeline
| Component | Timeline |
|---|---|
| Ethereum + ERC20 deposits/withdrawals | 4–6 weeks |
| Bitcoin | 3–4 weeks |
| TRON | 2–3 weeks |
| Each additional EVM network | 1–2 weeks |
| Multi-currency hot wallet management | 3–4 weeks |
| Admin dashboard for monitoring | 2–3 weeks |
Full system for 5-7 networks with HSM integration, AML checks, admin interface — 3–5 months.







