Skip to content

Architecture

This page explains how the pieces fit together — what talks to what, why the system is split the way it is, and where the trust boundaries fall.

System topology

flowchart LR
  UI["Frontend<br/><i>Next.js :3001</i><br/>/portfolio /passport /agent /trade"] --> API["zkde backend<br/><i>FastAPI :8003</i>"]
  API --> POL["Policy + trust"]
  API --> MKT["Opportunities + adapters"]
  API --> EXEC["Execution builders"]
  API --> SEQ["Proof sequencer bridge"]
  SEQ --> OBS["obsqra backend<br/><i>:8002</i>"]
  OBS --> MAD["Madara L3<br/><i>:9944</i>"]
  OBS --> L2["Starknet L2"]
  EXEC --> L2
  MAD --> RCPT["Receipts + status"]
  L2 --> RCPT
  RCPT --> UI

The frontend is a Next.js app that presents several product surfaces — /portfolio and /passport are live on Starknet mainnet, while /agent (Capital OS) and /trade are on Sepolia. It talks exclusively to the FastAPI backend on port 8003 — the frontend never calls proof services or chains directly.

The backend is the orchestration layer. It handles four categories of work:

  1. Policy + trust — reputation queries, risk passports, compliance checks, session key management
  2. Opportunities + adapters — market surface data, pool metadata, adapter routing for Ekubo/lending/staking
  3. Execution builders — calldata construction, simulation, wallet signing preparation
  4. Proof sequencer bridge — forwards proof artifacts to the obsqra backend for aggregation and settlement

The obsqra backend (:8002) is a separate service that handles proof aggregation and settlement. It bridges facts to either the Madara L3 appchain (:9944) for dedicated proof storage, or directly to Starknet L2 for contract settlement. Both paths produce receipts that flow back to the UI.

Why two backends?

The split between the zkde backend (8003) and the obsqra backend (8002) isn't arbitrary. The zkde backend is product-oriented — it knows about users, sessions, policies, and UI state. The obsqra backend is infrastructure-oriented — it knows about proof aggregation, settlement paths, and chain state. Keeping them separate means the proving infrastructure can evolve independently of the product surface.

Component responsibilities

ComponentPortWhat it owns
Frontend (Next.js)3001UI surfaces, wallet connection, signing UX, state rendering
zkde backend (FastAPI)8003Orchestration, policy enforcement, API composition, receipt lifecycle, WebSocket events
obsqra backend8002Proof aggregation, sequencing, settlement bridge, chain indexing
Madara L39944Dedicated appchain for proof fact registration — separate block space for proof throughput
Starknet L2Primary settlement layer — verifier contracts, registries, adapters, privacy pools
nginx443Reverse proxy, TLS termination, static docs serving, cache headers

Verification modes

Not every action goes through the same level of proof scrutiny. The system uses three modes, applied per-flow:

ModeWhat happensWhen you'd see it
Gate-criticalProof required before execution proceeds. No proof → no execution.Deploy to Ekubo, automated rebalance, autonomous mode
AdvisoryRisk signal returned, but execution isn't blocked. The UI shows warnings.Pool safety check, pre-trade risk scan
Wallet-firstUser signs and executes, then the system reconciles. Trust the wallet.Manual swap, manual LP adjustment

This isn't a compromise — it's a design choice. Gate-critical mode for everything would make the app unusably slow for operations where the user is already signing with their own wallet. Wallet-first mode for everything would defeat the purpose of proof-gating. The system uses the right mode for each flow.

Trust domains

Reputation, credit, and governance are designed as separate trust domains. A high reputation tier doesn't automatically grant lending capacity. A lending history doesn't automatically confer governance voting power. Signals in one domain should not silently grant rights in another.

This boundary separation is partially implemented today and will be fully formalized in V3. The intent is to prevent the kind of composability risk where a single exploit in one domain cascades across the system.

Health checks

EndpointServiceWhat it tells you
GET /healthzkde backendBasic liveness — if this fails, the API is down
GET /api/v1/zkdefi/proofs/sequencer-statuszkde backendWhether the proof sequencer bridge is connected
GET /api/v1/aggregation/statsobsqra backendAggregation stats — proof throughput, queue depth
GET /api/v1/aggregation/madara/healthobsqra backendMadara L3 connectivity

Runtime lifecycle

Here's what happens when a user interacts with the system, end to end:

  1. Load trust context — the frontend fetches reputation, passport, and policy state from /profile
  2. Load opportunities — adapter metadata and market surface data from the backend
  3. Evaluate gates — the UI checks which actions are available given the user's trust context
  4. Build and simulate — the backend constructs calldata and runs simulation
  5. Sign and submit — the user signs with their wallet, tx goes to chain
  6. Reconcile — receipts and outcomes flow back into UI state
  7. Settlement — for proof flows, settlement updates arrive through the sequencer path and get written to registries

Steps 1–3 happen on every page load. Steps 4–7 happen per action.

Source references

For deeper architecture documentation inside the repo:

  • docs/ARCHITECTURE.md — internal architecture details
  • docs/AGENT_FLOW.md — how agent actions move through the pipeline
  • docs/MADARA_L3_APPCHAIN_ARCHITECTURE.md — Madara L3 design and configuration
  • docs/CAPITAL_OS_PORTABLE_REPUTATION_V3_SPEC.md — V3 trust domain specification

Built by Obsqra Labs