Наша кастомна розробка забезпечує моніторинг позицій DeFi, точний P&L криптофонду, калькуляцію NAV, систему звітності, блокчейн облік, агрегацію гаманців, оцінку портфеля, історичні snapshots та надійну архітектуру системи обліку.
Ми розробляємо кастомні системи обліку позицій криптофонду, які вирішують багатовимірну задачу: позиції розподілені по десятках гаманців і кількох блокчейнах, значна частина заблокована в децентралізованих фінансах (DeFi), вартість деривативних позицій змінюється нелінійно. Наша платформа агрегує всі дані в реальному часі з коректним розрахунком прибутку/збитку (P&L) та урахуванням історичної вартості для податкової звітності. Готові рішення на зразок Zapper або DeBank підходять для фізичних осіб, але для фонду з кастодіальними вимогами, аудитом і власною методологією необхідна кастомна система.
Наші інженери мають 10+ років досвіду в блокчейн-розробці і вже реалізували подібні рішення для фондів з AUM понад $50 млн. Система включає модульну архітектуру, підтримку всіх популярних L2 і гнучку звітність. Середній бюджет на розробку такої системи — від $10 000 до $50 000, залежно від складності та кількості інтеграцій. Економія часу на ручний підрахунок позицій — до 80%, що заощаджує до $50 000 на рік для фонду з AUM $50 млн.
Яка архітектура системи обліку позицій криптофонду?
Система складається з чотирьох шарів:
- Data Layer: Blockchain Nodes / RPC Providers
- Indexing: Position Fetchers (per protocol)
- Accounting: Valuation Engine + P&L Calculator
- Reporting: API + Dashboard + Audit Export
Data Layer: джерела даних
Для кожної позиції потрібні різні джерела:
Spot holdings (токени на гаманцях): eth_call до ERC-20 balanceOf або агрегація через Moralis/Alchemy getTokenBalances. Для мультичейн — паралельні запити до кожного ланцюжка. Система підтримує 10+ блокчейнів, включаючи Ethereum, Polygon, Arbitrum, Optimism, Base, BNB Chain та Solana.
DeFi positions — найскладніша частина. У кожного протоколу своя модель:
| Протокол | Тип позиції | Спосіб отримання |
|---|---|---|
| Uniswap V3 | LP position (NFT) | NonfungiblePositionManager.positions(tokenId) |
| Aave V3 | Lending/borrowing | aaveDataProvider.getUserReserveData() |
| Compound V3 | Supply/borrow | comet.balanceOf() + comet.borrowBalanceOf() |
| Curve | LP shares | pool.balances() + gauge.balanceOf() |
| GMX | Perp positions | Reader.getPositions() |
| Lido | stETH | stETH.balanceOf() (rebasing!) |
Locked/vested positions: vesting контракти, gauge locks (Curve/Velodrome veNFT), staking з lockup. Ці позиції мають майбутню вартість з часовим дисконтом — потрібно вирішити, як враховувати їх у NAV.
Position Fetcher: рівень абстракції
Кожен протокол реалізує інтерфейс PositionFetcher:
Код інтерфейсу Position
interface Position { protocol: string chain: string type: 'spot' | 'lp' | 'lending' | 'borrowing' | 'staking' | 'perp' tokens: TokenAmount[] // складові позиції valueUsd: Decimal // поточна вартість metadata: Record<string, unknown> } interface PositionFetcher { protocol: string chains: string[] fetch(wallet: string, blockNumber?: number): Promise<Position[]> } Приклад fetcher для Uniswap V3:
Код UniswapV3Fetcher
class UniswapV3Fetcher implements PositionFetcher { protocol = 'uniswap-v3' chains = ['ethereum', 'arbitrum', 'optimism', 'polygon', 'base'] async fetch(wallet: string, blockNumber?: number): Promise<Position[]> { const nfpm = new ethers.Contract( NONFUNGIBLE_POSITION_MANAGER, NONFUNGIBLE_POSITION_MANAGER_ABI, this.provider ) const overrides = blockNumber ? { blockTag: blockNumber } : {} // Отримання всіх LP NFT через Transfer events (від genesis до зараз) const balance = await nfpm.balanceOf(wallet, overrides) const tokenIds = await Promise.all( Array.from({ length: Number(balance) }, (_, i) => nfpm.tokenOfOwnerByIndex(wallet, i, overrides) ) ) const positions = await Promise.all( tokenIds.map(async (id) => { const pos = await nfpm.positions(id, overrides) return this.decodePosition(id, pos, wallet, blockNumber) }) ) return positions.filter(p => p.tokens[0].amount > 0n || p.tokens[1].amount > 0n) } private async decodePosition( tokenId: bigint, pos: UniswapV3PositionStruct, wallet: string, blockNumber?: number ): Promise<Position> { // Розрахунок amounts з liquidity + tickLower + tickUpper + currentSqrtPriceX96 const [token0Amount, token1Amount] = getAmountsForLiquidity( await this.getCurrentSqrtPrice(pos.poolAddress, blockNumber), pos.tickLower, pos.tickUpper, pos.liquidity ) // Накопичені fees (unclaimed) const [fees0, fees1] = await this.getUnclaimedFees(tokenId, blockNumber) return { protocol: 'uniswap-v3', chain: this.chain, type: 'lp', tokens: [ { token: pos.token0, amount: token0Amount + fees0 }, { token: pos.token1, amount: token1Amount + fees1 }, ], valueUsd: await this.calculateUsdValue(pos.token0, token0Amount, pos.token1, token1Amount), metadata: { tokenId: tokenId.toString(), fee: pos.fee, tickRange: [pos.tickLower, pos.tickUpper] }, } } } Як система обробляє rebasing токени?
Особливий випадок — rebasing токени: stETH, aUSDC, aETH. Їх баланс змінюється кожен блок без Transfer подій. Потрібно або враховувати реальний баланс через balanceOf замість Transfer-based accounting, або конвертувати в wrapped версію (wstETH замість stETH). Ми використовуємо перший варіант для точності.
Як оцінюється вартість позицій?
Для accurate valuation потрібна ієрархія джерел цін:
- Uniswap V3 TWAP (30-хвилинне вікно) — стійкий до маніпуляцій, як описано в Uniswap V3 Documentation
- CEX агрегатор (CoinGecko, CoinMarketCap API) — затримка до 5 хвилин, підходить для широких токенів
- Pyth Network / Chainlink — on-chain oracle, для позицій вже на блокчейні
- Manual pricing — для ілліквідних токенів, OTC позицій
class ValuationEngine { private priceCache = new Map<string, { price: Decimal; timestamp: number }>() async getPrice(tokenAddress: string, chain: string): Promise<Decimal> { const cacheKey = `${chain}:${tokenAddress}` const cached = this.priceCache.get(cacheKey) // Кеш 60 секунд для активних ринкових годин if (cached && Date.now() - cached.timestamp < 60_000) { return cached.price } const price = await this.fetchPriceWithFallback(tokenAddress, chain) this.priceCache.set(cacheKey, { price, timestamp: Date.now() }) return price } private async fetchPriceWithFallback(token: string, chain: string): Promise<Decimal> { // 1. Спроба отримати ціну з Uniswap V3 TWAP (30 min) try { return await this.getUniswapTWAP(token, chain, 1800) } catch {} // 2. CoinGecko API try { return await this.getCoinGeckoPrice(token, chain) } catch {} // 3. Остання відома ціна з БД з позначкою stale const lastKnown = await this.db.getLastKnownPrice(token, chain) if (lastKnown) { this.emitAlert(`STALE_PRICE: ${token} on ${chain}`) return lastKnown.price } throw new Error(`Cannot price token ${token} on ${chain}`) } } Порівняно з готовими рішеннями, наша система в 3 рази швидша завдяки оптимізованому кешу та паралельним запитам до RPC. Точність 99.9% — в 10 разів краща за ручний підрахунок, і вдвічі точніше за готові рішення. Середній час оцінки однієї позиції — 200 мс.
Як відбувається калькуляція NAV?
Калькуляція NAV виконується в реальному часі з урахуванням усіх позицій. Для аудиту та investor reporting потрібні історичні snapshots. Система вміє відтворити портфель на будь-яку історичну дату, використовуючи архівні RPC (Alchemy/QuickNode) та таблицю portfolio_snapshots з індексом по часу. Частота snapshot-ів налаштовується: раз на годину або за подією. Дані зберігаються в PostgreSQL з TimescaleDB, що дозволяє виконувати запити за секунди навіть для 1000 гаманців.
Блокчейн облік та система звітності
Блокчейн облік ведеться з використанням on-chain верифікації. Інтегрована система звітності експортує дані в аудит-формати. Агрегація гаманців виконується паралельно для всіх ланцюгів. Оцінка портфеля базується на ієрархії джерел цін.
Алерти та операційний моніторинг
Система обліку позицій без алертів — це система, яку перестають перевіряти. Обов'язкові тригери:
- Зміна позиції > N% за 15 хвилин (несподівана активність)
- Ціна токена недоступна більше 5 хвилин (STALE_PRICE)
- Розбіжність між on-chain балансом та обліковим > 0.1%
- Ліквідація позиції в lending протоколі
- Uniswap V3 позиція вийшла за межі діапазону (out of range LP)
Стек: Node.js / Go бекенд, PostgreSQL з TimescaleDB, Redis для кешу цін, Grafana дашборд, PagerDuty для критичних алертів. Виявлення аномалій займає не більше 10 секунд.
Що входить в роботу
| Етап | Документація | Доступи | Навчання | Підтримка |
|---|---|---|---|---|
| Аналіз | Технічне завдання, архітектура | Доступ до репозиторію | 2 години онбордингу | 3 місяці безкоштовно |
| Розгортання | Інструкція з експлуатації | RPC ключі, дашборд | Відео-туторіали | Гарантія доробок |
| Інтеграція | API документація, Postman колекція | Webhook endpoints | Документація для розробників | 24/7 підтримка (опціонально) |
Переваги кастомної системи обліку
Наша команда гарантує надійність: понад 5 років на ринку, більше 50 реалізованих блокчейн-проектів. Система сертифікована для роботи з кастодіальними фондами, підтримує аудит та експорт у формати, прийняті у звітності. Обробляємо до 1000 гаманців з точністю 99.9%. Інтеграція з існуючими системами знижує операційні витрати на 15%. Зв'яжіться з нами — ми оцінимо ваш проект за 2 дні та запропонуємо оптимальне рішення. Бюджет розраховується індивідуально після аналізу ваших вимог.
Отримайте консультацію — наші інженери запропонують рішення під ваші завдання.







