Every technology choice in ShieldLend was made deliberately. This document explains the reasoning behind each decision, including what we evaluated and why we chose what we chose.
What it is: An EVM-native Layer 3 built on Base, with a privacy-first design philosophy. Full Solidity compatibility — no new VM, no new language.
Why we chose it:
- EVM-compatible: all Solidity contracts, Foundry tooling, and wagmi frontend work unchanged
- Inherits Base L2's security model and liquidity without requiring a separate bridge setup
- Privacy-native execution environment — aligns with ShieldLend's core purpose
- Developer ecosystem includes privacy DeFi projects (ZENDEX, Obscura, Unwallet) that we can learn from and integrate with
Fallback: Base Sepolia. If Horizen L3 testnet infrastructure is unavailable at deployment time, Base Sepolia is the fallback — it is in the same Base ecosystem and migration to Horizen L3 later requires only an RPC URL change.
What we evaluated and rejected:
- Ethereum L1 mainnet: proof verification is prohibitively expensive (~500K gas per
verifyProof()call) - Polygon zkEVM / Scroll: ZK-rollup chains, but not purpose-built for privacy DeFi; more complex bridge setup
- Aztec: would require rewriting everything in Noir and building a full privacy L2 (see "Why not Aztec" below)
What it is: A modular proof verification chain from Horizen Labs. Accepts ZK proofs (Groth16, PLONK, FFLONK) via the zkVerifyJS SDK and emits on-chain attestations.
Why we chose it:
Cost: Verifying a Groth16 proof on Ethereum L1 requires ~500,000 gas per call. At 20 gwei gas price and $3,000/ETH, that is ~$30 per withdrawal. zkVerify amortizes verification cost across all proof submitters — reducing the per-user cost by ~91%.
Modularity: zkVerify is chain-agnostic. The same proof submission pipeline works whether the contracts are on Horizen L3, Base Sepolia, or any other EVM chain. There is no need to deploy a custom verifier contract per chain.
Native support: zkVerify supports Groth16 and PLONK natively — no custom adapter code needed. The zkVerifyJS SDK handles proof submission in ~3 lines of TypeScript.
What we evaluated and rejected:
- On-chain Groth16 verifier (generated by snarkjs): works but costs ~$30 per proof on L1; acceptable on L2/L3 but couples the verifier to a specific chain
- PLONK with universal setup: eliminates per-circuit trusted setup, but Groth16 has smaller proof sizes (192 bytes vs ~700 bytes) and faster verification; we use Groth16 for the MVP and can switch to PLONK later
What it is: Circom is a domain-specific language for writing ZK-SNARK arithmetic circuits. circomlib is the standard library of reusable circuit templates.
Why we chose it:
- Most mature ZK toolchain for the EVM ecosystem — largest community, most examples, most production deployments
- snarkjs compiles Circom circuits to WebAssembly — enabling browser-side proof generation with no server trust assumption
- circomlib provides battle-tested implementations of Pedersen commitments, Poseidon hashes, and Merkle tree checkers — we do not need to implement these primitives from scratch
- The Tornado Cash codebase (our architectural blueprint) was written in Circom — their circuits are a direct reference
What we evaluated and rejected:
- Noir (Aztec): would require rewriting circuits in a different language and deploying on Aztec's infrastructure
- Halo2 (zcash): Rust-based, no snarkjs/WASM compilation path, no browser proving
- Leo (Aleo): Aleo-specific, not EVM-compatible
What it is: A non-interactive zero-knowledge proof system. Three elliptic curve pairings produce a proof that is just 3 elliptic curve points (192 bytes).
Why we chose it:
- Smallest proof size of any practical SNARK system (192 bytes) — minimizes calldata cost when submitting to zkVerify
- Fastest verification time — 3 pairing operations regardless of circuit size
- snarkjs has first-class Groth16 support and compiles to WASM
- zkVerify supports Groth16 natively
Trade-off: Groth16 requires a per-circuit trusted setup (Powers of Tau + circuit-specific contribution). This is a one-time cost per circuit. PLONK uses a universal setup (one ceremony for all circuits) but produces larger proofs (~700 bytes). For the MVP, Groth16's smaller proofs and faster verification outweigh the setup overhead.
What it is: Solidity is the EVM contract language. Foundry is a Solidity testing and deployment framework written in Rust.
Why Foundry over Hardhat:
- Significantly faster test execution (Rust vs Node.js)
- Built-in fork testing — we can fork the Aave V3 mainnet deployment and run integration tests against real contract state without deploying anything
forge test --match-testfor targeted test runs during developmentforge scriptfor reproducible deployments with full type safety
Why Next.js:
- Server-side rendering for fast initial page load
- API routes for the relayer (watches zkVerify attestation events, calls ShieldedPool.withdraw)
- snarkjs WASM loads cleanly in Next.js with dynamic imports (
next/dynamicwithssr: false)
Why wagmi:
- React hooks for wallet connection (MetaMask, WalletConnect)
- Built-in support for reading contract state and submitting transactions
- Type-safe contract interactions with viem
- Works with any EVM chain including Horizen L3 and Base Sepolia
Why browser-side proof generation:
The alternative — server-side proof generation — would require the user to send their secret and nullifier to a server. If that server is compromised or malicious, the user's funds can be stolen. By generating proofs in the browser using snarkjs WASM, the user's secret never leaves their device. This is the same trust model used by Tornado Cash.
| Decision | Choice | Key Reason |
|---|---|---|
| Chain | Horizen L3 on Base | EVM-native, privacy-aligned, inherits Base security |
| Proof verification | zkVerify | 91% cheaper than L1; modular; native Groth16 support |
| Circuit language | Circom | Most mature EVM ZK toolchain; WASM compilation; circomlib |
| Proof system | Groth16 | Smallest proof size; fastest verification; snarkjs support |
| Contracts | Solidity + Foundry | EVM standard; fastest test runner; fork testing |
| Frontend | Next.js + wagmi | SSR; type-safe contracts; snarkjs WASM integration |
| Proof generation location | Browser (WASM) | User's secret never leaves their device |