Onchain Accounting
Verifiable, manipulation-resistant NAV for each fund — composed from onchain balances and prices in one contract per chain.
KPK's onchain accounting system produces a verifiable, manipulation-resistant Net Asset Value (NAV) for each fund by composing three layers of onchain infrastructure into a single contract — the NAV Calculator — deployed once per chain.
Each fund's NAV is computed independently on every chain where it operates, then aggregated offchain into a single global figure. Every computation input — balances and prices — is read from onchain sources and is independently verifiable.
How it fits together
The NAV Calculator inherits two libraries of behaviour — Balances and Prices — and combines them into the NAV layer.
Balance layer
For each tracked asset, the NAV Calculator collects the account's holdings from a set of registered balance adapters. A built-in ERC20DefaultAdapter reports plain wallet balances; protocol adapters report positions that are not visible as a simple balanceOf (Morpho supply shares, Aave aTokens, staked LP, reward accruals, …). Each adapter returns balance-only PositionBalance entries tagged with a machine-readable identity (the protocolBrand/protocolId/protocolSubId taxonomy, positionId, positionKind, isLocked).
Price layer
Each balance is priced by the asset's single primary price feed (Chainlink, Redstone, API3, or a custom composite adapter). Any additional trustworthy source is a monitor feed, read only to check the primary for divergence — never to price NAV. If the primary is stale, the asset is added to NAV.stalePriceAssets and the reading is flagged unreliable; if the primary diverges from a monitor (or, for stablecoins, strays from $1) beyond tolerance, the asset is added to NAV.irregularPriceAssets as a soft alert. If monitors are configured but none of them was readable, the divergence check could not run at all, and the asset is added to NAV.monitorsUnhealthyPriceAssets — so a clean irregular flag is never mistaken for a check that actually happened.
Aggregation layer
On each chain, the NAV Calculator prices every position and sums them into a chain-local NAV (int256, in the quote asset's decimals — 8 for USD). Debt positions subtract. The offchain NAV Worker collects per-chain values and sums them into the global NAV used for subscriptions and redemptions.
Architecture
A single
NAVCalculatoris deployed per chain as a UUPS proxy at a canonical CREATE2 address (identical across chains). It is fund-agnostic — one instance prices any account on that chain.It inherits the
PricesandBalancesregistries, and delegates heavy registry mutations and read loops to external libraries (NAVRegistryLib,PriceFeedLib) to stay under the EIP-170 contract-size limit.Human-readable labels come from the NAV Calculator's own verbose read methods (
getAccountNavVerbose/getAccountPositionsVerbose) — the label-enrichment path is inlined into the contract rather than split into a separate lens. There is no standalone lens contract.Chains where the funds hold positions: Ethereum, Optimism, Arbitrum, Base, Gnosis — the NAV is also live (canonical layer only) on 19 more chains. See Deployment addresses.
License: the contracts are released under BUSL-1.1 (licensor KPK; converts to GPL-2.0-or-later on 2030-07-01), with a GPL-2.0-or-later exception for the bundled Uniswap V3 math libraries.
Key contracts
NAV Calculator
NAVCalculator (UUPS proxy)
Registers assets, feeds, and adapters; prices balances; returns chain NAV and positions, plus labelled *Verbose reads for dashboards
Default adapter
ERC20DefaultAdapter
Reports plain wallet balances for every registered ERC-20 + the native token
Balance adapter
Various (plain & meta)
Report protocol positions as balance-only PositionBalance entries
Price feed
Chainlink / Redstone / API3 / custom
Return a price and staleness signal per asset
Explore the section
Last updated