Limit orders that earn yield while hiding from MEV. Built on Uniswap v4
GhostVault solves two problems with on-chain limit orders: MEV bots see your target price and front-run you, and your capital sits idle earning nothing while waiting.
We built a Uniswap v4 hook with two order types:
YieldOrder — Set a target price. Your funds route to an ERC-4626 vault and earn yield. When price hits target, the agent swaps and you get output plus yield.
GhostOrder — Set a time delay. Only a hash of your intent goes on-chain. After the delay, the agent reveals and executes. MEV bots never knew what you were trading.
Both use commit-reveal: you commit a hash, keep the plaintext off-chain, and reveal at execution. By the time anyone sees the trade, it's already done.
The solver agent monitors conditions 24/7 and executes when profitable. It earns fees from the yield your order generated — aligned incentives.
Future: users will choose their own yield strategy (conservative Aave lending vs aggressive leveraged vaults). Since we use ERC-4626, any compliant vault plugs in. Higher yield means more solver fees, which means faster execution.
The core is a Uniswap v4 hook (GhostVaultHookV2.sol, ~665 lines) that implements beforeSwap and afterSwap callbacks. We use Cancun's transient storage (tstore/tload) to distinguish hook-initiated swaps from external swaps — this prevents the hook from triggering itself when it calls poolManager.swap().
For yield, we integrate with any ERC-4626 vault. In production we'd use MetaMorpho (Gauntlet USDC Prime). For the demo, we built SimpleYieldVault that simulates 4% APY with time warping.
The commit-reveal uses keccak256(targetPrice, zeroForOne, salt). The salt is 32 random bytes generated client-side — this prevents rainbow table attacks against common price targets.
The agent is TypeScript with viem. It polls Chainlink for price, checks order conditions, calculates if solver fees cover gas, and executes. We integrated x402 protocol for HTTP 402 agent-to-agent payments — the gateway returns a 402 challenge, the caller signs a USDC payment, and the gateway executes.
Batch execution aggregates multiple orders into one swap. On-chain observers see one large trade instead of individual order sizes — additional privacy layer.
Frontend is Next.js 15 with wagmi v2 and RainbowKit. Zustand stores reveal data in localStorage (never touches the chain). We built on Base mainnet fork with Anvil for the demo.
35 tests total: 22 local mock tests, 13 fork tests against real Base mainnet state.

