Разработка панели LP (Limited Partner) для крипто-фонда
Limited Partner крипто-фонда хочет знать три вещи: сколько стоит его доля прямо сейчас, как изменилась NAV за период и что именно находится в портфеле. Звучит просто, но на практике крипто-фонд держит активы в десятках мест одновременно — hot wallets на разных сетях, позиции в DeFi-протоколах, стейкинг, ликвидность в пулах, OTC-позиции в CeFi — и все они считаются по-разному.
Источники данных портфеля
Главная сложность LP-дашборда — не UI, а агрегация данных из гетерогенных источников с корректным расчётом стоимости.
On-chain позиции
Простые балансы — ERC-20 токены на custody адресах. Читаются через multicall (Multicall3 по адресу 0xcA11bde05977b3631167028862bE2a173976CA11 — задеплоен на 100+ сетях). Один RPC-запрос возвращает балансы по сотне контрактов:
const calls = tokens.map(token => ({
target: token.address,
callData: erc20.encodeFunctionData("balanceOf", [walletAddress])
}));
const results = await multicall3.aggregate3(calls);
Liquidity pool позиции — Uniswap V3 позиции в виде NFT (ERC-721). Для расчёта текущей стоимости нужно читать NonfungiblePositionManager.positions(tokenId), затем считать amount0/amount1 через формулу ликвидности V3. Готовые SDK: @uniswap/v3-sdk с методом Position.fromAmounts().
Lending позиции — Aave V3 возвращает полную информацию через getUserAccountData(): collateral, debt, health factor. Compound через CToken.borrowBalanceCurrent() и CToken.balanceOfUnderlying(). Для сети Ethereum + 3 L2 это уже 8 отдельных запросов только для Aave/Compound.
Staking — validator balances через Beacon Chain API (/eth/v1/beacon/states/finalized/validator_balances). Liquid staking (stETH, rETH) — просто ERC-20 баланс, конвертированный в ETH по текущему exchange rate.
Off-chain позиции
CeFi позиции (биржи, OTC-деск) читаются через их API:
- Binance:
GET /api/v3/account(HMAC-SHA256 подпись) - Coinbase Prime: REST API с JWT аутентификацией
- OTC-позиции часто через manual import или CSV
Архитектурный паттерн: каждый источник данных — отдельный adapter с единым интерфейсом:
interface PositionAdapter {
getPositions(params: AdapterParams): Promise<Position[]>;
getHistoricalNAV(from: Date, to: Date): Promise<NAVPoint[]>;
}
Расчёт NAV и ценообразование
NAV (Net Asset Value) — центральный показатель, вокруг которого строится весь дашборд. Корректный расчёт требует цен на каждый актив в моменте.
Источники цен
| Тип актива | Источник цены |
|---|---|
| Major tokens (ETH, BTC, SOL) | Chainlink Price Feeds или CoinGecko API |
| DeFi long-tail | Uniswap V3 TWAP (30-минутный) |
| LP позиции Uniswap V3 | Формула из tick bounds + spot price |
| NFT / неликвид | Manual input или пауза в расчёте |
| Lending collateral | Underlying token price × collateral factor |
Для исторического NAV нужны исторические цены. CoinGecko Pro API предоставляет OHLCV данные с дневным и почасовым разрешением. Для минутного разрешения — собственный сбор цен из событий Uniswap.
Важно: NAV считается в USD, но фонд может иметь позиции в нескольких базовых валютах. Нужна таблица FX rates (ECB API или fx-rates от Fixer.io) для конвертации non-USD деноминированных позиций.
Расчёт доли LP
Когда NAV посчитан, доля конкретного LP:
LP Share Value = NAV × (LP Capital / Total Fund Capital)
Для фондов с нескольким классами акций (Fund I / Fund II, different fee structures) — отдельный NAV per share class. Management fee и performance fee (carried interest) снижают NAV LP при начислении.
Архитектура системы
Data Aggregation Layer
├── On-chain adapters (Ethereum, Arbitrum, Solana...)
├── CeFi adapters (Binance, Coinbase, OTC)
└── Manual input (для неликвидных позиций)
↓
Pricing Engine
(CoinGecko + Chainlink + Uniswap TWAP)
↓
NAV Calculator
(portfolio aggregation, FX conversion, share class logic)
↓
Database (PostgreSQL + TimescaleDB для time-series NAV)
↓
API Layer (REST / GraphQL)
↓
LP Dashboard (React)
TimescaleDB — расширение PostgreSQL для time-series данных. NAV snapshots пишутся каждые 15–60 минут, исторические запросы ("NAV за последние 90 дней с daily resolution") выполняются через continuous aggregates.
Функциональность дашборда
Для LP (read-only доступ):
- Текущая стоимость доли с динамикой за 1d/7d/30d/1y
- Breakdown по asset classes: DeFi, CeFi, Staking, Cash
- Unrealized P&L по каждой позиции
- Capital calls и distributions история
- Документы: quarterly reports, K-1/tax statements
Для GP (управляющий фонда):
- Полный portfolio view с позициями по адресам
- Risk metrics: concentration risk, correlation matrix
- Waterfall расчёт carried interest при различных сценариях выхода
- Экспорт в CSV/Excel для отчётности перед инвесторами
Безопасность и доступ
LP видит только свою позицию, не позиции других инвесторов. Authentication через JWT + MFA (TOTP). Данные API ключей от бирж хранятся зашифрованными (AES-256, ключи в AWS KMS / HashiCorp Vault) — LP-дашборд требует только read-only ключи, write-доступ никогда не нужен.
Для белого-листа IP с которых принимаются API-запросы к биржам — дополнительный уровень защиты от компрометации ключей.
Технический стек
Backend: Node.js (TypeScript) + PostgreSQL + TimescaleDB. Cron-задачи для периодического обновления NAV через node-cron или Bull queue. Redis для кэширования текущих цен (TTL 60 сек).
Frontend: React + Recharts или TradingView Lightweight Charts для NAV графиков. Table компоненты (TanStack Table) для портфолио breakdown.
Infrastructure: Railway / Render для MVP, AWS ECS + RDS для production с SLA. Отдельный сервис для on-chain data fetching с возможностью горизонтального масштабирования.
Типичный timeline: MVP с основными функциями — 8–12 недель. Production-ready система с аудитом доступа, полным набором адаптеров и документоборотом — 4–6 месяцев.







