Development of LP (Limited Partner) Dashboard for Crypto Fund
A Limited Partner in a crypto fund wants to know three things: how much their share is worth right now, how NAV changed over the period, and what exactly is in the portfolio. Sounds simple, but in practice a crypto fund holds assets in dozens of places simultaneously — hot wallets on different networks, positions in DeFi protocols, staking, liquidity in pools, OTC positions in CeFi — and each is calculated differently.
Portfolio Data Sources
The main challenge of LP dashboard — not UI, but aggregating data from heterogeneous sources with correct valuation.
On-Chain Positions
Simple balances — ERC-20 tokens on custody addresses. Read via multicall (Multicall3 at address 0xcA11bde05977b3631167028862bE2a173976CA11 — deployed on 100+ networks). One RPC request returns balances across hundreds of contracts:
const calls = tokens.map(token => ({
target: token.address,
callData: erc20.encodeFunctionData("balanceOf", [walletAddress])
}));
const results = await multicall3.aggregate3(calls);
Liquidity pool positions — Uniswap V3 positions as NFT (ERC-721). To calculate current value you need to read NonfungiblePositionManager.positions(tokenId), then calculate amount0/amount1 via V3 liquidity formula. Ready SDKs: @uniswap/v3-sdk with Position.fromAmounts() method.
Lending positions — Aave V3 returns full information via getUserAccountData(): collateral, debt, health factor. Compound via CToken.borrowBalanceCurrent() and CToken.balanceOfUnderlying(). For Ethereum + 3 L2s this is already 8 separate requests just for Aave/Compound.
Staking — validator balances via Beacon Chain API (/eth/v1/beacon/states/finalized/validator_balances). Liquid staking (stETH, rETH) — just ERC-20 balance converted to ETH by current exchange rate.
Off-Chain Positions
CeFi positions (exchanges, OTC desk) are read via their APIs:
- Binance:
GET /api/v3/account(HMAC-SHA256 signature) - Coinbase Prime: REST API with JWT authentication
- OTC positions often via manual import or CSV
Architectural pattern: each data source — separate adapter with unified interface:
interface PositionAdapter {
getPositions(params: AdapterParams): Promise<Position[]>;
getHistoricalNAV(from: Date, to: Date): Promise<NAVPoint[]>;
}
NAV Calculation and Valuation
NAV (Net Asset Value) — central metric around which the whole dashboard is built. Correct calculation requires prices for each asset at the moment.
Price Sources
| Asset Type | Price Source |
|---|---|
| Major tokens (ETH, BTC, SOL) | Chainlink Price Feeds or CoinGecko API |
| DeFi long-tail | Uniswap V3 TWAP (30-minute) |
| Uniswap V3 LP position | Formula from tick bounds + spot price |
| NFT / illiquid | Manual input or pause calculation |
| Lending collateral | Underlying token price × collateral factor |
For historical NAV you need historical prices. CoinGecko Pro API provides OHLCV data with daily and hourly resolution. For minute resolution — own collection of prices from Uniswap events.
Important: NAV is calculated in USD, but fund can have positions in multiple base currencies. Need FX rates table (ECB API or fx-rates from Fixer.io) to convert non-USD denominated positions.
LP Share Value Calculation
When NAV is calculated, LP's share value:
LP Share Value = NAV × (LP Capital / Total Fund Capital)
For funds with multiple share classes (Fund I / Fund II, different fee structures) — separate NAV per share class. Management fee and performance fee (carried interest) reduce LP NAV when accrued.
System Architecture
Data Aggregation Layer
├── On-chain adapters (Ethereum, Arbitrum, Solana...)
├── CeFi adapters (Binance, Coinbase, OTC)
└── Manual input (for illiquid positions)
↓
Pricing Engine
(CoinGecko + Chainlink + Uniswap TWAP)
↓
NAV Calculator
(portfolio aggregation, FX conversion, share class logic)
↓
Database (PostgreSQL + TimescaleDB for time-series NAV)
↓
API Layer (REST / GraphQL)
↓
LP Dashboard (React)
TimescaleDB — PostgreSQL extension for time-series data. NAV snapshots are written every 15–60 minutes, historical queries ("NAV for last 90 days with daily resolution") executed via continuous aggregates.
Dashboard Functionality
For LP (read-only access):
- Current share value with dynamics for 1d/7d/30d/1y
- Breakdown by asset classes: DeFi, CeFi, Staking, Cash
- Unrealized P&L per each position
- Capital calls and distributions history
- Documents: quarterly reports, K-1/tax statements
For GP (fund manager):
- Full portfolio view with positions per address
- Risk metrics: concentration risk, correlation matrix
- Waterfall calculation of carried interest under different exit scenarios
- Export to CSV/Excel for investor reporting
Security and Access
LP sees only their own position, not other investors' positions. Authentication via JWT + MFA (TOTP). Exchange API key data stored encrypted (AES-256, keys in AWS KMS / HashiCorp Vault) — LP dashboard requires only read-only keys, write access is never needed.
Whitelist of IPs for API requests to exchanges — additional layer of protection from key compromise.
Technical Stack
Backend: Node.js (TypeScript) + PostgreSQL + TimescaleDB. Cron tasks for periodic NAV updates via node-cron or Bull queue. Redis for caching current prices (TTL 60 sec).
Frontend: React + Recharts or TradingView Lightweight Charts for NAV graphs. Table components (TanStack Table) for portfolio breakdown.
Infrastructure: Railway / Render for MVP, AWS ECS + RDS for production with SLA. Separate service for on-chain data fetching with horizontal scaling capability.
Typical timeline: MVP with core features — 8–12 weeks. Production-ready system with access audit, full adapter set, and document handling — 4–6 months.







