Пример #1
0
    def _ratios_after_slippage(self, slippage_tolerance: Fraction) -> Tuple:
        assert isinstance(slippage_tolerance, Fraction)
        assert (1 > slippage_tolerance.float_quotient() > 0)

        price_lower_slippage_factor = Fraction(1).subtract(slippage_tolerance)
        price_upper_slippage_factor = slippage_tolerance.add(Fraction(1))
        pool_token_0_price_fraction = self.pool.get_token_0_price(
        ).as_fraction()
        price_lower = pool_token_0_price_fraction.multiply(
            price_lower_slippage_factor)
        price_upper = pool_token_0_price_fraction.multiply(
            price_upper_slippage_factor)

        sqrtRatioX96Lower = encodeSqrtRatioX96(price_lower.numerator,
                                               price_lower.denominator)

        if sqrtRatioX96Lower < MIN_SQRT_RATIO:
            sqrtRatioX96Lower = MIN_SQRT_RATIO + 1

        sqrtRatioX96Upper = encodeSqrtRatioX96(price_upper.numerator,
                                               price_upper.denominator)

        if sqrtRatioX96Upper > MAX_SQRT_RATIO:
            sqrtRatioX96Upper = MAX_SQRT_RATIO - 1

        return (sqrtRatioX96Lower, sqrtRatioX96Upper)
Пример #2
0
    def get_tick_at_price(price) -> int:
        """ returns the first tick whose price is greater than or equal to the input tick price """
        assert isinstance(price, PriceFraction)

        sorted = int(price.base_token.address.address, 16) < int(
            price.quote_token.address.address, 16)

        sqrt_ratio_x96 = encodeSqrtRatioX96(
            price.numerator,
            price.denominator) if sorted else encodeSqrtRatioX96(
                price.denominator, price.numerator)

        tick = get_tick_at_sqrt_ratio(sqrt_ratio_x96)

        next_tick_price = PriceFraction.get_price_at_tick(
            price.base_token, price.quote_token, tick + 1)

        if sorted:
            if not price.less_than(next_tick_price):
                tick += 1
        else:
            if not price.greater_than(next_tick_price):
                tick += 1

        return tick
Пример #3
0
def test_get_tick_at_sqrt_ratio():
    calculated_sqrt_price_ratio = encodeSqrtRatioX96(1, 1900)
    sqrt_price_ratio_expected = 1817618704642608503278368873

    assert calculated_sqrt_price_ratio == sqrt_price_ratio_expected

    tick = get_tick_at_sqrt_ratio(calculated_sqrt_price_ratio)

    assert tick == -75500
    assert get_tick_at_sqrt_ratio(MIN_SQRT_RATIO) == MIN_TICK
    assert get_tick_at_sqrt_ratio(MAX_SQRT_RATIO - 1) == MAX_TICK - 1
Пример #4
0
 def get_starting_sqrt_ratio(self, amount_0, amount_1) -> int:
     return encodeSqrtRatioX96(amount_1, amount_0)
Пример #5
0
    def test_should_mint_with_nonstandard_decimals(self):
        """ mint a position with one of the tokens having nonstandard decimals.
            Verify that the positions price and minted amounts accounts for decimals.
        """
        test_token_1 = Token(
            "test_1", Address("0x0000000000000000000000000000000000000001"),
            18)
        test_token_2 = Token(
            "test_2", Address("0x0000000000000000000000000000000000000002"), 6)

        # instantiate test pool
        # sqrt_price_ratio = self.get_starting_sqrt_ratio(Wad.from_number(1).value, Wad.from_number(3500).value)
        sqrt_price_ratio = self.get_starting_sqrt_ratio(1, 3500)
        current_tick = get_tick_at_sqrt_ratio(sqrt_price_ratio)
        ticks = []
        test_pool = Pool(test_token_1, test_token_2, FEES.MEDIUM.value,
                         sqrt_price_ratio, 0, current_tick, ticks)

        # based upon current price (expressed in token1/token0), determine the tick to mint the position at
        tick_spacing = TICK_SPACING.MEDIUM.value
        desired_price = PriceFraction(test_token_1, test_token_2, 1, 3500)
        desired_tick = PriceFraction.get_tick_at_price(desired_price)

        # identify upper and lower tick bounds for the position
        desired_lower_tick = Tick.nearest_usable_tick(
            desired_tick - tick_spacing * 5, tick_spacing)
        desired_upper_tick = Tick.nearest_usable_tick(
            desired_tick + tick_spacing * 7, tick_spacing)

        # calculate amount to add for each position.
        ## since test_token_2 has 6 decimals, we must unnormalize the Wad amount from 18 -> 6
        token_1_balance = Wad.from_number(10)
        token_2_balance = Wad.from_number(100)

        token_1_to_add = test_token_1.unnormalize_amount(token_1_balance).value
        token_2_to_add = test_token_2.unnormalize_amount(token_2_balance).value
        # token_1_to_add = token_1_balance.value
        # token_2_to_add = token_2_balance.value

        calculated_position = Position.from_amounts(test_pool,
                                                    desired_lower_tick,
                                                    desired_upper_tick,
                                                    token_1_to_add,
                                                    token_2_to_add, False)

        amount_0, amount_1 = calculated_position.mint_amounts()

        slippage_tolerance = Fraction(2, 100)
        amount_0_min, amount_1_min = calculated_position.mint_amounts_with_slippage(
            slippage_tolerance)

        # check that mint amounts will pass periphery contract assertions
        assert amount_0 > 0 and amount_1 > 0
        assert amount_0_min > 0 and amount_1_min > 0
        assert amount_0_min < amount_0 and amount_1_min < amount_1

        # assume pool.tick_current < desired_upper_tick
        expected_amount_0 = SqrtPriceMath.get_amount_0_delta(
            test_pool.square_root_ratio_x96,
            get_sqrt_ratio_at_tick(desired_upper_tick),
            calculated_position.liquidity, True)
        expected_amount_1 = SqrtPriceMath.get_amount_1_delta(
            get_sqrt_ratio_at_tick(desired_lower_tick),
            test_pool.square_root_ratio_x96, calculated_position.liquidity,
            True)

        assert amount_0 == expected_amount_0
        assert amount_1 == expected_amount_1

        # get amounts from liquidity
        price_lower_tick = pow(1.0001, calculated_position.tick_lower)
        price_upper_tick = pow(1.0001, calculated_position.tick_upper)

        assert price_lower_tick < 3500 < price_upper_tick

        position_token_0 = calculated_position.liquidity / math.sqrt(
            price_upper_tick)
        position_token_1 = calculated_position.liquidity * math.sqrt(
            price_lower_tick)

        # compare original sqrt_price_ratio_x96 to the ratio determined by liquidity to mint
        assert str(sqrt_price_ratio)[:2] == str(
            encodeSqrtRatioX96(int(position_token_1),
                               int(position_token_0)))[:2]
        assert sqrt_price_ratio // Q96 == encodeSqrtRatioX96(
            int(position_token_1), int(position_token_0)) // (2**96)
Пример #6
0
def test_encode_srt_ratio():
    assert encodeSqrtRatioX96(1, 1) == Q96
    assert encodeSqrtRatioX96(100, 1) == 792281625142643375935439503360
    assert encodeSqrtRatioX96(1, 100) == 7922816251426433759354395033
    assert encodeSqrtRatioX96(111, 333) == 45742400955009932534161870629
    assert encodeSqrtRatioX96(333, 111) == 137227202865029797602485611888