ReceiptVault / ERC20PriceOracleReceiptVault / OffchainAssetReceiptVault generalize ERC4626 with per-id receipts, but there's no test suite that pins the spec clauses themselves. Each test file targets a single function's behaviour; nothing exercises the cross-function invariants the spec demands.
Concrete evidence the gap matters: #302's testMaxFunctionsDoNotRevertOnOracleRevert (added to assert oracle errors don't reach the MUST-NOT-revert surface) flagged maxWithdraw(owner, 0) panicking with Panic(0x12) from divide-by-zero inside _calculateRedeem. That's a direct violation of ERC4626's "MUST NOT revert" clause for max*, oracle-independent, and unaddressed today. The PR test was scoped narrowly to the oracle hypothesis (id bounded > 0) to avoid expanding scope, but the underlying defect persists.
Suggested coverage:
max* MUST NOT revert for any input (including id == 0, zero balances, paused state, broken oracle).
preview* matches the corresponding mutating call when called from the same caller with the same args under the same state.
convertToShares / convertToAssets round-trip behaviour and inverse relationship.
totalAssets consistency under deposit / withdraw / mint / redeem.
asset() immutability post-init.
- Decimals offset / rounding direction per ERC4626 spec table.
Each clause should apply to both ERC20PriceOracleReceiptVault and OffchainAssetReceiptVault, with the receipt-id dimension fuzzed.
ReceiptVault / ERC20PriceOracleReceiptVault / OffchainAssetReceiptVault generalize ERC4626 with per-id receipts, but there's no test suite that pins the spec clauses themselves. Each test file targets a single function's behaviour; nothing exercises the cross-function invariants the spec demands.
Concrete evidence the gap matters: #302's
testMaxFunctionsDoNotRevertOnOracleRevert(added to assert oracle errors don't reach the MUST-NOT-revert surface) flaggedmaxWithdraw(owner, 0)panicking withPanic(0x12)from divide-by-zero inside_calculateRedeem. That's a direct violation of ERC4626's "MUST NOT revert" clause formax*, oracle-independent, and unaddressed today. The PR test was scoped narrowly to the oracle hypothesis (idbounded> 0) to avoid expanding scope, but the underlying defect persists.Suggested coverage:
max*MUST NOT revert for any input (includingid == 0, zero balances, paused state, broken oracle).preview*matches the corresponding mutating call when called from the same caller with the same args under the same state.convertToShares/convertToAssetsround-trip behaviour and inverse relationship.totalAssetsconsistency under deposit / withdraw / mint / redeem.asset()immutability post-init.Each clause should apply to both
ERC20PriceOracleReceiptVaultandOffchainAssetReceiptVault, with the receipt-id dimension fuzzed.