Module orca_whirlpool.internal.utils.liquidity_math

Expand source code
import math
from decimal import Decimal
from ..types.types import TokenAmounts
from ..invariant import invariant


class LiquidityMath:
    # https://orca-so.github.io/whirlpools/classes/PoolUtil.html#getTokenAmountsFromLiquidity
    # https://github.com/orca-so/whirlpools/blob/7b9ec35/sdk/src/utils/public/pool-utils.ts#L84
    @staticmethod
    def get_token_amounts_from_liquidity(
        liquidity: int,
        sqrt_price_x64_current: int,
        sqrt_price_x64_lower: int,
        sqrt_price_x64_upper: int,
        round_up: bool
    ) -> TokenAmounts:
        invariant(sqrt_price_x64_lower < sqrt_price_x64_upper, "sqrt_price_x64_lower < sqrt_price_x64_upper")

        liq = Decimal(liquidity)
        lower = Decimal(sqrt_price_x64_lower)
        upper = Decimal(sqrt_price_x64_upper)
        current = min(max(Decimal(sqrt_price_x64_current), lower), upper)  # bounded

        shift_64 = Decimal(2)**64
        token_a = liq * shift_64 * (upper - current) / (current * upper)
        token_b = liq * (current - lower) / shift_64

        if round_up:
            return TokenAmounts(math.ceil(token_a), math.ceil(token_b))
        else:
            return TokenAmounts(math.floor(token_a), math.floor(token_b))

    @staticmethod
    def get_token_a_from_liquidity(
        liquidity: int,
        sqrt_price_x64_0: int,
        sqrt_price_x64_1: int,
        round_up: bool
    ) -> int:
        small_sqrt_price_x64 = min(sqrt_price_x64_0, sqrt_price_x64_1)
        large_sqrt_price_x64 = max(sqrt_price_x64_0, sqrt_price_x64_1)
        if small_sqrt_price_x64 == large_sqrt_price_x64:
            return 0

        return LiquidityMath.get_token_amounts_from_liquidity(
            liquidity,
            small_sqrt_price_x64,
            small_sqrt_price_x64,
            large_sqrt_price_x64,
            round_up
        ).token_a

    @staticmethod
    def get_token_b_from_liquidity(
            liquidity: int,
            sqrt_price_x64_0: int,
            sqrt_price_x64_1: int,
            round_up: bool
    ) -> int:
        small_sqrt_price_x64 = min(sqrt_price_x64_0, sqrt_price_x64_1)
        large_sqrt_price_x64 = max(sqrt_price_x64_0, sqrt_price_x64_1)
        if small_sqrt_price_x64 == large_sqrt_price_x64:
            return 0

        return LiquidityMath.get_token_amounts_from_liquidity(
            liquidity,
            large_sqrt_price_x64,
            small_sqrt_price_x64,
            large_sqrt_price_x64,
            round_up
        ).token_b

    # https://github.com/orca-so/whirlpools/blob/7b9ec35/sdk/src/utils/public/pool-utils.ts#L237
    @staticmethod
    def get_liquidity_from_token_a(sqrt_price_x64_0: int, sqrt_price_x64_1: int, amount: int) -> int:
        small_sqrt_price_x64 = min(sqrt_price_x64_0, sqrt_price_x64_1)
        large_sqrt_price_x64 = max(sqrt_price_x64_0, sqrt_price_x64_1)
        if small_sqrt_price_x64 == large_sqrt_price_x64:
            return 0

        # a = L/small_sqrt_price_x64/x64 - L/large_sqrt_price_x64/x64
        # a = L * x64 * ( 1/small_sqrt_price_x64 - 1/large_sqrt_price_x64 )
        # a = L * x64 * ((large_sqrt_price_x64 - small_sqrt_price_x64) / (small_sqrt_price_x64 * large_sqrt_price_x64))
        # L = a / x64 / ((large_sqrt_price_x64 - small_sqrt_price_x64) / (small_sqrt_price_x64 * large_sqrt_price_x64))
        # L = a * (small_sqrt_price_x64 * large_sqrt_price_x64) / (x64 * (large_sqrt_price_x64 - small_sqrt_price_x64))
        shift_64 = 2**64
        num = amount * (small_sqrt_price_x64 * large_sqrt_price_x64)
        denom = shift_64 * (large_sqrt_price_x64 - small_sqrt_price_x64)
        return num // denom

    # https://github.com/orca-so/whirlpools/blob/7b9ec35/sdk/src/utils/public/pool-utils.ts#L248
    @staticmethod
    def get_liquidity_from_token_b(sqrt_price_x64_0: int, sqrt_price_x64_1: int, amount: int) -> int:
        small_sqrt_price_x64 = min(sqrt_price_x64_0, sqrt_price_x64_1)
        large_sqrt_price_x64 = max(sqrt_price_x64_0, sqrt_price_x64_1)
        if small_sqrt_price_x64 == large_sqrt_price_x64:
            return 0

        # b = L*large_sqrt_price_x64/x64 - L*small_sqrt_sqrt_price_x64/x64
        # L = b / ( large_sqrt_price_x64/x64 - small_sqrt_sqrt_price_x64/x64 )
        # L = b * x64 / ( large_sqrt_price_x64 - small_sqrt_price_x64 )
        shift_64 = 2**64
        num = amount * shift_64
        denom = large_sqrt_price_x64 - small_sqrt_price_x64
        return num // denom

    # https://orca-so.github.io/whirlpools/classes/PoolUtil.html#estimateLiquidityFromTokenAmounts
    # https://github.com/orca-so/whirlpools/blob/7b9ec35/sdk/src/utils/public/pool-utils.ts#L141
    @staticmethod
    def get_max_liquidity_from_token_amounts(
        sqrt_price_x64_current: int,
        sqrt_price_x64_lower: int,
        sqrt_price_x64_upper: int,
        amounts: TokenAmounts
    ) -> int:
        invariant(sqrt_price_x64_lower < sqrt_price_x64_upper, "sqrt_price_x64_lower < sqrt_price_x64_upper")

        if sqrt_price_x64_current >= sqrt_price_x64_upper:
            return LiquidityMath.get_liquidity_from_token_b(sqrt_price_x64_lower, sqrt_price_x64_upper, amounts.token_b)
        if sqrt_price_x64_current <= sqrt_price_x64_lower:
            return LiquidityMath.get_liquidity_from_token_a(sqrt_price_x64_lower, sqrt_price_x64_upper, amounts.token_a)

        liq_a = LiquidityMath.get_liquidity_from_token_a(sqrt_price_x64_current, sqrt_price_x64_upper, amounts.token_a)
        liq_b = LiquidityMath.get_liquidity_from_token_b(sqrt_price_x64_lower, sqrt_price_x64_current, amounts.token_b)
        return min(liq_a, liq_b)

