Private ERC-20 payments on Arbitrum. Deposit once, pay teams without exposing who paid whom or how much, withdraw when ready. ZK proofs in-browser and onchain verifier, live on Arbitrum Sepolia.
Shielded is a privacy-first payments layer for Arbitrum. It lets teams, DAO treasurers, and operators move money without broadcasting every payment on a public ledger.
The product follows a simple mental model: move funds in → pay privately → cash out when you want. Users connect a normal wallet (MetaMask or similar), deposit ERC-20 tokens into a shielded balance, send private payments to other Shielded users, and withdraw back to a public address when they choose. Deposit and withdrawal are normal on-chain actions and are clearly labeled in the app. While funds sit in the private layer, who paid whom and how much is not exposed to everyday chain observers.
Shielded is built on a note-based UTXO privacy pool, inspired by STRK20-style workflows and adapted for EVM with Noir and UltraHonk (Barretenberg). Read technical doc : https://drive.google.com/file/d/1oDqvVAs_sgybDCvJoz7PyYF8D5lmWcxs/view?usp=drive_link
On-chain layer
ShieldedERC20Pool — multi-token pool that holds shielded notes for allowlisted ERC-20s (MOCK, USDC, USDT, DAI, LINK on testnets)
IncrementalMerkleTree — Poseidon2-based commitment tree with a rolling root window for concurrency
UltraVerifier — Solidity verifier generated from the Noir circuit via Barretenberg
Nullifier set — prevents double-spends without revealing which note was spent
Zero-knowledge layer
Noir circuit (packages/circuits) enforces Merkle membership, nullifier correctness, output commitments, and conservation of value (inputs = outputs + fee)
Supports private transfer and unshield in one circuit via a mode flag
Proofs are generated in the browser with bb.js — keys and witness data never leave the client for standard flows
Privacy and discovery
Output notes are encrypted (ECDH + HKDF + AES-256-GCM) and emitted as RoutedCommitment events indexed by channel/subchannel
Recipients scan logs and decrypt only notes addressed to them using a viewing key
Senders submit via a relayer so the on-chain transaction origin is the relayer, not the user’s EOA
Client surfaces
Web app (Next.js) — Dashboard, deposit/shield, private transfer, unshield, inbox, faucet, settings; multi-chain pool switching
Browser wallet extension (Manifest V3) — EOA vault, public + private balances, in-browser proving, note sync against live pool contracts
TypeScript SDK — proof bundle construction, note discovery helpers, relayer client
Relayer service — HTTP API for proof submission, multi-chain RPC routing, round-robin signers; deployed live on Render
Finance and ops leads, DAO treasurers, founders paying contributors, and anyone who needs operational discretion e.g. payroll, vendor payments, treasury flows etc. without “anonymity theater.” Shielded is infrastructure, open source, and built for real teams.
Private (in-pool): sender identity (via relayer), receiver identity (encrypted notes), amounts (encrypted + in witness).
Public (by design at boundaries): deposit and unshield are visible entry/exit points on a public chain. The app is explicit about this so users are never surprised.
Fully deployed and usable on:
Arbitrum Sepolia (421614)
Ethereum Sepolia (chain id 11155111)
Base Sepolia (84532)
Each chain has its own pool, verifier, Merkle tree, and mock stablecoin set. Users can try the full flow end to end via the in-app faucet.
User wallet → Deposit (public) → Shielded balance (private notes in Merkle tree)
↓
Private transfer (ZK proof → relayer → pool)
↓
Recipient decrypts note via viewing key
↓
Unshield (public) → EOA
Public blockchains are great for auditability, but many real workflows need selective privacy: you should not have to publish every payroll line item to the world. Shielded adds a practical private balance layer on top of existing ERC-20s, with browser-native proving, relayer-mediated submission, and a product UX that non-cryptographers can actually use.
During the hackathon we went from protocol scaffolding to a multi-chain, end-to-end private payments product you can demo on live testnets.
We designed and shipped the full shielded transfer stack:
Noir circuit with Poseidon2 hashing, dual-input spends, fee notes, and unshield mode in one artifact
Generated UltraHonk Solidity verifier from the circuit verification key
ShieldedERC20Pool with token allowlisting, nullifier replay protection, root checks, and non-reentrancy
IncrementalMerkleTree with Poseidon2 parent hashing and a rolling known-root window
Poseidon2 EVM helpers aligned with circuit hashing
Foundry test suite for pool behavior
We deployed the full contract set to Ethereum Sepolia, Base Sepolia, and Arbitrum Sepolia, including batch mock tokens (USDC, USDT, DAI, LINK) and checked deployment snapshots into the repo for reproducibility.
We built and deployed a production relayer (services/relayer) to Render with:
POST /relay/shielded-transfer for on-chain proof submission
GET /relay/status/:requestId for transaction tracking
Multi-chain RPC routing (11155111, 84532, 421614) with round-robin relayer signers
Health checks and stub fallback for local dev
This lets private transfers land on-chain without exposing the user’s EOA as the transaction sender.
We shipped a polished Next.js web app covering the full user journey:
Landing and about pages explaining the privacy model in plain language
Dashboard with hide/reveal balance, per-token breakdown, recent activity
Shield (deposit) — move public ERC-20 into the private pool
Transfer — private send to a Shielded address with in-browser proof generation
Unshield — withdraw from private balance to a public address
Inbox — incoming private payments discovered via encrypted note scanning
Faucet — test tokens for demo flows
Settings — network selection, key management, privacy controls
We invested heavily in multi-chain UX: pool network switching, wallet chain prompts, and resilient RPC log scanning (chunked eth_getLogs for Alchemy free tier and L2 public RPC limits, especially on Arbitrum Sepolia).
We built a Manifest V3 Chrome extension that mirrors core wallet functionality:
Encrypted local vault (import + PBKDF2/AES-GCM storage)
Deterministic shield key derivation (spending key, viewing key, owner pk) from wallet identity
Public balance + public send flows
Shielded note discovery via RoutedCommitment log scanning and decryption
In-browser Noir + bb.js proving for private transfer and unshield
Clear separation between public and private balances and send modes
Multi-chain RPC support (Sepolia, Base Sepolia, Arbitrum Sepolia)
We added a TypeScript SDK (@zkproject/sdk) for proof bundles, discovery, and relayer integration.
We wrote automated E2E scripts for:
Local Anvil (monolith and multi-token pool)
Sepolia testnet (deploy, shield, transfer, decrypt)
Pool deploy scripts for Base Sepolia and Arbitrum Sepolia
RPC smoke probes for L2 log indexing
The monorepo is organized as workspaces: packages/circuits, packages/contracts, packages/sdk, apps/web, apps/wallet-extension, services/relayer.
A user can:
Connect MetaMask on Arbitrum Sepolia
Claim test tokens from the faucet
Deposit into a shielded balance
Send a private payment to another Shielded address (amount and parties hidden on-chain)
See the payment appear in the recipient’s inbox after note decryption
Withdraw back to a public wallet
All of this runs against live deployed contracts with a live relayer, with proofs generated client-side in the browser.
Deposit and unshield remain public boundary actions (by EVM design)
First-time note scans on L2 can be slow on public RPCs (mitigated with chunked reads and premium RPC fallbacks)
Production hardening (formal audit, richer key recovery, relayer auth) is planned post-hackathon
None