Accounting

MORE Vaults separates position logic from asset accounting. Each strategy facet owns its own storage and position-management code, while the invariant core is the single source of truth for the vault’s totalAssets. This design keeps upgrades local to the facet that changes, yet guarantees that every share is always backed 1 : 1 by on‑chain‑verifiable value.

Available Assets

A vault can end up holding many different tokens beyond its deposit list including LP shares, yield tokens, debt receipts, even bridged assets on another chain. These tokens encompass anything that may appear in availableAssets() and therefore in totalAssets.

For each available asset the strategist must ensure two things:

  1. Valuation path – An oracle, TWAP, or deterministic formula can convert the asset to the accounting unit at any time.

  2. Registry entry – The oracle contract is published in an Oracle Registry or the pricing method is included in facet accounting so auditors and dashboards can trace the number.

If either requirement is missing, the asset will be excluded from its valuation and impact total asset accounting and share price.

Deposit Tokens

Before a vault goes live, the strategist whitelists a set of deposit tokens: the ERC-20s users are allowed to send when calling deposit(). The list can be contain a single token (e.g. USDC) or multiple tokens (ETH, stETH, USDC). Each token must have a reliable oracle listed in an Oracle Registry so the core can convert incoming amounts into the accounting asset. If a user tries to deposit a token that is not whitelisted, the transaction reverts. Smaller sets reduce oracle risk, keep gas costs down, and simplify price charts.

Per-Facet Tracking

Accounting logic is dependent on the accounting of the protocol with which the facet interacts. In this way, accounting is inherited from each protocol and compiled independently from other facets so that it can be subsequently composed into the vault's NAV.

Facets expose a unique accounting selector that returns their current valuation in the vault’s accounting asset. There are no cross‑facet calls.

Some facets contain a hook that executes before accounting in order to include tokens or yield that is not exposed through the underlying protocol's native accounting functions. Tokens that are not included in the native NAV calculation do not reflect in the share price provided by front-ends unless a deposit or withdrawal action is initiated.

Valuation must be deterministic at deposit and withdrawal time. If pricing depends on a DEX TWAP or Chainlink round, the facet fetches and converts it internally.

totalAssets = Σ facetAssets() + spotBalance

Every action on a vault updates the NAV calculation, with updates occurring at most once per block.

If a facet reverts or oracle is stale, operations will be reverted and vault governance can then inspect, replace, or pause the offending module without halting withdrawals.

Valuation Sources

Source Type
When Used
Guardrails

Spot balance

Simple ERC‑20 or native token positions

Priced via Pyth, Chainlink, Redstone, etc. oracle; revert if price feed is older than MAX_DELAY.

DEX LP positions

Uniswap V3, Balancer, Curve

Use an in‑facet math lib to value assets at pool’s virtual price; sanity‑check against on‑chain oracles.

Lending protocol deposits

Aave v3, Compound v3

Read getUserAccountData.

Yield‑bearing tokens

LRT, wstETH, PT-sUSDe, etc.

Pull exchangeRate() directly on-chain from protocol and multiply by holding balance.

Facets must convert their asset values into the vault’s single accounting asset using at most one intermediate oracle call to prevent gas‑bomb loops.

Fee Accrual

Management and performance fees are applied inside deposit() and redeem() in the VaultFacet before the NAV snapshot is finalised. When the fee is skimmed, new shares are minted to the fee recipient.

This keeps fee accounting transparent. Fees show up as an explicit delta rather than hidden dilution.

Last updated