In Morpho Vault V2, maxRate limits how quickly recognized totalAssets can grow from the last recorded balance. The vault compares that time-based ceiling with idle assets plus adapter reports and uses the lower amount. Excess value can accrue later; reported losses below the recorded balance reduce totalAssets at accrual. The limit sets no minimum yield and does not guarantee recovery of the reported assets.
Start with the V2 accounting layer
A vault can report more underlying value than it currently recognizes for its receipt tokens. Explaining that gap requires three inputs: the last recorded asset total, time elapsed since that record, and the aggregate value reported now. Looking only at an adapter's increase misses the vault's distribution rule.
This walkthrough follows Morpho's VaultV2 reference implementation at commit a0ba9df0ea697a080c0de69c18b84738cfb3bef7, checked on 29 October 2026. The official V2 overview describes the adapter architecture. Identify a deployed vault's chain, address and code before applying this example; the reference snapshot does not identify every live implementation.
The Morpho Blue supply-shares guide explains a position inside an underlying market. Here, the question is what the V2 vault recognizes after aggregating its positions. Similarly, Yearn V3 idle and debt accounting follows a different report mechanism. Neither prior supplies V2's rate ceiling.
| Quantity | Meaning in this walkthrough | What to avoid assuming |
|---|---|---|
_totalAssets() | Cached total from the last state update | That it includes the next accrual |
Aggregate realAssets | Vault idle balance plus enabled adapters' reports | That all reported value is withdrawable cash |
maxTotalAssets | Highest total permitted by elapsed growth | That underlying positions earned this amount |
totalAssets() | Current view result after applying accrual logic | That a view call stored a new baseline |
The pinned getter calls accrueInterestView(). Thus an outside read of totalAssets() can differ from _totalAssets() without a new transaction. A view projects the calculation; a successful accrual records its result and updates lastUpdate.
Read the report before interpreting the rate
An adapter's realAssets() is a valuation function. In the named MorphoMarketV1AdapterV2 implementation, it sums expected supply assets across tracked markets, using the adapter's internally recorded supply shares. Those calculations include expected market accrual and round the asset conversion down.
That path differs from reading the adapter's token balance or adding the entire market's supply. It values this adapter's tracked positions. A different adapter needs its own inspection. Morpho's adapter setup guide identifies this adapter as the bridge from a V2 vault to Blue variable-rate markets.
The word “real” in a function name does not independently verify collectability. The report depends on its valuation logic and inputs. A report that reverts can also prevent the vault from completing accrual; the named adapter's source explicitly identifies that dependency.
Morpho's yield documentation describes the vault-level comparison. Let A be cached assets, R the current aggregate report, t elapsed seconds and r the stored maxRate integer:
- Permitted growth is
floor(A × t × r / 10^18). - The ceiling is A plus that permitted growth.
- The new recognized total is the lower of R and the ceiling.
The math library performs integer division rounded down. Run it in asset base units before formatting token decimals. An early rounded token display can move a boundary by one or more base units.
maxRate uses a 10^18 scale per second. An annual percentage needs conversion into that unit. The documented protocol maximum is expressed as 200% APR; it is a configuration bound, not a quoted return. A single interval grows linearly from its recorded baseline. Subsequent successful accruals can change that baseline, so an annualized parameter alone does not specify realized compounded APY.
Reproduce the exact second that releases a surplus
This is a hypothetical accounting fixture, using fictional token U with six decimals. Amounts in the tables are displayed U, without an assumed dollar value. Both vault fees are zero. There are no deposits, withdrawals, penalties, share burns or other changes during each branch. Adapters function correctly and report the stipulated amounts.
At time T, cached assets equal 10,000 U and lastUpdate equals T. The vault holds 1,000 U idle. Its adapter now reports 9,012 U, making R equal 10,012 U. These extra 12 U are already present in the aggregate reported value, but have not been recognized in the cache.
The illustrative rate integer is 10,000,000,000. Dividing by 10^18 gives 0.00000001 per second. Multiplying that by 31,536,000 seconds gives the simple annualized convention of 31.536%. This invented input is chosen for transparent arithmetic.
First, assume no state-changing accrual after T. Perform separate view observations with the aggregate report fixed at 10,012 U:
| Seconds after T | Growth ceiling in U | Projected totalAssets in U |
|---|---|---|
| 119,999 | 10,011.999900 | 10,011.999900 |
| 120,000 | 10,012.000000 | 10,012.000000 |
| 120,001 | 10,012.000100 | 10,012.000000 |
At 119,999 seconds, the raw growth numerator is 10,000,000,000 × 119,999 × 10,000,000,000. Dividing by 10^18 and rounding down gives 11,999,900 base units.
That is 11.999900 U. Exactly 100 raw units, or 0.000100 U, remain outside the recognized total. One second later, the ceiling reaches the full 12 U surplus. Another second adds no recognized value because the aggregate report stays at 10,012 U.
None of these reads resets the clock. Each uses cached A of 10,000 U and the original T. Treating each read as a new accrual would understate the elapsed interval.
Actual accrual timing can matter. With R instead held at 10,020 U, one successful accrual after 120,000 seconds recognizes 10,012 U. Two accruals 60,000 seconds apart recognize 10,006 U and then 10,012.003600 U. The second interval applies its rate to 10,006. Both paths respect their interval formulas. They do not prove a fixed annual payout.
Follow a declining report through the buffer
Now take an alternative branch from T, independent of the three view observations. Execute a successful accrual after 60,000 seconds. It records 10,006 U against reported assets of 10,012 U. The difference is a 6 U accounting buffer.
Later reports decline. Each row below is a separate successful accrual transaction, with the preceding row's result becoming the next cached total and timestamp. After a successful accrual sets transient firstTotalAssets to a nonzero amount, later calls in that transaction reuse the recorded total. All totals in this fixture are nonzero.
| Time after T | Aggregate report R | Growth ceiling | Recorded total |
|---|---|---|---|
| 60,000 seconds | 10,012.000000 | 10,006.000000 | 10,006.000000 |
| 60,100 seconds | 10,008.000000 | 10,006.010006 | 10,006.010006 |
| 60,200 seconds | 10,000.000000 | 10,006.020012 | 10,000.000000 |
Between the first two rows, reported value falls by 4 U. Yet recognized assets rise by 0.010006 U. The remaining report still exceeds the ceiling, so the prior surplus absorbs the reported decline while a small amount continues to accrue. The remaining gap becomes 10,008 − 10,006.010006 = 1.989994 U.
At the final row, R is below the previously recorded 10,006.010006 U. The vault records 10,000 U, recognizing a loss of 6.010006 U from that previous record. The upward ceiling supplies no floor against this loss.
Calling the buffer “insurance” would misdescribe this fixture. Its size depends on reported values that can change. It is already part of the vault's reported positions, rather than a separately guaranteed recovery fund. If a report overstates recoverable value, the gap also overstates the economic cushion.
A zero rate still permits recorded losses
The roles reference assigns setMaxRate to an Allocator. The emergency guide identifies setting it to zero as an action without a timelock. A Sentinel's separate deallocation powers do not automatically grant this setter; inspect actual role membership. The Curator, Allocator and Sentinel guide follows those authorities.
Changing the setting first accrues the preceding interval under the old rate. The new value then applies going forward, as the yield documentation explains. A zero setting cannot retroactively remove growth recognized by that preceding accrual.
Continue from cached assets of 10,000 U after the loss branch. Assume a later setter call accrues with R still at 10,000 U, then sets r to zero. After another 86,400 seconds, a report of 10,020 U still yields recognized assets of 10,000 U. If a subsequent report drops to 9,990 U, the next accrual recognizes 9,990 U. Time passing under a zero rate does not distribute the 20 U surplus, while the loss remains recognizable.
The setting governs the whole vault's growth calculation. It does not select one market's losses for exclusion or constrain rewards paid separately outside the vault.
Validate the total, the fee shares and the exit separately
The fixture deliberately removes fees to isolate the asset boundary. In an actual vault, fee collection mints vault shares. The pinned calculation bases performance fees on positive recognized interest; management fees can apply during a loss interval. A net depositor conversion therefore needs the projected fee shares as well as new assets. The V2 fee-shares reconciliation develops that next step.
For a reproducible observation, use one block reference and retain:
- The vault address, code identity, underlying token and decimals, cached
_totalAssets,lastUpdateandmaxRate. - The vault's idle token balance, every enabled adapter address and each
realAssets()result, including any failed call. - The floored growth ceiling, aggregate report, their minimum, and all three
accrueInterestView()outputs. - Any intervening cash flows, state-changing accruals, fee settings or rate changes before comparing snapshots.
A failed report is a failed calculation, not evidence of zero assets. Preserve the failure and investigate the adapter instead of silently omitting it from the sum.
Finally, apply Morpho's liquidity routing distinction: a withdrawal first uses idle assets and can require the designated liquidity adapter. A report values positions; it does not establish how much those positions can return now. Check the intended exit's routing, gates and simulation. In this reference implementation, the ERC-4626 maximum functions return zero, so maxWithdraw() alone cannot serve as an available-liquidity measurement.
For the loss branch, the reproducible record ends with 10,000 U recognized and 10,000 U reported. Keep the independently checked withdrawal capacity beside those figures. That record explains both the completed accounting loss and the evidence still needed before an exit.