Classes

class LiquidityMath
Expand source code
class LiquidityMath:
    # https://orca-so.github.io/whirlpools/classes/PoolUtil.html#getTokenAmountsFromLiquidity
    # https://github.com/orca-so/whirlpools/blob/7b9ec35/sdk/src/utils/public/pool-utils.ts#L84
    @staticmethod
    def get_token_amounts_from_liquidity(
        liquidity: int,
        sqrt_price_x64_current: int,
        sqrt_price_x64_lower: int,
        sqrt_price_x64_upper: int,
        round_up: bool
    ) -> TokenAmounts:
        invariant(sqrt_price_x64_lower < sqrt_price_x64_upper, "sqrt_price_x64_lower < sqrt_price_x64_upper")

        liq = Decimal(liquidity)
        lower = Decimal(sqrt_price_x64_lower)
        upper = Decimal(sqrt_price_x64_upper)
        current = min(max(Decimal(sqrt_price_x64_current), lower), upper)  # bounded

        shift_64 = Decimal(2)**64
        token_a = liq * shift_64 * (upper - current) / (current * upper)
        token_b = liq * (current - lower) / shift_64

        if round_up:
            return TokenAmounts(math.ceil(token_a), math.ceil(token_b))
        else:
            return TokenAmounts(math.floor(token_a), math.floor(token_b))

    @staticmethod
    def get_token_a_from_liquidity(
        liquidity: int,
        sqrt_price_x64_0: int,
        sqrt_price_x64_1: int,
        round_up: bool
    ) -> int:
        small_sqrt_price_x64 = min(sqrt_price_x64_0, sqrt_price_x64_1)
        large_sqrt_price_x64 = max(sqrt_price_x64_0, sqrt_price_x64_1)
        if small_sqrt_price_x64 == large_sqrt_price_x64:
            return 0

        return LiquidityMath.get_token_amounts_from_liquidity(
            liquidity,
            small_sqrt_price_x64,
            small_sqrt_price_x64,
            large_sqrt_price_x64,
            round_up
        ).token_a

    @staticmethod
    def get_token_b_from_liquidity(
            liquidity: int,
            sqrt_price_x64_0: int,
            sqrt_price_x64_1: int,
            round_up: bool
    ) -> int:
        small_sqrt_price_x64 = min(sqrt_price_x64_0, sqrt_price_x64_1)
        large_sqrt_price_x64 = max(sqrt_price_x64_0, sqrt_price_x64_1)
        if small_sqrt_price_x64 == large_sqrt_price_x64:
            return 0

        return LiquidityMath.get_token_amounts_from_liquidity(
            liquidity,
            large_sqrt_price_x64,
            small_sqrt_price_x64,
            large_sqrt_price_x64,
            round_up
        ).token_b

    # https://github.com/orca-so/whirlpools/blob/7b9ec35/sdk/src/utils/public/pool-utils.ts#L237
    @staticmethod
    def get_liquidity_from_token_a(sqrt_price_x64_0: int, sqrt_price_x64_1: int, amount: int) -> int:
        small_sqrt_price_x64 = min(sqrt_price_x64_0, sqrt_price_x64_1)
        large_sqrt_price_x64 = max(sqrt_price_x64_0, sqrt_price_x64_1)
        if small_sqrt_price_x64 == large_sqrt_price_x64:
            return 0

        # a = L/small_sqrt_price_x64/x64 - L/large_sqrt_price_x64/x64
        # a = L * x64 * ( 1/small_sqrt_price_x64 - 1/large_sqrt_price_x64 )
        # a = L * x64 * ((large_sqrt_price_x64 - small_sqrt_price_x64) / (small_sqrt_price_x64 * large_sqrt_price_x64))
        # L = a / x64 / ((large_sqrt_price_x64 - small_sqrt_price_x64) / (small_sqrt_price_x64 * large_sqrt_price_x64))
        # L = a * (small_sqrt_price_x64 * large_sqrt_price_x64) / (x64 * (large_sqrt_price_x64 - small_sqrt_price_x64))
        shift_64 = 2**64
        num = amount * (small_sqrt_price_x64 * large_sqrt_price_x64)
        denom = shift_64 * (large_sqrt_price_x64 - small_sqrt_price_x64)
        return num // denom

    # https://github.com/orca-so/whirlpools/blob/7b9ec35/sdk/src/utils/public/pool-utils.ts#L248
    @staticmethod
    def get_liquidity_from_token_b(sqrt_price_x64_0: int, sqrt_price_x64_1: int, amount: int) -> int:
        small_sqrt_price_x64 = min(sqrt_price_x64_0, sqrt_price_x64_1)
        large_sqrt_price_x64 = max(sqrt_price_x64_0, sqrt_price_x64_1)
        if small_sqrt_price_x64 == large_sqrt_price_x64:
            return 0

        # b = L*large_sqrt_price_x64/x64 - L*small_sqrt_sqrt_price_x64/x64
        # L = b / ( large_sqrt_price_x64/x64 - small_sqrt_sqrt_price_x64/x64 )
        # L = b * x64 / ( large_sqrt_price_x64 - small_sqrt_price_x64 )
        shift_64 = 2**64
        num = amount * shift_64
        denom = large_sqrt_price_x64 - small_sqrt_price_x64
        return num // denom

    # https://orca-so.github.io/whirlpools/classes/PoolUtil.html#estimateLiquidityFromTokenAmounts
    # https://github.com/orca-so/whirlpools/blob/7b9ec35/sdk/src/utils/public/pool-utils.ts#L141
    @staticmethod
    def get_max_liquidity_from_token_amounts(
        sqrt_price_x64_current: int,
        sqrt_price_x64_lower: int,
        sqrt_price_x64_upper: int,
        amounts: TokenAmounts
    ) -> int:
        invariant(sqrt_price_x64_lower < sqrt_price_x64_upper, "sqrt_price_x64_lower < sqrt_price_x64_upper")

        if sqrt_price_x64_current >= sqrt_price_x64_upper:
            return LiquidityMath.get_liquidity_from_token_b(sqrt_price_x64_lower, sqrt_price_x64_upper, amounts.token_b)
        if sqrt_price_x64_current <= sqrt_price_x64_lower:
            return LiquidityMath.get_liquidity_from_token_a(sqrt_price_x64_lower, sqrt_price_x64_upper, amounts.token_a)

        liq_a = LiquidityMath.get_liquidity_from_token_a(sqrt_price_x64_current, sqrt_price_x64_upper, amounts.token_a)
        liq_b = LiquidityMath.get_liquidity_from_token_b(sqrt_price_x64_lower, sqrt_price_x64_current, amounts.token_b)
        return min(liq_a, liq_b)

