Privacy-preserving DEX frontend for Uniswap v4 on Unichain Sepolia, powered by ZK-SNARKs.
- Private Swaps: Swap ETH/USDC with complete sender/recipient unlinkability
- Stealth Addresses: One-time addresses for receiving swap outputs
- ZK Proof Generation: Client-side Groth16 proof generation
- Deposit Management: Grimoire wallet for managing deposit notes
- Liquidity Provision: Add/remove liquidity to privacy and vanilla pools
- Position Tracking: Track your liquidity positions with on-chain event scanning
- Real-time Pool Data: Live pool state from Uniswap v4 StateView
- Transaction Success Modals: Animated confirmation modals for all transactions
- Onboarding Modal: Multi-step walkthrough for first-time users (per-wallet)
- Relayer Auto-Retry: Automatic retry (up to 3 attempts) on relayer submission failures
- Smart Claim Flow: Auto-detects swap output token for claiming from stealth addresses
- React 18 + TypeScript
- Vite
- TailwindCSS + GSAP animations
- wagmi v2 + viem for Web3
- WalletConnect Web3Modal
- snarkjs for ZK proof generation
- IndexedDB for secure note storage
# Install dependencies
npm install
# Copy environment file
cp .env.example .env
# Start development server
npm run devVITE_WALLETCONNECT_PROJECT_ID=your_project_idsrc/
├── components/
│ ├── effects/ # Aurora background, noise overlay, smooth scroll
│ ├── layout/ # Header, layout wrapper
│ ├── privacy/ # Ring visualization, stealth balance, privacy meter
│ ├── swap/ # Swap card, token inputs, settings, pool statistics
│ ├── ui/ # Buttons, cards, modals, inputs, onboarding, success/error modals
│ └── web3/ # Connect button, transaction status
├── hooks/
│ ├── use-deposit-notes.ts # IndexedDB note management
│ ├── use-grim-pool.ts # Deposit to privacy pool
│ ├── use-grim-swap.ts # Private swap execution
│ ├── use-liquidity.ts # Add/remove liquidity
│ ├── use-liquidity-positions.ts # Track LP positions from events
│ ├── use-merkle-tree.ts # Poseidon tree sync
│ ├── use-onboarding.ts # Per-wallet onboarding state
│ ├── use-pool-manager.ts # Pool state from events
│ ├── use-quoter.ts # Swap quotes from Quoter contract
│ ├── use-settings.ts # User settings (slippage, deadline)
│ ├── use-state-view.ts # Pool state from StateView
│ ├── use-stealth-addresses.ts # Stealth keypair management (+ swap output token)
│ ├── use-token-balance.ts # ETH/ERC20 balances
│ ├── use-token-price.ts # CoinGecko price feeds
│ └── use-zk-proof.ts # ZK proof generation
├── lib/
│ ├── constants.ts # Contract addresses, chain config
│ ├── contracts.ts # Pool keys, ABIs
│ ├── relayer.ts # Relayer API client
│ ├── tokens.ts # Token definitions with logos
│ ├── utils.ts # Utility functions
│ ├── wagmi.ts # Web3 config
│ ├── storage/ # IndexedDB wrappers
│ └── zk/ # Proof generation, Merkle tree, Poseidon
├── pages/
│ ├── home.tsx # Landing page
│ ├── pools.tsx # Liquidity pools management
│ ├── swap.tsx # Swap interface with pool stats
│ └── wallet.tsx # Grimoire (deposit notes + stealth addresses)
└── providers.tsx # Web3 + React Query providers
- First-time users see an onboarding walkthrough explaining the privacy flow
- Deposit ETH/USDC to GrimPool (creates encrypted note)
- Select swap amount (uses full note amount)
- Generate ZK proof client-side
- Submit to relayer (auto-retries up to 3 times on failure)
- Receive output tokens at stealth address
- Redirects to Grimoire after successful swap
- View active pools (vanilla ETH/USDC + GrimSwap privacy pool)
- Add liquidity with ratio validation
- Remove liquidity with percentage controls
- Track your positions (LP tokens, pool share, ETH/USDC amounts)
- View pool statistics (TVL, price, composition)
- Initialize new privacy pools
- Deposit ETH or USDC to privacy pool
- Manage deposit notes (view, copy, delete)
- Export/import notes for backup
- View stealth addresses with real-time balances
- Claim swap output tokens from stealth addresses (auto-detects ETH or USDC)
- Transaction history
| Contract | Address |
|---|---|
| GrimPoolMultiToken | 0xEAB5E7B4e715A22E8c114B7476eeC15770B582bb |
| GrimSwapZK V3 (Hook) | 0x6AFe3f3B81d6a22948800C924b2e9031e76E00C4 |
| Groth16Verifier | 0xF7D14b744935cE34a210D7513471a8E6d6e696a0 |
| PoolManager | 0xC81462Fec8B23319F288047f8A03A57682a35C1A |
| StateView | 0xc199F1072a74D4e905ABa1A84D9a45E2546B6222 |
| Quoter | 0x7643a9a6BE6Dc9c7689ba89A81A9611e17Bf02c4 |
| PoolModifyLiquidityTest | 0x6ff5693b99212da76ad316178a184ab56d299b43 |
| USDC | 0x31d0220469e10c4E71834a79b1f276d740d3768F |
| Parameter | Value |
|---|---|
| Pool ID | 0xbd351665b4f49e58a20e3fdc4861d0fbf0affff0f63fd7b9e113cbaf2734f712 |
| Fee | 500 (0.05%) |
| TickSpacing | 10 |
| Hook | 0x6AFe3f3B81d6a22948800C924b2e9031e76E00C4 |
| Parameter | Value |
|---|---|
| Pool ID | 0x1927686e9757bb312fc499e480536d466c788dcdc86a1b62c82643157f05b603 |
| Fee | 3000 (0.3%) |
| TickSpacing | 60 |
| Hook | 0x0000000000000000000000000000000000000000 |
1. DEPOSIT
User → GrimPoolMultiToken.deposit(commitment) + ETH/USDC
└─► Commitment added to Merkle tree
└─► Deposit event emitted with leafIndex
└─► Note saved locally (secret + nullifier + amount)
2. PRIVATE SWAP
User → Generate ZK proof (proves deposit without revealing which one)
└─► Proof includes: nullifierHash, recipient (stealth), swapAmountOut
└─► Submit proof to relayer
└─► Relayer verifies proof + executes swap via GrimSwapZK hook
└─► Output tokens sent to stealth address
└─► Relayer funds stealth address with ETH for gas
3. CLAIM
User → Redirected to Grimoire after swap
└─► View stealth address balance (auto-detects swap output token)
└─► Click "Claim" → enter destination address
└─► Sign transaction with stealth private key
└─► Only the swapped token (ETH or USDC) is transferred to destination
# Run dev server
npm run dev
# Build for production
npm run build
# Type check
npm run typecheck
# Lint
npm run lint
# Preview production build
npm run previewThe app connects to the GrimSwap relayer at https://services.grimswap.com for submitting private swaps. The relayer:
- Validates ZK proofs before submission
- Submits transactions on-chain (auto-retries up to 3 times on intermittent failures)
- Pays gas on behalf of users
- Funds stealth addresses with ETH for claiming (~0.0005 ETH)
| Endpoint | Description |
|---|---|
GET /info |
Relayer address and fee info |
POST /relay |
Submit private swap with proof |
Animated success modal shown after:
- Successful swaps
- Adding liquidity
- Removing liquidity
- Deposits to privacy pool
- Claiming from stealth addresses
Real-time pool metrics including:
- Current price (from StateView)
- TVL calculated from virtual reserves
- Pool composition (ETH/USDC percentages)
- Liquidity depth
Tracks user positions via:
- On-chain ModifyLiquidity events from PoolManager
- localStorage for pending confirmations
- Calculates ETH/USDC amounts from liquidity + price
| Storage | Purpose |
|---|---|
| IndexedDB | Deposit notes (encrypted secrets), stealth addresses |
| localStorage | LP positions, settings, onboarding state (per-wallet) |
Important: Always backup your deposit notes! They are stored locally and cannot be recovered if lost.
MIT