ERC20PriceOracleReceiptVault._nextId() wraps priceOracle.price() in a bare try/catch and returns 0 on any revert. previewMint / mint then divide by zero in _calculateMint and surface as Panic(0x12), hiding the underlying cause (e.g. Pyth StalePrice()) from integrators, frontends, and on-chain monitoring.
No funds at risk: _deposit rejects shares==0/id==0 and _calculateMint panics before any transfer. The cost is purely diagnostic — a stale oracle is indistinguishable from a math bug.
Reproducer: cyclofinance/cyclo.sol#42 has a fork test pinning the StalePrice() (selector 0x19abf40e) → Panic(0x12) chain on Arbitrum at block 459580000 for cyWETH.PYTH. Suggested fix: rethrow on unknown selectors in the catch (or rethrow always — the ERC4626 "MUST NOT revert" requirement applies to view methods, not internal _nextId).
ERC20PriceOracleReceiptVault._nextId()wrapspriceOracle.price()in a baretry/catchand returns0on any revert.previewMint/mintthen divide by zero in_calculateMintand surface asPanic(0x12), hiding the underlying cause (e.g. PythStalePrice()) from integrators, frontends, and on-chain monitoring.No funds at risk:
_depositrejectsshares==0/id==0and_calculateMintpanics before any transfer. The cost is purely diagnostic — a stale oracle is indistinguishable from a math bug.Reproducer: cyclofinance/cyclo.sol#42 has a fork test pinning the
StalePrice()(selector0x19abf40e) →Panic(0x12)chain on Arbitrum at block 459580000 forcyWETH.PYTH. Suggested fix: rethrow on unknown selectors in the catch (or rethrow always — the ERC4626 "MUST NOT revert" requirement applies to view methods, not internal_nextId).