Skip to content
All work
Live · early
Crypto · P2P exchange
2026

QuataTrade

P2P crypto marketplace with escrow

A peer-to-peer USDT marketplace for Central Africa where the platform holds funds in escrow until both sides confirm — with a bank-grade double-entry ledger underneath.

Visit live site
quatatrade.com

Role

Lead developer

Client

QUATA Digital Enterprise

Status

Live · early

Year

2026

100%

Branch coverage on money paths

554

Test blocks

9

Escrow states

62k

Lines of code

8

Admin roles

0

Spend keys on the API server

The hardest problem

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

01

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.

02

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.

03

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.

04

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.

What I’d change

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.

Built with

NestJS 11FastifyKyselyPostgreSQL 16RedisBullMQMinIOTronWebNext.js 16VitestTestcontainers

Next case study

QuataAi

Self-hosted AI, no vendor in the loop