Carry shows your true LP return on Uniswap - net of LVR, not headline APR.
Carry is a concentrated-liquidity strategist for Uniswap on Base that shows your real return — net of LVR.
Every LP dashboard quotes a headline fee APR: fees ÷ capital. It looks amazing (40%, 80%, 200%) and it's misleading, because it ignores the single biggest cost of providing liquidity — LVR (loss-versus-rebalancing). An LP is structurally short gamma: on every price move, arbitrageurs rebalance your position against you at stale prices, so you're always selling the winner and buying the loser. That's not hand-wavy "impermanent loss" — it's a closed-form cost that scales with volatility (≈ σ²/8 per year for a full-range pool; Milionis–Moallemi–Roughgarden, 2022). Most LPs never see it, so they chase fat APRs into pools that are quietly bleeding.
Carry collapses this into one honest number: Net APR = Gross fee carry − LVR drag. Green means the fees pay you to take the volatility — LP it. Red means you're paying the pool to hold your bags — don't.
How it works. For any pool, Carry pulls realized volatility and volume from daily on-chain price history (GeckoTerminal) and reads live pool state — tick, liquidity — directly from Uniswap on Base via viem. It then models four observable quantities: σ (realized volatility), time-in-range (a lognormal price model for how long your band stays active), the v3 concentration factor (how much a tight range deepens your liquidity, 6–200×), and your fee share. The key insight it surfaces: concentration is a double-edged sword — tightening your range multiplies your fees and your LVR by the exact same factor, so there's a real optimum to find.
What you can do. Drag a price range in the live explorer and watch net-of-LVR APR update instantly; take a risk-profiled recommendation (ranges sized in volatility sigmas — conservative 2.5σ, balanced 1.5σ, aggressive 0.75σ); compare pools on a leaderboard ranked by net carry rather than headline yield; and review and manage live positions with a connected wallet.
Stack: Next.js 16, React 19, TanStack Query, shadcn/ui, viem/wagmi, Dynamic (wallet), GeckoTerminal + on-chain Uniswap data, all on Base.
The core is a pure, tested TypeScript model — everything else feeds it.
The LVR engine (src/lib/lvr) is dependency-free and unit-tested: realized volatility from log-returns, the v3 concentration factor 1/(1−⁴√(p_lo/p_hi)), a driftless-lognormal time-in-range, gross fee APR, and the σ²/8 · C · P LVR term — netting to a single Net APR. Because it's pure math with zero I/O, the range explorer recomputes net-of-LVR live on every drag of the slider with no network round-trip — the snappy "aha" of the demo is just a function call.
Two-tier data layer. Pool economics (price, realized σ, annualized volume) come from GeckoTerminal's daily OHLCV — cached server-side with Next's revalidate: 60 to stay under the free-tier rate limit. Live pool microstructure (tick, liquidity, token decimals) is read straight from Uniswap v3 on Base via viem multicall, batching slot0/liquidity/token0/token1 into one RPC call. Open positions are discovered by reading the NonfungiblePositionManager (balanceOf → tokenOfOwnerByIndex → positions), again batched through multicall and filtered to live liquidity.
Uniswap partner APIs do the heavy lifting on transactions: the Trade API (/quote) gives an orientation-agnostic spot price, and the Liquidity API (/lp/create) returns unsigned mint transactions for a chosen tick range — so we never hand-roll calldata. That call is wrapped in a retry that backs off on 5xx (Uniswap's gateway throws transient 504s) but fails fast on 4xx.
Frontend: Next.js 16 / React 19, TanStack Query for fetching/caching, shadcn/ui + Recharts for the price-history range chart, Dynamic for wallet connection — all on Base.
Hacky bits worth calling out:
Stack: Next.js 16, React 19, TypeScript, TanStack Query, shadcn/ui, Recharts, viem/wagmi, Dynamic, Uniswap Trade + Liquidity APIs, GeckoTerminal, Base.

