Skip to content

Latest commit

 

History

History
52 lines (33 loc) · 2.31 KB

091.md

File metadata and controls

52 lines (33 loc) · 2.31 KB

Prehistoric Cobalt Aphid

Medium

Price precision in the Strategy is insufficient for pairs that have different decimals and values

Summary

The price in the strategy is scaled from the square root as: FullMath.mulDiv(sqrtPriceX96, 1e15, 2 ** 96) ** 2; The issue is that it does not take into account the decimals of the underlying tokens, which means that the precision of 1e30 is not enough for certain pairs, as proved in the POC. If a token worth 1e-5 USD with 18 decimals is coupled with WBTC (or similar), the sqrtPrice will be very small and 1e15 precision is not enough. The sqrtPriceX96 should always be scaled by the decimal difference before dividing by 2**96 to preserve precision.

Root Cause

In Strategy:128 price and TWAP price have precision loss.

Internal Pre-conditions

None.

External Pre-conditions

Token with 18 decimals and low price is coupled with WBTC.

Attack Path

  1. Price is calculated for the mentioned token pair suffering significant precision loss, leading to 1-100 BIPS losses.

Impact

The protocol will use incorrect prices allowing users to do arbitrage in the Leverager and manipulate it.

PoC

The following test shows a 0.2 BIPS precision loss on the price with a token that is worth 1e-5 USD and WBTC.

    function test_POC_price_precision() public {
        uint256 sqrtPrice = 7922816211812353000; // sqrt((1e8-1)*2**96*2**96 / (1e10*e18)). This token is worth 10^-5 USD
        uint256 price = (FullMath.mulDiv(sqrtPrice, 1e15, 2 ** 96) ** 2);
        assertEq(price, 9999800001);
        uint256 correctPrice = uint256(1e8-1)*1e30/(1e10*1e18);
        assertEq(correctPrice, 9999999900); // error is 0.2 BIPS

        uint256 decimalsAdjustedPrice = (FullMath.mulDiv(sqrtPrice, 1e20, 2 ** 96) ** 2); // add 1e5 precision to sqrt to account for decimal diff
        assertEq(decimalsAdjustedPrice, 99999999000000002500);
        assertEq(uint256(1e8-1)*1e40/(1e10*1e18), 99999999000000000000);  // error is 0
    }

Mitigation

Scale the price by the decimal difference before dividing by 2**96. The POC above shows that the error is reduced to almost 0.