Static methods

def get_liquidity_from_token_a(sqrt_price_x64_0: int, sqrt_price_x64_1: int, amount: int) ‑> int
Expand source code
@staticmethod
def get_liquidity_from_token_a(sqrt_price_x64_0: int, sqrt_price_x64_1: int, amount: int) -> int:
    small_sqrt_price_x64 = min(sqrt_price_x64_0, sqrt_price_x64_1)
    large_sqrt_price_x64 = max(sqrt_price_x64_0, sqrt_price_x64_1)
    if small_sqrt_price_x64 == large_sqrt_price_x64:
        return 0

    # a = L/small_sqrt_price_x64/x64 - L/large_sqrt_price_x64/x64
    # a = L * x64 * ( 1/small_sqrt_price_x64 - 1/large_sqrt_price_x64 )
    # a = L * x64 * ((large_sqrt_price_x64 - small_sqrt_price_x64) / (small_sqrt_price_x64 * large_sqrt_price_x64))
    # L = a / x64 / ((large_sqrt_price_x64 - small_sqrt_price_x64) / (small_sqrt_price_x64 * large_sqrt_price_x64))
    # L = a * (small_sqrt_price_x64 * large_sqrt_price_x64) / (x64 * (large_sqrt_price_x64 - small_sqrt_price_x64))
    shift_64 = 2**64
    num = amount * (small_sqrt_price_x64 * large_sqrt_price_x64)
    denom = shift_64 * (large_sqrt_price_x64 - small_sqrt_price_x64)
    return num // denom
def get_liquidity_from_token_b(sqrt_price_x64_0: int, sqrt_price_x64_1: int, amount: int) ‑> int
Expand source code
@staticmethod
def get_liquidity_from_token_b(sqrt_price_x64_0: int, sqrt_price_x64_1: int, amount: int) -> int:
    small_sqrt_price_x64 = min(sqrt_price_x64_0, sqrt_price_x64_1)
    large_sqrt_price_x64 = max(sqrt_price_x64_0, sqrt_price_x64_1)
    if small_sqrt_price_x64 == large_sqrt_price_x64:
        return 0

    # b = L*large_sqrt_price_x64/x64 - L*small_sqrt_sqrt_price_x64/x64
    # L = b / ( large_sqrt_price_x64/x64 - small_sqrt_sqrt_price_x64/x64 )
    # L = b * x64 / ( large_sqrt_price_x64 - small_sqrt_price_x64 )
    shift_64 = 2**64
    num = amount * shift_64
    denom = large_sqrt_price_x64 - small_sqrt_price_x64
    return num // denom
def get_max_liquidity_from_token_amounts(sqrt_price_x64_current: int, sqrt_price_x64_lower: int, sqrt_price_x64_upper: int, amounts: TokenAmounts) ‑> int
Expand source code
@staticmethod
def get_max_liquidity_from_token_amounts(
    sqrt_price_x64_current: int,
    sqrt_price_x64_lower: int,
    sqrt_price_x64_upper: int,
    amounts: TokenAmounts
) -> int:
    invariant(sqrt_price_x64_lower < sqrt_price_x64_upper, "sqrt_price_x64_lower < sqrt_price_x64_upper")

    if sqrt_price_x64_current >= sqrt_price_x64_upper:
        return LiquidityMath.get_liquidity_from_token_b(sqrt_price_x64_lower, sqrt_price_x64_upper, amounts.token_b)
    if sqrt_price_x64_current <= sqrt_price_x64_lower:
        return LiquidityMath.get_liquidity_from_token_a(sqrt_price_x64_lower, sqrt_price_x64_upper, amounts.token_a)

    liq_a = LiquidityMath.get_liquidity_from_token_a(sqrt_price_x64_current, sqrt_price_x64_upper, amounts.token_a)
    liq_b = LiquidityMath.get_liquidity_from_token_b(sqrt_price_x64_lower, sqrt_price_x64_current, amounts.token_b)
    return min(liq_a, liq_b)
def get_token_a_from_liquidity(liquidity: int, sqrt_price_x64_0: int, sqrt_price_x64_1: int, round_up: bool) ‑> int
Expand source code
@staticmethod
def get_token_a_from_liquidity(
    liquidity: int,
    sqrt_price_x64_0: int,
    sqrt_price_x64_1: int,
    round_up: bool
) -> int:
    small_sqrt_price_x64 = min(sqrt_price_x64_0, sqrt_price_x64_1)
    large_sqrt_price_x64 = max(sqrt_price_x64_0, sqrt_price_x64_1)
    if small_sqrt_price_x64 == large_sqrt_price_x64:
        return 0

    return LiquidityMath.get_token_amounts_from_liquidity(
        liquidity,
        small_sqrt_price_x64,
        small_sqrt_price_x64,
        large_sqrt_price_x64,
        round_up
    ).token_a
def get_token_amounts_from_liquidity(liquidity: int, sqrt_price_x64_current: int, sqrt_price_x64_lower: int, sqrt_price_x64_upper: int, round_up: bool) ‑> TokenAmounts
Expand source code
@staticmethod
def get_token_amounts_from_liquidity(
    liquidity: int,
    sqrt_price_x64_current: int,
    sqrt_price_x64_lower: int,
    sqrt_price_x64_upper: int,
    round_up: bool
) -> TokenAmounts:
    invariant(sqrt_price_x64_lower < sqrt_price_x64_upper, "sqrt_price_x64_lower < sqrt_price_x64_upper")

    liq = Decimal(liquidity)
    lower = Decimal(sqrt_price_x64_lower)
    upper = Decimal(sqrt_price_x64_upper)
    current = min(max(Decimal(sqrt_price_x64_current), lower), upper)  # bounded

    shift_64 = Decimal(2)**64
    token_a = liq * shift_64 * (upper - current) / (current * upper)
    token_b = liq * (current - lower) / shift_64

    if round_up:
        return TokenAmounts(math.ceil(token_a), math.ceil(token_b))
    else:
        return TokenAmounts(math.floor(token_a), math.floor(token_b))
def get_token_b_from_liquidity(liquidity: int, sqrt_price_x64_0: int, sqrt_price_x64_1: int, round_up: bool) ‑> int
Expand source code
@staticmethod
def get_token_b_from_liquidity(
        liquidity: int,
        sqrt_price_x64_0: int,
        sqrt_price_x64_1: int,
        round_up: bool
) -> int:
    small_sqrt_price_x64 = min(sqrt_price_x64_0, sqrt_price_x64_1)
    large_sqrt_price_x64 = max(sqrt_price_x64_0, sqrt_price_x64_1)
    if small_sqrt_price_x64 == large_sqrt_price_x64:
        return 0

    return LiquidityMath.get_token_amounts_from_liquidity(
        liquidity,
        large_sqrt_price_x64,
        small_sqrt_price_x64,
        large_sqrt_price_x64,
        round_up
    ).token_b