Case Study: Distributed Crypto Exchange API & Swap Engine
The Engineering Challenge
Building an automated cross-currency swap framework requires handling non-deterministic, public distributed ledgers. The core constraints resolved over a year of rigorous architectural iteration include:
- Concurrency Isolation: Mitigating block-sync and transaction race-conditions by removing traditional database table locks during high-throughput transfer volumes.
- Infrastructure Decoupling: Migrating away from a highly fragile "individual wallet-per-user" model to a hardened "Master Wallet with Account-Based Indices" architecture.
- Network Resilience: Shielding customer API runtimes from high-latency cryptographic daemon node processing (e.g.,
bcoin and monero-ts synchronization delays).
Logical Service & Data Dependency Design
The following topology illustrates the asynchronous processing flow of the wallet engine. Transactions are safely isolated into Redis-backed queues before consuming workers execute sequential wallet daemon RPC updates.
graph TB
subgraph Clients["📱 Ingress & Gateway Layer"]
wfe["WFE (Web Front-End)"]
adminDash["Admin Queue Dashboard
(BullBoard + Bearer Auth)"]
apiGateway["Express.js Core API Gateway
/api/monero-account/* & /api/bitcoin/*"]
end
subgraph Queues["⚡ Asynchronous Event Broker (BullMQ)"]
txQueue["Monero/BTC Transaction Queue
(Attempts: 3, Exponential Backoff)"]
taskQueue["Scheduled Tasks Queue
(Cron: 3min / 5min Balance Sync)"]
ratesQueue["Rates Fetching Queue
(Attempts: 5, Memory-Cached)"]
end
subgraph Processing["⚙️ Stateless Worker Nodes & Business Logic"]
txWorker["Transaction Processor Worker
(Saga State Machine Handling)"]
taskWorker["Scheduled Maintenance Worker
(Balance Sync / Block Monitors)"]
ratesWorker["Exchange Rate Aggregate Worker"]
subgraph Services["Core Abstract Engines"]
btcService["Bitcoin Wallet Manager
(bcoin Library Abstraction)"]
xmrAccountService["Monero Account-Based Service
(moneroAccountClient / monero-ts)"]
ownershipService["Wallet Ownership Manager
(State Transfers: Order ➔ Escrow ➔ Vendor)"]
end
end
subgraph Cache["🛑 In-Memory State & Cache Layer (Redis)"]
redisMap["bitcoin:order:account:map
monero:order:account:map"]
redisTag["monero:tag:order_{orderId}
(Account Indices Mapping)"]
redisHistory["ownership:history:{walletId}"]
end
subgraph DB["💾 Hardened Enterprise Storage"]
mysqlDB[("MySQL Database
(Administrative Interface State)")]
end
subgraph Chains["⛓️ Cryptographic Network Integrations"]
bcoinNode["Bitcoin RPC Node
(Master Account Wallets)"]
moneroRPC["Monero Wallet RPC Daemon
(Master Multi-Account Architecture)"]
end
%% Routing Data Flow
wfe -->|"HTTPS / REST"| apiGateway
adminDash -->|"Admin Dashboard Route"| apiGateway
apiGateway -->|"Producer: Add Jobs"| txQueue
apiGateway -->|"Producer"| taskQueue
apiGateway -->|"Producer"| ratesQueue
%% Worker Execution
txQueue -->|"Consumer"| txWorker
taskQueue -->|"Consumer"| taskWorker
ratesQueue -->|"Consumer"| ratesWorker
%% Service Interaction
txWorker --> Services
taskWorker --> Services
ratesWorker --> Services
%% Redis State Maps
Services -->|"Atomic State Reads / Token Sync"| Cache
apiGateway -->|"Direct Metadata Checks"| Cache
%% Database Operations
apiGateway -->|"Persist Admin Metrics"| mysqlDB
%% RPC Daemon Operations
btcService -->|"bcoin RPC"| bcoinNode
xmrAccountService -->|"createAccount / tagAccount"| moneroRPC
%% Class Definitions for Theme Continuity
classDef clientNet stroke:#38bdf8,fill:#0c4a6e,color:#cbd5e1;
classDef apiNet stroke:#e879f9,fill:#581c87,color:#cbd5e1;
classDef workerNet stroke:#2dd4bf,fill:#115e59,color:#cbd5e1;
classDef cacheNet stroke:#a78bfa,fill:#2e1065,color:#cbd5e1;
classDef storageNet stroke:#fb923c,fill:#431407,color:#cbd5e1;
classDef nodeNet stroke:#f87171,fill:#450a0a,color:#cbd5e1;
class Clients clientNet;
class Queues apiNet;
class Processing workerNet;
class Cache cacheNet;
class DB storageNet;
class Chains nodeNet;
Core Architectural Pillar Deep Dives
1. Hardened Account-Based Order Flows
To preserve scalability, both Bitcoin and Monero runtimes share matching abstract account-based patterns in their master storage nodes. The entire transactional lifecycle is strictly managed via microservice hooks:
2. Asynchronous Processing via BullMQ Worker Nodes
API gateways handle customer inputs instantaneously by delegating high-latency crypto operations out to dedicated, Redis-backed transaction queues.
- Monero Transaction Queue: Handled with a robust exponential backoff strategy (3 attempts, 5000ms delay). Workers consume structured payload payloads, invoking the
sendFromUser() utility methods within isolated containers. - Cron Scheduled Tasks: A centralized
QueueScheduler maps out recurring background loops, enforcing structural integrity across volatile daemon endpoints:
- Every 3 Minutes: Scans the chain state to check pending transaction confirmations.
- Every 5 Minutes: Forces a strict balance-sync cross-check across all Monero subaddresses via the master
syncBalances() controller. - Every 15 Minutes: Triggers external exchange aggregators to compute fluid, memory-cached transactional currency conversion values.
3. Low-Latency Redis Schema Structure
The persistence strategy relies heavily on specialized key structures to handle state transformations in sub-millisecond durations:
# Bitcoin Key Ingress Topology
bitcoin:order:account:map # Global Order ID to Account string allocation
bitcoin:order:account:[orderId] # Specific order runtime metadata payload
ownership:history:[walletId] # Historical distributed ledger proof trail
# Monero Account-Index Topography
monero:order:account:map # Order ID mapped to explicit account index numbers
monero:tag:order # Global tracking tag arrays
monero:tag:order_[orderId] # Order context tags validated during finalization