The protocol expects to revert with Errors.InvalidTwapPrice() when twapPriceInEther == 0:
However, the control never reaches Line 88 when twapPriceInEther is zero. It rather reverts before that with error Division or modulo by 0.
NOTE: Due to this bug, Errors.InvalidTwapPrice() is never invoked/thrown by the protocol even under satisfactory conditions, even though it has been defined.
Since I could not find any helper function inside contracts/ or test/ which lets one set the twapPrice returned by uint256 twapPrice = IDiamond(payable(address(this))).estimateWETHInUSDC(Constants.UNISWAP_WETH_BASE_AMT, 30 minutes); to zero for testing purposes, I have created a simplified PoC which targets the problem area:
Save the following as a file named test/InvalidTwapPriceErrorCheck.t.sol and run the test via forge test --mt testInvalidTwapPriceErrNeverInvoked -vv. You will find that the test reverts with error Division or modulo by 0, but not with Errors.InvalidTwapPrice(). The PoC uses the same underlying math libraries and logic path as the protocol does in contracts/libraries/LibOracle.sol::baseOracleCircuitBreaker().
In the above test file, you can also run the test which invokes the "fixed" or "correct" code style via forge test --mt testInvalidTwapPriceErrInvokedCorrectly -vv. This will invoke the Errors.InvalidTwapPrice error, as expected.
The check on Line 87 (if condition) needs to be performed immediately after Line 85.
The above fix needed to be done because the inv() call caused a revert even before control used to reach the if condition.
Protocol owner or developer monitoring for a revert due to Errors.InvalidTwapPrice() in the logs will never see it and will make debugging & issue resolution harder.
Manual audit & foundry.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.