Assessment reports>Ionic Protocol>Medium findings>Unexpected reverts where overflow may be desireable
Category: Business Logic

Unexpected reverts where overflow may be desireable

Medium Severity
High Impact
High Likelihood


The UniswapTwapPriceOracleV2 is a modified version of the Compound UniswapTwapPriceOracleV2 contract. The Compound contract used Open Zeppelin's SafeMathUpgradeable to check for arithmetic overflow and underflow issues.

Ionic Protocol removed SafeMathUpgradeable and modified the Compound contracts to compile with solidity versions >=0.8.0 which by default includes checked arithmetic to revert on overflows and underflows.

The UniswapTwapPriceOracleV2 imports UniswapTwapPriceOracleV2Root which has also been modified to replace the SafeMathUpgradeable functionality with solidity 0.8.0+ default checked arithmetic. However, in UniswapTwapPriceOracleV2Root there are portions of code related to price accumulation (currentPx0Cumu, currentPx1Cumu) and time weighted average price (price0TWAP, price1TWAP) where arithmetic overflow is desirable. For further reading see Dapp's audit report of Uniswap v2.

This issue was duplicated with a parallel, internal review of the code conducted by Ionic Protocol.


When calling getUnderlyingPrice, an overflow in either currentPx0Cumu or currentPx1Cumu would lead to an unexpected transaction reversion, rendering the oracle useless.


Review all contracts in the codebase which were updated to compile with solidity 0.8.0+ and place unchecked blocks around code where overflow is desireable. This will allow values to wrap on overflows and underflows as expected in versions of solidity prior to 0.8.0.

Below is an example of corrected code for currentPx0Cumu in UniswapTwapPriceOracleV2Root:

function currentPx0Cumu(address pair) internal view returns (uint256 px0Cumu) {
  uint32 currTime = uint32(block.timestamp);
  px0Cumu = IUniswapV2Pair(pair).price0CumulativeLast();
  (uint256 reserve0, uint256 reserve1, uint32 lastTime) = IUniswapV2Pair(pair).getReserves();
  if (lastTime != block.timestamp) {
-    uint32 timeElapsed = currTime - lastTime; // overflow is desired
-    px0Cumu += uint256((reserve1 << 112) / reserve0) * timeElapsed; 
+    unchecked {
+      uint32 timeElapsed = currTime - lastTime; // overflow is desired
+      px0Cumu += uint256((reserve1 << 112) / reserve0) * timeElapsed;
+    }


The issue has been fixed by Ionic Protocol in commit a562fda.

Zellic © 2023Back to top ↑