Розробка дашборда DeFi-портфеля: агрегація, P&L, мультичейн

Ми розробляємо дашборди DeFi-портфелів під ключ. Уявіть: користувач тримає USDC в Aave, ETH-USDC LP в Uniswap V3, wstETH в Lido, та відкриту перпетуал позицію на GMX. Чотири різних протоколи, чотири різних способи представлення позицій, чотири різних API або субграфи. Завдання дашборда — агрегувати

Напрямки блокчейн-розробки

Часті запитання

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1452
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1309
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    1005
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1270
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    719
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    1012

Ми розробляємо дашборди DeFi-портфелів під ключ. Уявіть: користувач тримає USDC в Aave, ETH-USDC LP в Uniswap V3, wstETH в Lido, та відкриту перпетуал позицію на GMX. Чотири різних протоколи, чотири різних способи представлення позицій, чотири різних API або субграфи. Завдання дашборда — агрегувати все це в єдиний екран з реальними цифрами P&L. Наш досвід показує, що 80% зусиль йде на data layer: нормалізацію даних з різних джерел та коректний розрахунок stale/live балансів. Ми гарантуємо точність до блоку та мінімальну затримку. Зв'яжіться з нами, щоб оцінити проект для вашого стеку.

Як розраховується P&L та impermanent loss?

Найскладніша частина — коректний розрахунок unrealized P&L по LP позиціях. Для Uniswap V3 позиція — це NFT з певними tickLower, tickUpper, liquidity. Поточні amounts token0 та token1 залежать від поточного sqrtPriceX96 пулу. Формула нетривіальна:

function getAmountsFromLiquidity( sqrtPriceX96: bigint, sqrtRatioAX96: bigint, sqrtRatioBX96: bigint, liquidity: bigint ): [bigint, bigint] { if (sqrtPriceX96 <= sqrtRatioAX96) { const amount0 = (liquidity * (sqrtRatioBX96 - sqrtRatioAX96) * Q96) / (sqrtRatioBX96 * sqrtRatioAX96) return [amount0, 0n] } else if (sqrtPriceX96 < sqrtRatioBX96) { const amount0 = (liquidity * (sqrtRatioBX96 - sqrtPriceX96) * Q96) / (sqrtRatioBX96 * sqrtPriceX96) const amount1 = (liquidity * (sqrtPriceX96 - sqrtRatioAX96)) / Q96 return [amount0, amount1] } else { const amount1 = (liquidity * (sqrtRatioBX96 - sqrtRatioAX96)) / Q96 return [0n, amount1] } } 

Impermanent loss вважається як різниця між поточною вартістю позиції та вартістю, якби ті самі активи просто трималися з моменту входу. Для дашборда потрібно зберігати entry price та initial amounts при відкритті позиції.

Які джерела даних ми використовуємо?

On-chain direct calls vs індексатори. Найточніший спосіб отримати баланс — прямий eth_call до контракту. Для токен-балансу — balanceOf(). Для позиції Aave — getUserAccountData(). Це завжди актуально, але повільно: кожен протокол вимагає окремих викликів, а при кількох десятках протоколів латентність зростає лінійно. Рішення — Multicall3 (контракт 0xC...A11, деплой на всіх major EVM чейнах): батч з 50+ викликів в одній транзакції. Час відповіді — як один RPC виклик замість 50. Порівняння: Multicall3 в 20 разів швидший за послідовні виклики.

import { multicall } from 'viem' const results = await multicall(client, { contracts: [ { address: AAVE_POOL, abi: aavePoolAbi, functionName: 'getUserAccountData', args: [userAddress] }, { address: USDC_TOKEN, abi: erc20Abi, functionName: 'balanceOf', args: [userAddress] }, { address: UNISWAP_POSITION_MANAGER, abi: nftAbi, functionName: 'balanceOf', args: [userAddress] }, ] }) 

Для історичних даних (історія транзакцій, PnL за часом) прямі виклики не працюють — потрібні індексатори.

The Graph для історичних даних. Uniswap, Aave, Compound, Curve, Balancer — всі мають офіційні subgraphs в The Graph Network. Subgraph надає GraphQL API для запиту історичних подій: deposits, withdrawals, swaps, liquidations.

