Vulnerability Details
When calculating twapPriceInEther
, twapPrice
is divided by 1e6 before multiplication with 1e18 is done.
function baseOracleCircuitBreaker(
uint256 protocolPrice,
uint80 roundId,
int256 chainlinkPrice,
uint256 timeStamp,
uint256 chainlinkPriceInEth
) private view returns (uint256 _protocolPrice) {
if (invalidFetchData || priceDeviation) {
uint256 twapPrice = IDiamond(payable(address(this))).estimateWETHInUSDC(
Constants.UNISWAP_WETH_BASE_AMT, 30 minutes
);
uint256 twapPriceInEther = (twapPrice / Constants.DECIMAL_USDC) * 1 ether;
https://github.com/Cyfrin/2023-09-ditto/blob/a93b4276420a092913f43169a353a6198d3c21b9/contracts/libraries/LibOracle.sol#L64-L85
According to the above calculation, the twapPrice
obtained would be precise upto 6 decimal places. Performing division before multiplying with 1e18 will result in loss of this precision and.
Example Scenario
twapPrice = 1902501929
twapPriceInEther = 1902000000000000000000
twapPriceInEther = 1902501929000000000000
Impact
Price used can have -1 (in 18 decimals) difference from the original price.
Recommendations
Perform the multiplication before division.
@@ -82,7 +82,7 @@ library LibOracle {
uint256 twapPrice = IDiamond(payable(address(this))).estimateWETHInUSDC(
Constants.UNISWAP_WETH_BASE_AMT, 30 minutes
);
- uint256 twapPriceInEther = (twapPrice / Constants.DECIMAL_USDC) * 1 ether;
+ uint256 twapPriceInEther = (twapPrice * 1 ether) / Constants.DECIMAL_USDC;
uint256 twapPriceInv = twapPriceInEther.inv();
if (twapPriceInEther == 0) {
revert Errors.InvalidTwapPrice();