Skip to content

Latest commit

 

History

History
74 lines (45 loc) · 2.92 KB

File metadata and controls

74 lines (45 loc) · 2.92 KB

Shaggy Lava Mustang

Medium

Tokens with high decimals may cause precision loss and reverts

Summary

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.

Vulnerability Detail

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.

Impact

  • 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.

Code Snippet

https://github.com/sherlock-audit/2024-12-mach-finance/blob/main/contracts/src/Oracles/API3/API3Oracle.sol#L50-L51

https://github.com/sherlock-audit/2024-12-mach-finance/blob/main/contracts/src/Oracles/Pyth/PythOracle.sol#L82-L83

Recommendation

To increase the base of the 36 decimals for Oracle reporting. Alternatively, limit the maximum number of decimals for supported tokens to 18 only.