ERC4626SharePriceAssertion
Inherits: ERC4626BaseAssertion
Title: ERC4626SharePriceAssertion
Author: Phylax Systems
Asserts that the vault’s share price (totalAssets / totalSupply) does not decrease beyond a configurable tolerance, both transaction-wide and per individual user operation. Invariants covered:
- Non-dilutive entry/exit: absent explicit fee accrual or loss recognition, deposit/mint/withdraw/redeem must not reduce assets-per-share for remaining holders.
- Rounding favors incumbents: the share price must not move against the vault (i.e., existing holders) during ordinary user operations.
Uses the V2 assetsMatchSharePrice / assetsMatchSharePriceAt precompiles for the
primary check, and ratioGe for an explicit cross-multiplication comparison as a
second, readable signal.
The tolerance is expressed in basis points (1 bps = 0.01%).
A tolerance of 0 enforces strict non-decrease; values like 25-50 allow for rounding noise.
Constants
sharePriceToleranceBps
Maximum acceptable share-price decrease in basis points.
uint256 public immutable sharePriceToleranceBps
Functions
constructor
constructor(uint256 _toleranceBps) ;
_registerSharePriceTriggers
Register the default trigger set for share-price invariants.
Uses registerTxEndTrigger for the tx-wide envelope and registerFnCallTrigger
for per-call checks. Call this inside your triggers().
function _registerSharePriceTriggers() internal view;
assertSharePriceEnvelope
Verifies the share price did not decrease beyond tolerance across the entire transaction.
Uses assetsMatchSharePrice for a comprehensive all-forks check, then ratioGe for an explicit pre/post comparison as a second signal.
function assertSharePriceEnvelope() external;
assertPerCallSharePrice
Verifies each individual deposit/mint/withdraw/redeem call does not decrease the share price beyond tolerance.
Uses ph.context() to get the triggering call boundaries and assetsMatchSharePriceAt for a targeted pre/post-call comparison.
function assertPerCallSharePrice() external;