Fund a fresh wallet through a privacy pool, then trade it ! origin hidden, trade public.
Unlink × Uniswap is a live, testnet demo of gasless, unlinkable on-chain trading. On public chains every trade is permanently tied to the wallet that made it — which lets anyone profile a trader, copy their moves by reputation, and link their activity back to their identity. This project shows how to break that link while keeping the trade fully public and verifiable.
The flow: funds are deposited into Unlink's privacy pool (a shielded account layer), then a trade is executed on Uniswap v3 from a brand-new ERC-4337 smart account that is funded from the pool and whose gas is sponsored by a relayer. The result is that the swap is visible to everyone on-chain, but the trading account has no funding-graph connection to the origin wallet, and the user spends no ETH for gas. In short: the trade is public, the trader's origin is hidden, and there's no persistent address for copy-bots to follow.
It runs on Base Sepolia (chain 84532), where both Unlink and Uniswap are deployed. The web app walks through each step — preflight checks that both protocols are live, deposit, the gasless execute, and a verification step that confirms gas was paid by a relayer (not the origin) and the trading account differs from the origin. Every on-chain action surfaces a "Verify on BaseScan" link so anyone can confirm it independently. An optional MetaMask mode lets you run a normal swap from your own wallet — public and linkable to you — as a deliberate contrast to the unlinked path.
Built with the Unlink SDK, Uniswap v3, viem, and ERC-4337 execution accounts; hosted on Vercel as a static frontend plus serverless API functions (the privacy-layer admin key stays server-side). Testnet only.
Stack & architecture. Everything runs on Base Sepolia (84532), the one testnet where both Unlink and Uniswap are live. The app is a build-free static frontend (vanilla JS/CSS) plus Vercel serverless functions (api/.ts) that wrap a shared TypeScript core (src/actions.ts). A local node:http dev server dispatches /api/ to the exact same handlers, so local behaves identically to prod. viem handles all chain reads/writes and ABI encoding.
The gasless core (Unlink). We use the Unlink SDK in a server/custodial setup: createUnlinkAdmin (holds the API key, registers users, issues auth tokens) + createUnlinkClient (account.fromMnemonic, evm.fromViem). The unlinkable+gasless trade is a single primitive — client.execute({ token, amount, calls }) — which privately withdraws pool funds into a fresh ERC-4337 execution account and runs an atomic [approve, swap] batch with relayer-sponsored gas. Unlink was the key partner tech: it gave us shielded funding and account-abstraction gas sponsorship in one call. Without it we'd have had to stitch together a mixer + a paymaster + an AA bundler ourselves.
Uniswap. Swaps go through Uniswap v3 SwapRouter02.exactInputSingle. Notable hack: we set the swap recipient to Uniswap's MSG_SENDER sentinel (0x…01) so the output routes to the execution account without us needing to know its counterfactual address up front — that let us drop the reserve() + by_index dance entirely.
Vercel. Static public/ + serverless api/, with the Unlink admin key as an encrypted env var that never reaches the browser. vercel.json sets maxDuration: 60 so the execute() poll has room to finish.
Hacky / notable bits:

