Architecture Overview
System Components
lateo/
├── contracts/ Soroban smart contracts (Rust)
│ ├── pool/ Privacy pool — transact(), disburse()
│ ├── circom-groth16-verifier/ On-chain Groth16 verification
│ ├── asp-membership/ Binary Merkle tree for inclusion proofs
│ └── asp-non-membership/ Sparse Merkle tree for exclusion proofs
├── circuits/ Circom circuits (Groth16, BN254)
│ └── src/policyTransaction.circom
├── proxy/ Privacy proxy server (TypeScript)
│ ├── zk-pool-service.ts ZK proof generation + on-chain submission
│ ├── batch-operator.ts Temporal batching for x402 payments
│ ├── witness-builder.ts Circuit witness construction
│ └── storage.ts SQLite + AES-256-GCM encryption
├── dashboard/ React dashboard
├── landing/ Landing page
├── zksearch/ x402-protected search service
├── mcp-server/ MCP server for AI agent integration
└── target/wasm-prover-nodejs/ ark-groth16 compiled to WASMTransaction Flows
Deposit (Atomic ZK)
1. Frontend → POST /api/deposit/prepare { amount, publicKey }
2. Proxy: generates Groth16 proof + builds unsigned transact() XDR
3. Frontend → Freighter signTransaction(XDR) → user approves
4. Frontend → POST /api/deposit/submit { signedTransactionXDR }
5. Proxy → submits signed tx to Stellar
6. ON-CHAIN (atomic):
├── pool.transact() verifies Groth16 proof
├── pool.transact() transfers USDC from sender to pool
├── pool.transact() inserts commitments into Merkle tree
└── If ANY step fails → entire tx reverts → no USDC moves
7. Proxy → credits balance ONLY after on-chain confirmationx402 Payment (Batched)
1. Agent → POST /api/pay { serviceUrl }
2. Proxy: verifies agent balance
3. Proxy: enqueues in BatchOperator
4. BatchOperator: accumulates payments for batch window (15s)
5. BatchOperator: executes x402 payments from pool wallet
6. On-chain: Pool → Service (individual agent not identifiable)Withdrawal (Atomic ZK)
1. User → POST /api/withdraw { amount, destination }
2. Proxy: selects unspent notes for the withdrawal amount
3. Proxy: generates Groth16 proof with nullifiers
4. Proxy: operator signs transact() with negative ext_amount
5. ON-CHAIN (atomic):
├── pool.transact() verifies Groth16 proof
├── pool.transact() verifies nullifiers not already spent
├── pool.transact() marks nullifiers as spent
├── pool.transact() transfers USDC from pool to recipient
├── pool.transact() inserts change commitments
└── If ANY step fails → entire tx reverts → no USDC moves
6. Proxy → debits balance ONLY after on-chain confirmationSmart Contracts
| Contract | Purpose | Key Functions |
|---|---|---|
| Pool | Privacy pool with atomic ZK transactions | transact(proof, extData, sender), disburse(), get_root() |
| Groth16 Verifier | On-chain BN254 pairing check | verify(proof, publicInputs) |
| ASP Membership | Binary Merkle tree of verified participants | insert_leaf(), get_root() |
| ASP Non-Membership | Sparse Merkle tree for exclusion proofs | insert(), delete(), verify_non_membership() |
Trust Model
| Component | What it knows | Trust assumption |
|---|---|---|
| On-chain contracts | Commitments, nullifiers, Merkle roots | Trustless — verified by Stellar validators |
| Proxy server | Agent identities, notes, payment requests | Trusted operator (mitigated by encrypted storage) |
| Freighter wallet | User’s private key | User’s device |
| x402 Facilitator | Transaction authorization | Third-party (Coinbase/OpenZeppelin) |
| Batch operator | Which agent requested which payment | Same trust as proxy |
Last updated on