Skip to content

Repository files navigation

Aave Markets

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.

Live

Desktop Mobile
Wide viewport: the Featured 30-day supply-APY cards above the markets table, with search, Chain, Hub, and Market filters, and sortable columns Below the sm breakpoint: the Featured strip scrolled to its first card, above the card layout and its Sort control

Tech stack

  • 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.

Setup

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

Caching and rendering

                          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_MONTH bucket 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-store Route Handlers after hydration.
  • External data is validated before entering either cache.

Why this caching model

The market data performance architecture explains the alternatives, cache observations, platform-cost tradeoffs, and proposed A/B measurement.

Measured performance

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.

Assumptions and data semantics

  • 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 reads Not borrowable, and real zero values remain $0.00 or 0.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.

Loading and errors

  • 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.

With more time

  • 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.

About

See where Aave rates and liquidity are moving

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages