Titandocs

Trust model

What each participant can and cannot do, and which properties survive a compromise of each component.

Titan is non-custodial in a specific, checkable sense: no component between the wallet and the engine can produce a valid order signature.

The three keys

Prop

Type

Compromise analysis

CompromisedAttacker gainsAttacker cannot
BFFRead every user's projected history; observe the firehosePlace, cancel, or modify any order — no signature capability
Session keyTrade as that user until expiresAtWithdraw (withdrawals are on-chain, wallet-signed)
IndexerCorrupt the projectionChange custody or engine state — Postgres is downstream of both
EngineMis-match, mis-report positionsMove collateral without an on-chain withdrawal approval
Wallet keyEverything for that partyAffect any other party

A session key is a trading credential, not a custody credential. Its blast radius is bounded by expiresAt and by the fact that withdrawal requests are contracts on the ledger, signed by the wallet key.

Why the BFF forwards headers verbatim

The obvious alternative — the BFF re-signs on behalf of the user — would collapse the whole model. It would need the session private key, which would make a BFF breach equivalent to a wallet breach for every active trader.

So the contract is deliberately awkward: the browser produces the canonical bytes, signs them, and sends three headers the BFF is required to copy without inspection.

POST /v1/orders
X-User:        Alice::1220abcd…
X-Session-Id:  sess_7f2c…
X-Session-Sig: 3a91f0…            # hex(ed25519 sig over canonical bytes)
Content-Type:  application/json

{"market":"BTC-USDCX","side":"buy","size":"0.05","price":"64000","nonce":42}

If the body and the signed bytes disagree by a single byte, the engine rejects. This is the property that makes the pass-through safe.

Auditability

Every fill lands in a per-user merkle tree; every batch of trees produces a manifest committed on-chain. That gives two independent verification paths, both exposed by the BFF:

RouteChecks
GET /v1/verifications/user-batchesEngine's per-user leaves ↔ on-chain UserBatch
GET /v1/verifications/manifestsEngine's batch manifest ↔ on-chain BatchManifest

A mismatch there is the canary for engine misbehaviour — it does not require trusting the engine's own reporting.

On this page