Send money publicly or privately. Your choice, every transaction. Powered by Unlink, WalletConnect.
ICEBERG is a decentralized payment app built on Base Sepolia that combines public and private transactions in a single seamless experience, like Revolut, but on-chain.
Users connect their wallet via WalletConnect AppKit. From there, every payment comes with a choice: send publicly (on-chain, traceable, fast) or send privately using Unlink's zero-knowledge proof pool, where sender, receiver, and amount are completely hidden on-chain.
Key features include QR code payments and a payment link system for public transfers. For private payments, we integrate the full Unlink stack, users deposit funds into the Unlink privacy pool, transfer privately between unlink1... addresses using zero-knowledge proofs, and withdraw back to their public wallet at any time. Sender, receiver, and amount are fully hidden on-chain at every step. Built on WalletConnect, Unlink.
ICEBERG is built with Next.js 14 (App Router) and TypeScript on the frontend, running on Base Sepolia testnet.
For authentication and public payments, we use WalletConnect AppKit (wagmi v2 + viem) — users connect any wallet, sign a nonce, and receive a JWT from our backend. Public transactions are signed directly on-chain via wagmi's useWriteContract (ERC-20 USDC transfers) and useSendTransaction (native ETH), with settlement confirmed through our backend after on-chain receipt. QR code payments are also handled through WalletConnect, allowing users to generate and scan payment links for instant checkout.
For private transactions, we integrate the full Unlink SDK on the backend — each user gets a unique mnemonic stored server-side, completely decoupled from their public wallet. We use unlink.deposit() to move funds into the ZK pool, unlink.transfer() to send privately between unlink1... addresses with full zero-knowledge proof generation handled by Unlink's engine, and unlink.withdraw() to exit back to any EVM address. The frontend never touches the private keys — all Unlink operations go through our API routes.
The most notable architectural decision: the full separation between the public layer (WalletConnect + viem, browser-side signing) and the private layer (Unlink SDK, server-side only) — two completely independent payment rails in one unified UX.

