Shaggy Lava Mustang
Medium
Since the oracle reporting format is ${raw price} * 1e(36 - feedDecimals - underlyingAssetDecimals)
, the precision decreases up to zero as the underlying asset decimals approach 36
.
As stated in the contest README, the protocol is expected to operate with tokens up to 36 decimals:
Tokens are expected to have a maximum of 36 decimal places for precision oracle price reasons
https://audits.sherlock.xyz/contests/727
However, such tokens may lead to severely truncated price reports and even transaction reverts in edge cases.
To illustrate the root cause better, let's examine price scaling logic from API3Oracle.sol:
function getPrice(address token) external view returns (uint256 price, bool isValid) {
uint256 price = _getLatestPrice(token);
uint256 decimals = _getDecimals(token);
uint256 scaledPrice;
// Price from API3 is always multiplied by 1e18 base
if (API3_SCALE_FACTOR + decimals <= PRICE_SCALE) {
uint256 scale = 10 ** (PRICE_SCALE - API3_SCALE_FACTOR - decimals);
scaledPrice = price * scale;
} else {
uint256 scale = 10 ** (API3_SCALE_FACTOR + decimals - PRICE_SCALE);
scaledPrice = price / scale;
}
if (scaledPrice == 0) {
return (0, false);
}
return (scaledPrice, true);
}
When decimals
is higher than 18, the else
block is executed. Let's see what will be an outcome for the case of the underlying token to have maximum (36) decimals:
scale (decimals) = 18 + underlying decimals (36) - PRICE_SCALE (36) = 18 scaledPrice decimals = price decimals (18) - scale (18) = 0
Thus, the resulting price will be a plain integer value without any fractional part. This significantly reduces the price accuracy and will result in a value of 0 when an asset is priced for less than 1 USD. Consequently, any calculations based on this price will lead to transaction reversals.
It is worth noting that:
- The same problem exists for PythOracle as well.
- The impact is not limited to tokens with 36 decimals and may affect tokens with lower decimals. For example, for tokens with 24 decimals, the price precision will only have 12 decimals.
- Reduced accuracy may open the door to price-based manipulations and funds lost to arbitrage bots.
- A possible DoS state of the markets where the underlying asset is priced for less than 1 USD.
To increase the base of the 36
decimals for Oracle reporting. Alternatively, limit the maximum number of decimals for supported tokens to 18 only.