Наша кастомна розробка забезпечує моніторинг позицій 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 дні та запропонуємо оптимальне рішення. Бюджет розраховується індивідуально після аналізу ваших вимог.
Отримайте консультацію — наші інженери запропонують рішення під ваші завдання.







