DeFi protocol APY/APR comparison system

We design and develop full-cycle blockchain solutions: from smart contract architecture to launching DeFi protocols, NFT marketplaces and crypto exchanges. Security audits, tokenomics, integration with existing infrastructure.
Showing 1 of 1 servicesAll 1306 services
DeFi protocol APY/APR comparison system
Medium
~3-5 business days
FAQ
Blockchain Development Services
Blockchain Development Stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1214
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    852
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_logo-advance_0.png
    B2B Advance company logo design
    561
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    823

Development of APY/APR protocol comparison system

User compares yields manually: Aave shows 4.2% APY on USDC, Compound — 5.1%, Morpho — 5.8%. But these numbers can't be compared directly: Aave accounts for compound interest (APY), Compound historically showed APR (without reinvestment accounting), Morpho aggregates with additional MORPHO rewards. Without data normalization any comparison is misleading.

Main problem: metric normalization

APR vs APY and different compounding periods

APR (Annual Percentage Rate) — simple rate without reinvestment. APY (Annual Percentage Yield) — with compound effect. Difference on frequent compounding is significant:

APY = (1 + APR/n)^n - 1

With APR = 10% and compounding every block (≈ 2190 times per year on Ethereum) APY ≈ 10.52%. With daily compounding — 10.516%. Difference small, but when comparing protocols with different compounding periods you need uniform base.

For correct comparison system normalizes everything to Daily APR: divide annualized rate by 365. Show user APY (more understandable metric), calculate internally in Daily APR.

Reward tokens: how to include in calculation

Many protocols on top of base rate pay native tokens (COMP, AAVE, MORPHO). Must include in total APY, but accounting for:

  • Current reward token price (volatile — price can drop by claim time)
  • Vesting/lock: AAVE Safety Module rewards vest 10 days
  • Emission decay: decreasing emissions over time (many protocols reduce emissions every N days)

Approach: show base APY (no rewards) and total APY (with rewards) separately. User decides whether to account for unstable rewards.

Getting data on-chain

Each protocol provides data differently:

Aave V3: getReserveData(asset) returns currentLiquidityRate in ray (1e27). Conversion: APR = rate / 1e27 * SECONDS_PER_YEAR. Rewards through getRewardsData() in RewardsController.

Compound V3 (Comet): getSupplyRate(utilization) returns rate per second. APR = ratePerSecond * SECONDS_PER_YEAR.

Morpho: aggregates Aave and Compound markets with optimization. Base rate = underlying market rate, but with peer-to-peer matching can be higher. supplyAPR() from Morpho Lens contract.

Curve: yield from multiple sources — trading fees (automatically reinvested), CRV emissions (via gauge), boost. CRV APY depends on user's veCRV balance. For comparison systems take "base" APY without boost.

Pendle: YT (Yield Token) implied APY calculated through PT price — not direct contract value, but calculation through market price.

System architecture

Data fetching layer

On-chain calls expensive (in RPC request terms). With 10 protocols × 20 assets × 5 metrics = 1000 calls on each update. Solution: Multicall3 batching — all calls in one transaction.

const calls = protocols.flatMap(protocol => 
  assets.map(asset => ({
    target: protocol.address,
    callData: protocol.interface.encodeFunctionData("getReserveData", [asset])
  }))
);
const results = await multicall.aggregate(calls);

For historical data — The Graph subgraphs. Most large protocols (Aave, Compound, Uniswap) have official subgraphs with historical hourly rate data.

Caching and updates

APY in DeFi changes every block but significantly — every few minutes. Aggressive caching:

  • L1 cache (Redis): current rates, TTL 60 seconds
  • L2 cache (PostgreSQL): hourly snapshots for historical charts
  • Real-time updates: WebSocket for change subscriptions (if available)

Background job every 60 seconds fetches on-chain data, updates Redis, once per hour writes snapshot to PostgreSQL.

Historical dynamics

Current APY — momentary snapshot. For decision-making need historical dynamics: how did APY change last 7/30/90 days, how did it react to market events.

From hourly snapshots build:

  • Moving average (7d, 30d) for understanding average yield
  • Volatility metric (std deviation APY) — how stable is yield
  • Min/max for period — floor and ceiling of expected yield

Volatile APY (changes in 5x range monthly) — different risk profile than stable APY (±0.5%). Important info for user.

Ranking and comparison

Just sorting by APY — insufficient. Ranking should account for:

  • Risk-adjusted yield: different protocols have different risk profiles (audit history, TVL, age)
  • Liquidity: available deposit capacity — important for large sums
  • Stable vs volatile APY: rewards in native tokens less reliable
  • Network: gas costs on Ethereum vs L2 — matter for small deposits

Simple solution: show filters (stable APY only, audited protocols only, minimum TVL) without creating single "score" — user weighs priorities themselves.

Technical stack

Backend: Node.js + TypeScript. Viem for on-chain calls (lighter ethers.js, tree-shakeable). PostgreSQL for historical data. Redis for caching. Bullmq for background job queue.

Frontend: Next.js, TanStack Query for data fetching with caching and refetch intervals. Recharts or Tremor for historical yield charts.

Subgraphs: The Graph for historical Aave, Compound, Uniswap data. For protocols without official subgraph — custom event indexer through Ponder or custom indexer.

Timeline estimates

MVP with 3-5 protocols, current rates without history — 3-5 days. Full system with historical data, normalization, filters and visualization — 2-3 weeks. Cost calculated individually.