Aave V4 market data for Ethereum and Avalanche:
- Supply APY, base borrow APY, and available liquidity by asset.
- Chain, Hub, and Market filters.
- Featured 30-day supply APY charts for USDC, WETH, and WBTC.
Designed, built, deployed, and benchmarked in 48 hours.
| Desktop | Mobile |
|---|---|
![]() |
![]() |
- Next.js 16, React 19, and TypeScript for typed Server Components, Cache Components, Suspense, and Route Handlers.
- TanStack Query and Table for live refresh state and sortable market rows.
- Valibot for validating GraphQL responses before caching.
- Tailwind CSS, Radix UI, and Lucide for styling and interface primitives.
Requires Node.js 24. No environment variables are required.
npm ci
npm run dev
npm run check:full # Biome, ESLint, types, Vitest, Knip, and a production build
npm start # serve the production build Aave V4 GraphQL
┌───────────────┴───────────────┐
Current Reserves LAST_MONTH supply APY
fetch → validate → normalize fetch → validate → normalize
│ validate 30d/6h grid
│ │
initial: RSC "use cache" 60s initial: RSC "use cache" 6h
live: /api/markets live: /api/featured-histories
│ │
MarketsDataset FeaturedHistoriesDataset
├── All Markets │
└──────────────┬─────────────────────┘
Featured cards
headline + sparkline
- Current markets and 30-day history each use one field-selected GraphQL
operation and a separate cache profile: 60 seconds is an informational target
for markets; 6 hours follows the
LAST_MONTHbucket spacing. - The static HTML contains the shell and skeletons. Validated snapshots arrive in the initial RSC/Flight response and populate the page during client initialization without waiting for an extra Route Handler request.
- Independent Suspense and error boundaries keep the shell available while either dataset resolves or fails.
- Active tabs refresh through
no-storeRoute Handlers after hydration. - External data is validated before entering either cache.
The market data performance architecture explains the alternatives, cache observations, platform-cost tradeoffs, and proposed A/B measurement.
The performance study records rendering path, populated-row readiness, bundle size, cache transitions, image transfer, and local upstream-request amplification, with its test conditions and limits. It includes five mobile and five desktop Lighthouse runs against the Vercel deployment.
- Source data is per Reserve; displayed rows are grouped by Asset. Filters apply
before aggregation, and Assets group by Aave's
canonicalSymbol. - Featured cards use a fixed, curated set of Reserve-level histories, not aggregated Asset histories. All Markets controls do not change that set.
- Supply APY adds eligible Merkl supply rewards to each Reserve's base rate before Asset-level aggregation. Base Borrow APY excludes reward discounts.
- Available liquidity is pooled at HubAsset grain and counted once per unique
HubAsset.id, not once per Reserve. Collateral-only Assets remain visible. - Unavailable is not zero. Ineligible supply reads
Unavailable, ineligible borrow readsNot borrowable, and real zero values remain$0.00or0.00%. - Available liquidity is pooled protocol liquidity, not a user's borrow capacity or a transaction quote.
- The dashboard queries Ethereum and Avalanche, the complete Chain set accepted by the V4 Reserves API when last verified. Reverify the live boundary before adding Chains.
- The table and Featured region have independent skeletons.
- Markets refresh on mount, roughly every 60 seconds, and when the active tab regains focus.
- Failed markets refreshes keep the last-good rows and report their age. A cold markets failure also removes Featured, while the table shows a retry button and the shell remains available.
- Featured history uses a 6-hour stale window. A failed initial load removes only Featured; a failed refresh keeps the last-good charts.
- Turn repeatable metrics from the performance study into CI budgets. Use Chrome Performance and React Profiler to identify what delays populated rows.
- Test larger Reserve datasets plus delayed, failed, and burst refreshes.
- A/B-test ordinary and remote caching under identical conditions. Capacity-test Route Handlers against a controlled upstream, then derive path-scoped WAF rate limits from measured traffic and confirmed API constraints.
- Add and regression-test static-shell-compatible security headers, including a restrictive Content Security Policy. Allowlist or proxy API-provided asset-icon origins.
- Track GraphQL payload growth. Split operations only when measurements justify it, and consider deltas only if Aave adds revisions, cursors, or subscriptions.
- Add wallet-based asset filtering, an All/Stablecoins grouping control, APY tooltips that separate base yield from incentives, and locally persisted view preferences.
- Add end-to-end coverage for loading, filtering, and retry behavior.