query UserPositions($user: String!) { aaveV3_deposits(where: { user: $user }, orderBy: timestamp, orderDirection: desc) { amount reserve { symbol, decimals, priceInUSD } timestamp } aaveV3_borrows(where: { user: $user }) { amount reserve { symbol } currentVariableBorrowRate } } 

Проблема: у різних версій протоколів різні subgraphs. Aave V2 на Ethereum, Aave V3 на Polygon, Aave V3 на Arbitrum — три різних субграфи з різними схемами. Нормалізація — основна інженерна задача дашборда. Ми використовуємо єдиний шар абстракції, який мапить всі схеми в одну модель даних.

Alchemy та Moralis як API-over-RPC. Alchemy API надає готові методи: getTokenBalances() повертає всі ERC-20 баланси адреси без перебору контрактів. getAssetTransfers() — історію трансферів. Це значно спрощує початкову реалізацію, але коштує грошей при високому навантаженні. Moralis додатково агрегує дані про NFT позиції та DeFi protocol positions через їх DeFi API — платний, але економить місяці розробки кастомного data layer. Для MVP виправданий Alchemy + The Graph для ключових протоколів. Для production з десятками тисяч користувачів — власний indexer.

Джерело Свіжість Вартість Складність інтеграції
Multicall3 Live (до блоку) Безкоштовно (газ RPC) Середня
The Graph Відставання ~1 хв Безкоштовно (ліміти) Висока (різні схеми)
Alchemy API Live Платний (за запитами) Низька
Moralis Live Платний (підписка) Низька

Мультичейн агрегація

Типовий користувач активний на Ethereum mainnet, Arbitrum, Polygon, Base. Дашборд повинен показувати сумарний портфель поперек чейнів. Схема: паралельні запити до RPC кожного чейна через Promise.all(), нормалізація балансів в USD через єдиний price oracle. Coingecko API або DefiLlama Price API для отримання актуальних цін за token address + chain ID. Проблема cross-chain identity: адреса користувача однакова на всіх EVM чейнах (ECDSA), але смарт-контракт гаманець (Safe, Argent) може мати різні адреси на різних чейнах при несинхронізованому деплої. Ми підтримуємо multi-address mode: користувач може додати кілька адрес в один профіль.

Як ми забезпечуємо продуктивність?

Backend: Node.js + TypeScript з viem для RPC. Redis для кешу балансів (TTL 30 секунд для live даних, 5 хвилин для історичних). PostgreSQL для зберігання історичних snapshot-ів портфеля (для побудови equity curve).

Frontend: React + wagmi v2 для wallet connection, Recharts або TradingView Lightweight Charts для графіків, Tanstack Query для data fetching з автоматичним refetch кожні 30 секунд.

WebSocket для real-time оновлень: підписка на eth_subscribe("newHeads") для тригера оновлення балансів при новому блоці — виглядає живо без зайвих poll-запитів.

Приклад налаштування WebSocket
const transport = http('https://mainnet.infura.io/v3/YOUR_KEY') const client = createPublicClient({ transport }) 

Що входить в роботу

  • Документація по data layer (схеми даних, опис нормалізації).
  • Доступ до репозиторію з повним кодом дашборда.
  • Навчання команди замовника (2 години онлайн).
  • 2 тижні безкоштовної підтримки після деплою.
  • Можливість SLA на подальший супровід.

Наш досвід: 5 років на ринку blockchain-розробки, 20+ успішних проектів в DeFi. Ми гарантуємо, що дашборд працюватиме без простоїв та з точністю до останнього блоку.

Процес роботи

  1. Аналітика (1–2 дні). Список цільових протоколів та чейнів, пріоритизація за popular use cases аудиторії.
  2. Data layer (5–7 днів). Multicall агрегатор, інтеграція The Graph для ключових протоколів, нормалізація в єдину схему позиції.
  3. Backend API (3–5 днів). REST/GraphQL API для фронтенду, кешування, історія портфеля.
  4. Frontend (5–7 днів). Wallet connection, сумарний balance view, деталі за протоколами, графіки.

Орієнтири за термінами

Етап Термін
MVP (5–7 протоколів, 2–3 чейни) 2–3 тижні
Повноцінний дашборд (історія, IL, алерти, мобільний) 6–8 тижнів

Отримайте консультацію по вашому проекту — оцінимо складність та терміни безкоштовно.