Learn

NAV & price-per-portfolio token

NAV (Net Asset Value) is the total value of everything a portfolio holds. Price-per-portfolio token is that value divided by the number of portfolio tokens. Together they tell you what a portfolio token is worth — but, importantly, they are used only for display and pricing, never to gate your ability to deposit or withdraw.

How NAV is computed

For each constituent the portfolio holds, it multiplies the amount held by that token's price, then sums across all constituents:

NAV (USD, 1e18-scaled) = Σ_i  trackedBalance_i × price_i / 10^decimals_i
  • trackedBalance_i — the vault's internal accounting of how much of token i it holds.
  • price_i — the token's USD price from its Chainlink feed, normalized to 18 decimals by OracleLib.
  • decimals_i — the token's own decimals (so a 6-decimal token and an 18-decimal token are compared fairly).

This is exactly what the nav() view function returns.

Price-per-portfolio token

price-per-portfolio-token = NAV / totalSupply

At creation, a portfolio is seeded so that its first portfolio token is worth roughly the creator's chosen seed size (e.g. ~$25). From then on, price-per-portfolio token moves with the prices of the underlying stocks — up when they rise, down when they fall — plus the slow drag of the management fee.

Why NAV never gates mint or redeem

This is the most important property to understand:

  • In-kind mint and redeem are pro-rata on real balances. When you deposit or withdraw in-kind, the vault just gives or takes tokens in proportion to trackedBalance and your proportion of the supply. No price is consulted.
  • NAV is only used for: showing you the value, pricing one-click zaps, and accounting for fees.

So if a price feed goes stale or breaks, the portfolio's displayed NAV may be flagged stale and even understated — but you can still redeem your exact proportional slice of the underlying. Your exit is never blocked by an oracle.

Staleness and the stale flag

OracleLib reads each feed behind two guards — a staleness limit (the price must be recent enough) and a sequencer-uptime check (the L2 sequencer must have been up long enough). If anything is wrong, it returns stale = true instead of reverting.

  • If any constituent's price is stale, the portfolio's nav() sets its overall stale flag, and that leg contributes 0 to the sum.
  • The app marks stale NAV clearly (with a timestamp) everywhere it appears, and disables one-click zaps that would price off a stale feed — while still offering in-kind flows.

Returns

The backend snapshots NAV over time and computes each portfolio's return over rolling windows (24h, 7d, 30d) and since inception, which power the leaderboard and the return figures on each portfolio. A brand-new portfolio shows — for a window until enough history exists (e.g. a 30-day return needs 30 days of snapshots).

For developers

NAV-related fields are represented as raw 1e18 integer strings — divide by 1e18 to display. This includes navUsd, navPerShare, shareSupply, inceptionNavPs, and per-constituent valueUsd. See the wire-format note in Core concepts.