Розроблення системи сравління APY/APR протоколів
Користувач порівнює дохідність вручну: Aave показує 4.2% APY на USDC, Compound — 5.1%, Morpho — 5.8%. Але ці цифри не можна напрямко порівнювати: Aave враховує compound interest (APY), Compound історично показував APR (без врахування реінвестування), Morpho агрегує з додатковими MORPHO rewards. Без нормалізації даних будь-яке порівняння misleading.
Головна проблема: нормалізація метрик
APR vs APY та різні періоди нарахування
APR (Annual Percentage Rate) — проста ставка без урахування реінвестування. APY (Annual Percentage Yield) — з урахуванням compound ефекту. Різниця при частому нарахуванні істотна:
APY = (1 + APR/n)^n - 1
При APR = 10% і нарахуванні кожен блок (≈ 2190 разів на рік на Ethereum) APY ≈ 10.52%. При щоденному нарахуванні — 10.516%. Різниця невелика, але при порівняні протоколів з різними періодами нарахування потрібна єдина база.
Для коректного порівняння система нормалізує все у Daily APR: розділити annualized rate на 365. Показувати користувачеві APY (більш зрозуміла метрика), всередину розраховувати у Daily APR.
Reward токени: як включати в розрахунок
Багато протоколів поверх базової ставки платять власні токени (COMP, AAVE, MORPHO). Потрібно включити в total APY, але з урахуванням:
- Поточна ціна reward токена (volatile — ціна може упасти до моменту claim)
- Vesting/lock: AAVE Safety Module rewards вестуються 10 днів
- Emission decay: зниження emissions з часом (багато протоколів зменшують emissions кожні N днів)
Підхід: показувати base APY (без rewards) та total APY (з rewards) окремо. Користувач сам вирішує, враховувати ли нестабільні rewards.
Отримання даних on-chain
Кожен протокол надає дані по-своєму:
Aave V3: getReserveData(asset) повертає currentLiquidityRate у ray (1e27). Конвертація: APR = rate / 1e27 * SECONDS_PER_YEAR. Rewards через getRewardsData() в RewardsController.
Compound V3 (Comet): getSupplyRate(utilization) повертає rate за секунду. APR = ratePerSecond * SECONDS_PER_YEAR.
Morpho: агрегує ринки Aave та Compound з оптимізацією. Base rate = underlying market rate, але з peer-to-peer matching може бути вища. supplyAPR() з контракту Morpho Lens.
Curve: дохідність з кількох джерел — trading fees (автоматично реінвестуються), CRV emissions (через gauge), boost. CRV APY залежить від veCRV балансу користувача. Для систем порівняння беремо «base» APY без boost.
Pendle: YT (Yield Token) implied APY розраховується через ціну PT — не прямо значення з контракту, а розрахунок через market price.
Архітектура системи
Шар отримання даних
On-chain виклики дорогі (в смислі RPC requests). При 10 протоколах × 20 активів × 5 метрик = 1000 викликів при кожному оновленні. Рішення: Multicall3 батчинг — всі виклики в одну транзакцію.
const calls = protocols.flatMap(protocol =>
assets.map(asset => ({
target: protocol.address,
callData: protocol.interface.encodeFunctionData("getReserveData", [asset])
}))
);
const results = await multicall.aggregate(calls);
Для історичних даних — The Graph субграфи. Більшість крупних протоколів (Aave, Compound, Uniswap) мають офіційні субграфи з історичними даними rate за годину.
Кеширование та оновлення
APY у DeFi змінюється з кожним блоком, але значимо — раз на кілька хвилин. Агресивне кеширование:
- L1 cache (Redis): поточні rates, TTL 60 секунд
- L2 cache (PostgreSQL): часові снимки для історичних графіків
- Real-time оновлення: WebSocket для підписки на зміни (якщо доступно)
Background job кожні 60 секунд fetches on-chain дані, оновлює Redis, раз на годину записує снимок у PostgreSQL.
Історична динаміка
Поточний APY — миттєвий снимок. Для прийняття рішень потрібна історична динаміка: як змінювався APY за останні 7/30/90 днів, як реагував на ринкові события.
З часових снимків будуємо:
- Moving average (7d, 30d) для розуміння середньої дохідності
- Volatility метрика (std deviation APY) — наскільки стабільна дохідність
- Min/max за період — floor та ceiling очікуваної дохідності
Volatile APY (змінюється в 5x діапазоні за місяць) — інший профіль ризику, ніж stable APY (±0.5%). Це важлива інформація для користувача.
Ранжування та порівняння
Просто сортувати по APY — недостатньо. Ранжування повинно враховувати:
- Risk-adjusted yield: різні протоколи мають різний risk profile (історія аудитів, TVL, вік)
- Liquidity: доступна deposit capacity — важливо для великих сум
- Stable vs volatile APY: rewards в нативних токенах менш надійні
- Мережа: gas видатки на Ethereum vs L2 — важливі для малих депозитів
Просте рішення: показувати фільтри (лише stable APY, лише audited протоколи, мінімум TVL) без створення єдиного «score» — користувач сам зважує пріоритети.
Технічний стек
Backend: Node.js + TypeScript. Viem для on-chain викликів (легше ethers.js, tree-shakeable). PostgreSQL для історичних даних. Redis для кешування. Bullmq для черги background jobs.
Frontend: Next.js, TanStack Query для отримання даних з кешуванням та refetch intervals. Recharts або Tremor для графіків історичної дохідності.
Subgraphs: The Graph для історичних даних Aave, Compound, Uniswap. Для протоколів без офіційного субграфу — custom event indexer через Ponder або custom indexer.
Орієнтири по строкам
MVP з 3-5 протоколами, поточні rates без історії — 3-5 днів. Повноцінна система з історичними даними, нормалізацією, фільтрами та візуалізацією — 2-3 тижні. Вартість розраховується індивідуально.







