Guaranteeing that the internal ledger and the actual on-chain USDT balance can never silently diverge — while never letting the API server hold a key that can move funds. Once the two ledgers drift, every subsequent balance is wrong and the only honest recovery is to freeze withdrawals.
What I did about it
Key custody was split out entirely. The API and worker are given only an xpub — they can derive unlimited deposit addresses and watch them, but derivation from a public extended key mathematically cannot produce a spending key.
Signing lives in a separate service reached over mutual TLS, outside the repository, hand-written only. An attacker with full control of the API server can read data and derive addresses, but cannot move a single USDT.
Balances are never a stored number. Every movement is a double-entry journal posted through one method, in BIGINT smallest units, passed as strings over the wire so JavaScript float precision never touches them.
State transitions go through a trade_transitions table enforced by a database trigger — then proven, not asserted: 100% branch coverage on ledger, escrow and fees, with fault-injection tests that deliberately trigger serialization failures and deadlocks.
What I rejected, and why
An ORM with a balance column and optimistic locking would have been a fifth of the work. Rejected because it makes the current number authoritative and the history advisory — backwards when a user disputes a trade or a regulator asks how a figure was reached. Kysely over an ORM follows the same reasoning: on money paths the SQL should be readable in review, not inferred from decorators.
Prometheus and a monitoring stack are wired but no baseline was ever captured, so there is no answer to "is this slower than last month". I would capture p95 latency on the trade endpoints before launch, not after the first complaint.