ย ย
UMBRAย ย
Privacy-first cross-chain bridge
Swap XMR, BTC, ETH, TON, SOL and more โ trustless MPC threshold signatures, real-time rates, zero KYC.
What is Umbra?
Umbra is a non-custodial cross-chain bridge built around Monero โ the only cryptocurrency with mandatory privacy. It enables trustless swaps between privacy coins and public blockchains using FROST threshold signatures (2-of-3 MPC), meaning no single party ever holds your funds.
What makes Umbra different from every other bridge is the Proof Layer: the bridge does not ask to be trusted โ it produces cryptographic evidence for everything it does, and ships the tools to check that evidence offline.
The Proof Layer
Bridges are the most-hacked primitive in crypto (Ronin $624M, Multichain $126M, Nomad $190M, Harmony $100M โ drained over minutes-to-hours while nothing watched). Umbra's answer is a layer of verifiable accountability that no major bridge ships today:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ PROOF LAYER โ
โ โ
every โ โโโโโโโโโโโโโโ sealed โโโโโโโโโโโโโโโโโโโโ โ
order โโโโโบโ โ Signed โ every 5m โ Transparency โ โ
event โ โ Receipts โโโโโโโโโโโโโโบโ Log (Merkle) โ โ
โ โ Ed25519 + โ โ RFC 6962 proofs โ โ
โ โ ML-DSA-65 โ โโโโโโโโโโฌโโโโโโโโโโ โ
โ โโโโโโโโโโโโโโ โ anchors โ
โ โผ โ
โ โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โ
โ โ Sentinel โ โ Signed โ โ
โ โ 5 guards, 30s โ โ Canary โ โ
โ โ + Isolation โ โ (freshness- โ โ
โ โ Forest (ML) โ โ bound) โ โ
โ โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โฒ verify offline: browser page, single-file
HTML, or pure-stdlib Python CLI โ zero trust
1. Signed swap receipts โ a flight recorder for every order
Every lifecycle event of every order (order_created, status_confirming, status_completed, โฆ) produces a receipt signed with the bridge's Ed25519 key over canonical JSON. Receipts for one order are hash-chained (each embeds the SHA-256 of the previous receipt), so a user holding their final receipt can detect any retroactive edit to their order's history. Receipts carry a hash of the destination address, not the address โ the proof layer never becomes a metadata leak.
curl -s https://your-bridge/v1/proof/receipt/br_ab12cd34ef56 | \
python3 tools/verify_receipt.py receipts - --pin <PUBLIC_KEY>
2. Post-quantum hybrid signatures
Receipts are archival evidence with a multi-decade shelf life. Alongside Ed25519, every receipt and checkpoint is signed with ML-DSA-65 (FIPS 204, CRYSTALS-Dilithium) over the same canonical bytes. Ed25519 stays the cheap, universally verifiable online layer; the ML-DSA signature keeps the archive forgery-proof against a future quantum adversary. Forging history requires breaking both schemes.
3. Transparency log โ Certificate Transparency for a bridge
The audit hash-chain is sealed every few minutes into a signed Merkle checkpoint (the RFC 6962 construction used by Certificate Transparency, validated against the CT known-answer vectors). Anyone can then demand:
- Inclusion proofs โ
GET /v1/proof/inclusion/{audit_id} proves a specific audit entry is committed to by a checkpoint (logโ n hashes, verifiable offline).
- Consistency proofs โ
GET /v1/proof/consistency?old_size=&new_size= proves a newer checkpoint is a pure append-only extension of an older one. History cannot be rewritten without detection.
Mirror GET /v1/proof/checkpoint/latest on a cron job and you become an external witness the operator cannot silently contradict.
4. The Sentinel โ a circuit breaker between the bridge and catastrophe
Five guards run every 30 seconds:
| Guard | Trips when | Would have caught |
|---|
| Outflow velocity | per-chain outbound volume exceeds hourly caps | Ronin, Harmony (key-compromise drains) |
| Order velocity | order creation rate spikes | bot floods, probing attacks |
| Failure spike | failed orders cluster | subsystem exploitation |
| Rate divergence | independent price sources disagree > 5% | oracle poisoning |
| ML anomaly (optional) | Isolation Forest flags order-flow combinations vs the 7-day baseline | drain signatures no fixed threshold expresses |
A trip pauses new intake only โ in-flight swaps keep settling, so a false positive costs minutes of intake, not user funds. The sentinel never auto-resumes: a human must investigate and resume with a note. Every trip, pause, and resume lands in the tamper-evident audit chain and the public GET /v1/proof/status endpoint โ the bridge cannot be paused or unpaused in secret. The ML guard fails open: a risk-engine outage never blocks the bridge.
5. Signed, freshness-bound warrant canary
GET /v1/proof/canary returns a signed statement embedding the current time and the latest checkpoint root โ it cannot be replayed against a rewound log. A canary that stops updating is itself a signal.
Verify without trusting anything
Three independent verifiers ship in this repo, all validated against RFC 8032 test vectors and against each other:
| Verifier | Trust required |
|---|
website /verify page | verification runs client-side in your browser |
verifier/umbra-verify.html | none โ save the file, open from file://, zero network requests, pure-BigInt Ed25519 with an on-load self-test |
tools/verify_receipt.py | none โ pure Python stdlib, no dependencies; receipts/checkpoint/inclusion subcommands |
Pin the bridge's public key (GET /v1/proof/key) out-of-band once; from then on, every receipt either verifies or it doesn't. Telegram users get the same via /receipt <order_id> and /trust.
The full wire-format specification โ exact canonical forms, algorithms, threat model, and test vectors for building your own verifier โ lives in docs/PROOF_LAYER.md.
Supported Chains
| Chain | Ticker | Type |
|---|
| Monero | XMR | Privacy L1 |
| Bitcoin | BTC | L1 |
| Ethereum | ETH | L1 |
| TON | TON | L1 |
| Solana | SOL | L1 |
| Arbitrum | ARB | L2 (EVM) |
| Base | BASE | L2 (EVM) |
| USDT / USDC | Stablecoins | Multi-chain |
Architecture
+------------------+
| Nginx Proxy |
| :80 / :443 |
+--------+---------+
|
+------------------+------------------+
| | |
/app | / | /api |
v v v
+--------+------+ +------+-------+ +-------+-------+
| Telegram Mini | | Next.js | | Rust Backend |
| App (Vite) | | Website | | (axum) |
| :3000 | | :3001 | | :8000 |
+----------------+ +--------------+ +---+---+-------+
| |
+------------------+ +--------+
| |
+-------v------+ +--------v-------+
| PostgreSQL | | Redis |
| :5432 | | :6379 |
+--------------+ +----------------+
|
+-------------------------------------------+
| |
+--------v-------+ +--------v--------+
| Telegram Bot | | Prometheus + |
| (aiogram) | | Grafana |
+----------------+ +-----------------+
Single Rust binary replaces what would typically be 3+ Python processes. The backend handles HTTP API, WebSocket streaming, background task scheduling, and blockchain RPC โ all in one process using tokio.
Three Interfaces, One Backend
1. Telegram Mini App
Mobile-optimized bridge UI that runs inside Telegram. Tap, swap, done.
2. Telegram Bot
Full conversational bridge โ /bridge, /rate, /history, /status. Works without ever leaving the chat.
3. Enterprise Website
Desktop dashboard with portfolio tracking, analytics charts, order history, public transaction explorer, admin panel โ plus /verify (client-side receipt verification) and /transparency (live sentinel status, checkpoints, canary).
All three share the same Rust API and real-time WebSocket feed.
Tech Stack
| Layer | Technology |
|---|
| Backend | Rust, axum 0.7, sqlx, tokio, tower |
| Database | PostgreSQL 17, Redis 7 |
| MPC | FROST threshold signatures (frost-secp256k1) |
| Blockchain | monero-wallet-rpc, toncenter, EVM JSON-RPC, Solana RPC, Bitcoin Core |
| Website | Next.js 15, React 19, Tailwind CSS 4, Zustand, Recharts, TON Connect |
| Mini App | Vite 6, vanilla JS, Telegram WebApp SDK |
| Bot | Python, aiogram 3, httpx |
| Monitoring | Prometheus, Grafana |
| Proxy | Nginx with rate limiting |
| Rates | CoinGecko -> Binance -> CoinCap (triple fallback) |
Quick Start
git clone https://github.com/beepboop2025/umbra.git
cd umbra
cp backend/.env.example .env
docker compose up --build
Project Structure
umbra/
โโโ backend/ # Rust API (axum + sqlx + tokio)
โ โโโ src/
โ โ โโโ routes/ # HTTP + WebSocket endpoints (incl. /v1/proof/*)
โ โ โโโ services/ # Rates, orders, attestations, transparency, sentinel
โ โ โโโ blockchain/ # Monero, Bitcoin, EVM, TON, Solana RPC clients
โ โ โโโ mpc/ # FROST threshold signatures, coordinator, signers
โ โ โโโ middleware/ # Security headers, rate limiting, Telegram auth
โ โ โโโ tasks/ # Deposit monitor, confirmations, expiry, sentinel, sealing
โ โ โโโ models/ # SQLx models (orders, rates, audit, MPC)
โ โ โโโ utils/ # Crypto helpers, address validation, RFC 6962 Merkle
โ โโโ migrations/ # PostgreSQL schema
โโโ bot/ # Telegram bot (aiogram 3)
โ โโโ bot/
โ โโโ handlers/ # /start, /bridge, /rate, /history, /admin
โ โโโ keyboards/ # Inline keyboards for bridge flow
โ โโโ services/ # Backend API client
โโโ website/ # Enterprise dashboard (Next.js 15)
โ โโโ src/
โ โโโ app/ # Pages: bridge, dashboard, explorer, admin
โ โโโ components/ # UI, bridge, charts, wallet, layout
โ โโโ hooks/ # useRate, useOrders, useWebSocket, useWallet
โ โโโ stores/ # Zustand state management
โ โโโ lib/ # API client, validators, utilities
โโโ src/ # Telegram Mini App (Vite)
โโโ risk-engine/ # Python risk service (FastAPI)
โ โโโ services/ # Isolation Forest, MAD z-score, drain scoring
โโโ verifier/ # Single-file offline verifier (umbra-verify.html)
โโโ tools/ # verify_receipt.py โ pure-stdlib CLI verifier
โโโ docker-compose.yml # Full stack orchestration (10 services)
โโโ nginx.conf # Reverse proxy + rate limiting
โโโ monitoring/ # Prometheus + Grafana config
How a Bridge Swap Works
1. User selects pair XMR -> TON, enters amount
2. Rate lock Cross-rate from CoinGecko (30s cache)
3. Sentinel gate Intake refused instantly if the circuit breaker is tripped
4. Order created Deposit address generated, 30min expiry, signed receipt #0
5. Deposit detected Monero wallet-rpc monitors subaddress
6. Confirmations 10 confirms for XMR, 1 for TON
7. MPC signing 2-of-3 FROST threshold signature
8. Withdrawal sent TON transfer broadcast
9. Complete Signed receipt binds the withdrawal tx hash;
user notified via WebSocket + Telegram
Every step from 4 onward emits a hash-chained, dual-signed receipt the user can verify offline โ the order's history is provable end to end.
Security
- FROST 2-of-3 MPC โ No single party can sign transactions
- Proof Layer โ Signed receipts (Ed25519 + ML-DSA-65), RFC 6962 transparency log, sentinel circuit breaker, signed canary (see above)
- Hash-chain audit log โ Every state change is tamper-evident (SHA-256 chain), sealed into signed Merkle checkpoints
- Telegram WebApp auth โ HMAC-SHA-256 verification of
initData
- Rate limiting โ Redis sliding window (60/min API, 10/min orders, 5 WS/IP)
- Security headers โ CSP, HSTS, X-Frame-Options, X-Content-Type-Options
- Argon2id โ Password hashing for admin accounts
- JWT โ Admin authentication with configurable expiry
- Anti-replay โ Nonce-based protection on order creation and MPC signing
- Address validation โ Per-chain regex validation (XMR base58, BTC bech32, ETH checksum, TON friendly/raw, SOL base58)
Key custody for the Proof Layer
The attestation identity is derived deterministically from SECRET_KEY by default (fine for development). In production set independent seeds โ ATTESTATION_SECRET_KEY (Ed25519) and ATTESTATION_PQ_SEED (ML-DSA-65) โ so receipt-signing custody can be separated from JWT custody, and publish the public keys from GET /v1/proof/key somewhere you don't control (a tweet, a git tag, another bridge's transparency page) so users can pin them.
API Reference
Rates
GET /v1/rate?direction=XMR_TO_TON Current rate + 24h change + sparkline
GET /v1/rate/history?direction=&period=1h Rate history (1h/4h/24h/7d/30d)
Orders
POST /v1/order Create bridge order
GET /v1/order/:id Order details
GET /v1/orders?telegram_user_id=&limit=50 Order history
POST /v1/order/:id/cancel Cancel pending order
WebSocket
WS /v1/ws/order/:id Real-time order status updates
WS /v1/ws/rates Live rate feed
Proof Layer (public โ no auth, by design)
GET /v1/proof/key Bridge public keys (Ed25519 + ML-DSA-65) โ pin these
GET /v1/proof/receipt/:order_id Signed receipts for an order (full lifecycle)
GET /v1/proof/checkpoint/latest Latest signed Merkle tree head
GET /v1/proof/checkpoints?limit=20 Checkpoint history
GET /v1/proof/inclusion/:audit_id RFC 6962 inclusion proof for an audit entry
GET /v1/proof/consistency?old_size=&new_size= Append-only proof between two checkpoints
GET /v1/proof/audit/verify Server-side full hash-chain walk
GET /v1/proof/canary Signed, freshness-bound warrant canary
GET /v1/proof/status Sentinel state: accepting orders? why not?
Risk Engine (internal, X-API-Key)
POST /v1/risk/anomaly Statistical drain scores (MAD z-score, burst, round amounts)
POST /v1/risk/anomaly/ml Isolation Forest anomaly scores over order-flow features
Admin
POST /v1/admin/login JWT authentication
GET /v1/admin/stats System statistics
POST /v1/admin/order/:id/refund Manual refund
GET /v1/admin/sentinel Sentinel state + last 50 events
POST /v1/admin/sentinel/pause Manual pause (reason required)
POST /v1/admin/sentinel/resume Resume (investigation note required)
System
GET /health Liveness probe
GET /ready Readiness probe (DB + Redis)
GET /metrics Prometheus metrics
Monitoring
Prometheus scrapes the /metrics endpoint for:
- API request latency (p50/p95/p99)
- Order throughput and failure rate
- Rate source health and fetch duration
- WebSocket connection count
- Background task execution metrics
Grafana dashboards available at :3002 (default password: admin).
Development
cd backend
cargo run
cd website
npm install && npm run dev
npm run dev
cd backend
cargo test
Environment Variables
See backend/.env.example for the full list. Key ones:
| Variable | Description |
|---|
SECRET_KEY | JWT signing key (64+ chars) |
TELEGRAM_BOT_TOKEN | From @BotFather |
MONERO_RPC_URL | monero-wallet-rpc endpoint |
TON_API_URL | toncenter API |
ETH_RPC_URL | Ethereum JSON-RPC |
BRIDGE_FEE_PERCENT | Fee per swap (default: 0.3%) |
MPC_THRESHOLD | Signatures required (default: 2) |
ATTESTATION_SECRET_KEY | Ed25519 receipt-signing seed, 64 hex chars (derived from SECRET_KEY if unset) |
ATTESTATION_PQ_SEED | ML-DSA-65 seed, 64 hex chars (derived if unset) |
PQ_SIGNATURES_ENABLED | Post-quantum hybrid signatures (default: true) |
TRANSPARENCY_SEAL_INTERVAL_SECS | Checkpoint sealing cadence (default: 300) |
CANARY_STATEMENT | Warrant-canary text served at /v1/proof/canary |
SENTINEL_ENABLED | Circuit breaker (default: true) |
SENTINEL_OUTFLOW_CAPS | Per-chain hourly caps, e.g. XMR:1000,BTC:20 |
RISK_ENGINE_URL | Enables the Isolation Forest sentinel guard (optional) |
License
Private. All rights reserved.