Batches & commitments
How off-chain fills become on-chain merkle commitments, and how to verify one.
Matching is off-chain, so the ledger needs a compact, verifiable summary of what happened. That summary is a two-level merkle structure committed on a fixed cadence.
The two levels
Per-user tree → UserBatch
Every fill for a party becomes a leaf. Leaves accumulate into a per-user merkle tree; the root
is committed on-chain as a UserBatch contract, chained to that user's previous batch.
Global tree → BatchManifest
Each UserBatch root is itself a leaf of the global tree for that cadence window. Its root is
committed as a BatchManifest, numbered monotonically by batchNum.
fill fill fill fill fill
└──┬──┘ │ └──┬──┘
▼ ▼ ▼
user tree (Alice) user tree (Bob)
root root
└────────┬───────────┘
▼
global tree ──► BatchManifest #1421 (on-chain)Why chained per-user batches
Chaining each UserBatch to its predecessor means a user's whole trading history is a hash chain
they can walk independently. Dropping or reordering one batch breaks the chain — the operator
cannot quietly rewrite an interval.
GET /v1/users/:party/user-batches returns them oldest first precisely so the chain can be
verified in order.
Reading commitments
| Route | Returns |
|---|---|
GET /v1/batches?limit | batch_manifests, newest first |
GET /v1/batches/:batchNum | One manifest |
GET /v1/user-batches?limit | All user batches |
GET /v1/users/:party/user-batches?limit | One user's chain, oldest first |
Verifying
The BFF exposes cross-checks that compare what the engine claims against what the ledger records. These are the audit surface — they do not require trusting engine self-reporting.
# Every user batch: engine leaf set ↔ on-chain UserBatch root
curl 'http://localhost:4000/v1/verifications/user-batches?status=mismatch&limit=50'
# Every manifest: engine global root ↔ on-chain BatchManifest
curl 'http://localhost:4000/v1/verifications/manifests?status=mismatch&limit=50'A non-empty status=mismatch result is an incident, not a warning. It means the off-chain engine
and the on-chain commitment disagree about what was traded.
Cadence trade-off
| Shorter cadence | Longer cadence |
|---|---|
| Faster finality for withdrawals | Fewer ledger writes, lower cost |
| More on-chain traffic | Larger exposure window if the engine misbehaves |
Withdrawals are gated on the batch containing the relevant fills being committed — so cadence is directly the user-visible withdrawal latency. See Withdrawals.