Architecture
How the Medici Protocol is built — from Canton ledger to frontend.
System Diagram
Layer Descriptions
Layer 1 -- Canton Ledger (DAML)
The foundation. All contracts live on the Canton Network, a privacy-preserving blockchain from Digital Asset. DAML contracts define the protocol's rules: what a vault is, how P and N tokens work, how settlement happens. Once deployed, DAML contracts are immutable (upgradable via SCU -- Smart Contract Upgrade for minor changes, or migration for major ones).
Key properties: Sub-transaction privacy (only parties to a contract see its details), no public mempool (no front-running or MEV), ledger time for maturity checks, causality enforcement via DAML's contract model.
Layer 2 -- Ledger Service (Go)
A single Go binary that absorbs all 8 Canton JSON API quirks and exposes a clean
REST + WebSocket API. This is the recommended interface for all application
code. It normalizes created-event payloads (created.payload ?? created.createArguments),
handles token refresh (5-min lifespan with retry), wraps commands into proper Canton format,
and manages party/user lifecycle.
For non-custodial external parties, it also owns the Path C prepare/execute flow: the service prepares transactions, relays prepared hashes to the wallet for signing, and submits the signed transaction -- the service never sees a private key.
Layer 3 -- Agent SDK (TypeScript)
Shared library providing:
- LedgerClient -- typed wrapper around the Ledger Service API
- StateStore -- SQLite-backed persistent state, survives restarts and replays missed events
- EventBus -- publish/subscribe for agent coordination
- Agent Base Class -- lifecycle (start/stop/tick), health checks, structured logging
- Safety -- per-agent constraint enforcement (circuit breaker, rate limits, coherence checks)
Layer 4 -- Specialized Agents
Independent, single-purpose agents that execute specific strategies:
| Agent | Responsibility |
|---|---|
| OracleAgent | Publishes live price observations (CoinGecko) and the public PublishedPrice feed |
| RebalanceAgent | Monitors vault delta, executes rolls when price approaches 1.5x strike |
| StrategyAgent | Translates user intents into agent configurations, reports drift |
| SettleAgent | Watches maturity, fetches oracle price, submits settlement claims |
| PositionMonitorAgent | Tracks vault drift, M2M value, delta exposure |
| SwapTakerAgent | Monitors SwapOffer contracts, auto-fills matching offers |
Layer 5 -- Agent Runtime
The runtime orchestrator manages the fleet: tick scheduling (every N seconds), singleton enforcement (one instance per agent type), health checks with auto-restart, process supervision, and structured logging. Agents register with the runtime, which handles the lifecycle.
Layer 6 -- Intent Expression (Off-Chain)
Users express what they want through structured intents. A StrategyIntent
might say "Track $50k BTC/USDC with standard strategy, max 15 bps/roll slippage."
The StrategyEngine validates constraints, applies parameter defaults, and configures
agents. A constraintHash links the off-chain intent to on-chain verification.
Layer 7 -- On-Chain Intents (DAML)
Intents recorded on the ledger provide an immutable audit trail. Templates include
IntentAnnouncement (public signal of user intent), VaultComplianceRegistry
(per-vault compliance tracking), and AgentMessage (inter-agent coordination).
The DAML layer enforces lifecycle: an intent is created, agents reference it, and settlement
verifies against it.
Layer 8 -- Frontend Interfaces
Three interface paths:
- Chat / NL Interface -- natural language intent expression ("Track $50k BTC/USDC")
- Strategy Dashboard -- drift tracking, roll history, agent status, M2M values
- Manual Trading -- existing Trade, Earn, Swap, Admin pages as escape hatch
Data Flow
Auth Flow
Multi-Party Propose/Operator-Execute Pattern
The protocol uses a two-phase pattern for operations that require multiple parties to authorize. This is Canton's equivalent of a multi-sig wallet (like Gnosis Safe).
Key Design Decisions
- No contract keys -- templates use
ContractIdfor cross-contract references, avoiding key-based lookup complexity - Pure verification -- invariant checks are closed-form math
(
verifyInvariantetc.), not runtime assertions - Upgrade-transparent package IDs -- using the
#package-nameform instead of content hashes so references never go stale across DAR rebuilds - Singleton price feed -- the oracle archives the prior PublishedPrice in the same transaction as each new publish, so at most one is active per ticker
- Bearer token gates service; signature authorizes ledger -- the RS256
token proves who is calling the Ledger Service; the wallet's Ed25519 signature over
preparedTransactionHashauthorizes the on-ledger action - Coherence-gated multi-attestation -- divergent oracle observations trigger fallback, not bad settlements