Architecture
Shildo moves value in three coordinated phases. Each phase runs without exposing payment metadata on public rails. This page describes components, trust boundaries, and the end to end data path.
Component diagram
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ Wallet │────▶│ Privacy vault │────▶│ Prover │
│ (client) │ │ (off chain) │ │ network │
└─────────────┘ └──────────────┘ └──────┬──────┘
│ Groth16 proof
▼
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ Destination │◀────│ Relayers │◀────│ Base verifier│
│ chains │ │ │ │ + state root│
└─────────────┘ └──────────────┘ └─────────────┘
Phase 01: Seal intent off chain
Sender builds a payment intent containing:
asset(eth, usdc, shld, btc in demo)amountas a positive decimalrecipientas a checksummed EVM address or Solana pubkeymemooptional UTF-8 stringshieldedboolean flag
The wallet derives an encryption key from the user seed and encrypts the intent. A commitment hash is published to the privacy vault. Validators index commitments but cannot read plaintext without the key or a view key.
Privacy vault responsibilities
- Store commitment with timestamp and expiry window
- Reject duplicate or replayed commitments
- Expose merkle inclusion proofs for prover input
- Never write plaintext to Base or outer chain mempools
Phase 02: Prove on Base
A prover node fetches the commitment, generates a Groth16 proof, and submits it to the Base verifier contract. Public inputs include the new state root, asset class identifier, and delivery route id. Private inputs remain in the proof witness.
Median finality target is ~1.2s after proof inclusion. The verifier contract atomically:
- Validates the proof against the verification key
- Checks nullifier set for double spend prevention
- Updates the settlement root in storage
- Emits
DeliveryAuthorized(root, routeId, nonce)
Phase 03: Release shielded
Relayers subscribe to delivery events on Base. Each relayer holds liquidity on destination chains. After sufficient confirmations, the relayer releases funds to the recipient endpoint. For shielded transfers, public explorers on outer chains show relayer activity but not sender linked metadata.
Seal intent off chain
Sender builds a payment intent: recipient, asset, amount, optional memo. The intent is encrypted and committed in the privacy vault before any public mempool interaction.
Prove on Base
A zero knowledge proof is generated for the committed intent. Base verifies the proof and updates the unified settlement state. Median finality target is ~1.2s.
Release shielded
Settlement triggers delivery on the destination chain. Receiver gets funds with no linkable trail between sender, amount, and memo on public explorers.
Data flow (detailed)
Sender wallet
→ build intent { asset, amount, recipient, memo, shielded }
→ encrypt(intent, userKey)
→ commitment = hash(ciphertext)
→ privacy vault.store(commitment)
→ prover.generateProof(commitment, witness)
→ Base.verify(proof, publicInputs)
→ emit DeliveryAuthorized
→ relayer.release(destinationChain, recipient)
→ recipient balance credited
State model
Base holds the canonical settlement root. The root is a merkle accumulator over verified intents. Outer chains do not maintain independent privacy state. Instead they consume proofs that the root on Base authorizes a specific delivery.
On chain state (Base)
settlementRootbytes32nullifiersmapping to prevent replayverificationKeyHashfor circuit upgrades
Off chain state (vault)
- Encrypted intent blobs keyed by commitment
- Expiry queue for unproven commitments
- View key registry (optional, user controlled)
Demo wallet mapping
The demo wallet simulates phases 01 and partial explorer visibility using Supabase. Sends call process_transfer which updates balances and writes a transaction row. The is_shielded flag controls whether amount and memo are masked in the network explorer UI.
Failure modes
| Failure | Behavior |
|---|---|
| Invalid proof | Base verifier reverts, no state change |
| Prover timeout | Intent expires in vault, sender can re seal |
| Relayer offline | Delivery retried by backup relayers |
| Insufficient liquidity | Route queued until pool refilled |