Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rounding errors #1

Open
OxMarco opened this issue Jul 11, 2021 · 1 comment
Open

Rounding errors #1

OxMarco opened this issue Jul 11, 2021 · 1 comment

Comments

@OxMarco
Copy link

OxMarco commented Jul 11, 2021

Hi, thanks for sharing this code, it's something I've looking for a while as "officially" Uniswap discourage the usage of on-chain oracles. However, I see your implementation may cause problems due to how you manage roundings.
Let me share what something I have been working on so far. I tested it on Kovan and it seems to work, yet somehow I cannot get it to compile locally because Uniswap core math libraries are bugged.

function getQuote(
        address fromToken,
        address toToken,
        uint128 swapAmount // amount in fromToken to be converted
    ) external view override returns (uint256 quoteAmount, uint24 poolFee) {
        int24 timeWeightedAverageTick;
        int32 period = 600; // average over x seconds

        (address pool, uint24 _poolFee) = getCheapestPool(fromToken, toToken);
        poolFee = _poolFee; /// @dev is it really needed?

        uint32[] memory secondAgos = new uint32[](2);
        secondAgos[0] = uint32(period);
        secondAgos[1] = 0;

        (int56[] memory tickCumulatives, ) = IUniswapV3Pool(pool).observe(secondAgos);
        int56 tickCumulativesDelta = tickCumulatives[1] - tickCumulatives[0];

        timeWeightedAverageTick = int24(tickCumulativesDelta / period);

        // Always round to negative infinity
        if (tickCumulativesDelta < 0 && (tickCumulativesDelta % period != 0)) timeWeightedAverageTick--;
        
        uint160 sqrtRatioX96 = TickMath.getSqrtRatioAtTick(timeWeightedAverageTick);

        // Calculate quoteAmount with better precision if it doesn't overflow when multiplied by itself
        if (sqrtRatioX96 <= type(uint128).max) {
            uint256 ratioX192 = uint256(sqrtRatioX96) * sqrtRatioX96;
            quoteAmount = fromToken < toToken
                ? FullMath.mulDiv(ratioX192, swapAmount, 1 << 192)
                : FullMath.mulDiv(1 << 192, swapAmount, ratioX192);
        } else {
            uint256 ratioX128 = FullMath.mulDiv(sqrtRatioX96, sqrtRatioX96, 1 << 64);
            quoteAmount = fromToken < toToken
                ? FullMath.mulDiv(ratioX128, swapAmount, 1 << 128)
                : FullMath.mulDiv(1 << 128, swapAmount, ratioX128);
        }
    }
    
    // try all fee values from the most profitable (lowest, 0.03%) to the least profitable (highest, 1%)
    function getCheapestPool(address _token0, address _token1) public view override returns(address, uint24) {
        // try 0.05%
        address pool = factory.getPool(_token0, _token1, 500);
        if(pool != address(0)) return (pool, 500);

        // try 0.3%
        pool = factory.getPool(_token0, _token1, 3000);
        if(pool != address(0)) return (pool, 3000);

        // try 1%
        pool = factory.getPool(_token0, _token1, 10000);
        if(pool != address(0)) return (pool, 10000);
        else revert("Uniswap pool does not exist");
    }
@noahfigueras
Copy link
Owner

noahfigueras commented Jul 13, 2021 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants