Реалізація просмотру доходності DeFi-позицій у мобільному кошельку
DeFi-позиції — ліквідність у Uniswap v3, стейкинг у Lido, лендинг у Aave — у кожного протоколу свої смарт-контракти, свої методи розрахунку доходності та своя логіка визначення поточного балансу. Агрегувати це в єдиний екран «ваші позиції» без готового агрегатора складно: потрібно знати адреси контрактів кожного протоколу, ABI-інтерфейси, формули розрахунку APY.
Джерела даних для DeFi-позицій
DeFi Llama API — безплатний агрегатор протоколів. Endпоінт /tvl/{protocol} повертає TVL, /yields — поточні APY за пулами. Добре підходить для відображення ринкових даних, але не дає позицій конкретної адреси.
Zapper API / Zerion API — агрегатори портфелів. Один запит з адресою кошельку повертає всі DeFi-позиції за підтримуваними протоколами з поточним балансом та P&L. Zerion підтримує 400+ протоколів на 10+ сітях. Платні, але економлять місяць розробки.
Прямі виклики смарт-контрактів через eth_call — для специфічних протоколів або кастомних даних, яких немає в агрегаторах.
Читаємо позицію напряму з контракту: Aave v3
Для Aave v3 основний контракт — UiPoolDataProviderV3. Один eth_call повертає всі дані за всіма резервами користувача:
// Виклик через web3dart
final contract = DeployedContract(
ContractAbi.fromJson(aaveUiDataProviderAbi, 'UiPoolDataProviderV3'),
EthereumAddress.fromHex('0x91c0eA31b49B69Ea18607702c5d9aC360bf3dE7d'), // Ethereum mainnet
);
final result = await ethClient.call(
contract: contract,
function: contract.function('getUserReservesData'),
params: [
EthereumAddress.fromHex(poolAddressProvider), // Aave pool address provider
EthereumAddress.fromHex(userAddress),
],
);
// result[0] — List<UserReserveData>: токен, currentATokenBalance, currentVariableDebt, ...
Структура UserReserveData містить currentATokenBalance (скільки депозитовано з урахуванням накопленних відсотків) та currentVariableDebt (змінний борг). APY обчислюється з liquidityRate резерву через формулу APY = (1 + liquidityRate/10^27 / secondsPerYear)^secondsPerYear - 1.
Uniswap v3: позиції з діапазоном цін
Uniswap v3 — складніше, тому що кожна позиція — NFT з індивідуальним діапазоном концентрованої ліквідності. NFT-позиції зберігаються в NonfungiblePositionManager (адреса 0xC36442b4a4522E871399CD717aBDD847Ab11FE88 на mainnet).
Для отримання позицій користувача потрібно:
-
balanceOf(userAddress)— кількість NFT-позицій -
tokenOfOwnerByIndex(userAddress, index)— token IDs для кожної позиції -
positions(tokenId)— параметри позиції: token0/token1, fee tier, tickLower, tickUpper, liquidity
Розрахунок поточної кількості token0/token1 з liquidity та поточного sqrtPriceX96 — нетривіальна математика за формулами Uniswap v3 whitepaper. Правильніше використовувати готовий @uniswap/v3-sdk на JS через WebView bridge або портувати формули на Dart/Kotlin/Swift.
Простіше: Uniswap Subgraph на The Graph повертає position з уже посчитаним collectedFeesToken0, collectedFeesToken1, depositedToken0, depositedToken1.
Розрахунок P&L за DeFi-позицією
P&L = (поточна вартість позиції в USD) - (спочатку вложена вартість в USD)
Підводний камінь: impermanent loss. Якщо вкласти 1 ETH + 1000 USDC у пул на Uniswap v3, а ETH виріс — у пулі стане менше ETH та більше USDC. Просто порівняти поточний баланс з початковим у USD недостатньо — потрібно враховувати IL відносно hold-стратегії.
Для відображення P&L користувачу: показуємо «fees earned» окремо від «price change of underlying assets» — це зрозуміліше, ніж єдине число P&L.
Оновлення даних та кешування
DeFi-дані змінюються з кожним блоком (~12 секунд на Ethereum). Запитувати їх при кожному відкритті екрана — достатньо, pull-to-refresh — стандартний UX-паттерн. Кешувати з TTL 60 секунд: користувачі не очікують real-time точності для лендингу.
Для стейкинг-позицій з повільним накопленням доходності (Lido stETH) — локально рахуємо накопленний yield за поточним APY та часом з останнього оновлення, відображаємо оптимістичну оцінку без лишніх запитів.
Що входить у роботу
- Вибір та інтеграція джерел даних (агрегатори або прямі контракти)
- Відображення позицій для пріоритетних протоколів (Aave, Uniswap, Compound, Lido та ін.)
- Розрахунок поточного балансу та APY
- Відображення fees earned та P&L
- Кешування з правильним TTL
- Підтримка кількох сітей (Ethereum, Arbitrum, Optimism, Base)
Строки
Інтеграція через агрегатор (Zerion/Zapper) з відображенням позицій: 1–2 тижні. Прямої інтеграції з 3–5 протоколами з кастомним розрахунком P&L: 4–6 тижнів. Вартість розраховується індивідуально.







