PathrockNetwork Gno Explorer
HomeBlocksTransactionsTokensRealmsPackagesValidatorsAnalytics

PathrockNetwork Gno Explorer — an independent explorer for Gno.land Mainnet (gnoland-1), operated by PathrockNetwork. Not an official Gno.land service.

gnowebarchive RPC

gno.land/p/gnoswap/gnsmath/v1

Package
Open in gnoweb ↗

Overview

Kind
Pure package
Name
v1
Namespace
gnoswap / gnsmath
Files
11 (README)(gnomod.toml)
Exported functions
n/a — not supported for pure packages by the node (vm/qfuncs)
Module
gno.land/p/gnoswap/gnsmath/v1
gno
0.9

Files (11)

  • README.mdmarkdown
  • gnomod.tomltoml
  • bit_math.gnogno
  • consts.gnogno
  • doc.gnogno
  • errors.gnogno
  • liquidity_math.gnogno
  • safe_math.gnogno
  • sqrt_price_math.gnogno
  • swap_math.gnogno
  • tick_math.gnogno
  • liquidity_math.gnogno
    1package gnsmath23import (4	ufmt "gno.land/p/nt/ufmt/v0"56	"gno.land/p/gnoswap/consts/v1"7	i256 "gno.land/p/gnoswap/int256/v1"8

    Functions

    not supported for pure packages by the node (vm/qfuncs)

    Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.

    u256 "gno.land/p/gnoswap/uint256/v1"
    9)
    10
    11// computeLiquidityForAmount0 calculates the liquidity for a given amount of token0.
    12//
    13// This function computes the maximum possible liquidity that can be provided for `token0`
    14// based on the provided price boundaries (sqrtRatioAX96 and sqrtRatioBX96) in Q64.96 format.
    15//
    16// Parameters:
    17// - sqrtRatioAX96: *u256.Uint - The square root price at the lower tick boundary (Q64.96).
    18// - sqrtRatioBX96: *u256.Uint - The square root price at the upper tick boundary (Q64.96).
    19// - amount0: *u256.Uint - The amount of token0 to be converted to liquidity.
    20//
    21// Returns:
    22// - *u256.Uint: The calculated liquidity, represented as an unsigned 128-bit integer (uint128).
    23//
    24// Panics:
    25// - If the resulting liquidity exceeds the uint128 range, `SafeConvertToUint128` will trigger a panic.
    26func computeLiquidityForAmount0(sqrtRatioAX96, sqrtRatioBX96, amount0 *u256.Uint) *u256.Uint {
    27 sqrtRatioAX96, sqrtRatioBX96 = toAscendingOrder(sqrtRatioAX96, sqrtRatioBX96)
    28 intermediate := u256.MulDiv(sqrtRatioAX96, sqrtRatioBX96, consts.Q96())
    29
    30 diff := u256.Zero().Sub(sqrtRatioBX96, sqrtRatioAX96)
    31 if diff.IsZero() {
    32 panic(newErrorWithDetail(
    33 errLiquidityIdenticalTicks,
    34 ufmt.Sprintf("sqrtRatioAX96 (%s) and sqrtRatioBX96 (%s) are identical", sqrtRatioAX96.ToString(), sqrtRatioBX96.ToString()),
    35 ))
    36 }
    37 res := u256.MulDiv(amount0, intermediate, diff)
    38 return SafeConvertToUint128(res)
    39}
    40
    41// computeLiquidityForAmount1 calculates liquidity based on the provided token1 amount and price range.
    42//
    43// This function computes the liquidity for a given amount of token1 by using the difference
    44// between the upper and lower square root price ratios. The calculation uses Q96 fixed-point
    45// arithmetic to maintain precision.
    46//
    47// Parameters:
    48// - sqrtRatioAX96: *u256.Uint - The square root ratio of price at the lower tick, represented in Q96 format.
    49// - sqrtRatioBX96: *u256.Uint - The square root ratio of price at the upper tick, represented in Q96 format.
    50// - amount1: *u256.Uint - The amount of token1 to calculate liquidity for.
    51//
    52// Returns:
    53// - *u256.Uint: The calculated liquidity based on the provided amount of token1 and price range.
    54//
    55// Notes:
    56// - The result is not directly limited to uint128, as liquidity values can exceed uint128 bounds.
    57// - If `sqrtRatioAX96 == sqrtRatioBX96`, the function will panic due to division by zero.
    58// - Q96 is a constant representing `2^96`, ensuring that precision is maintained during division.
    59//
    60// Panics:
    61// - If the resulting liquidity exceeds the uint128 range, `SafeConvertToUint128` will trigger a panic.
    62func computeLiquidityForAmount1(sqrtRatioAX96, sqrtRatioBX96, amount1 *u256.Uint) *u256.Uint {
    63 sqrtRatioAX96, sqrtRatioBX96 = toAscendingOrder(sqrtRatioAX96, sqrtRatioBX96)
    64
    65 diff := u256.Zero().Sub(sqrtRatioBX96, sqrtRatioAX96)
    66 if diff.IsZero() {
    67 panic(newErrorWithDetail(
    68 errLiquidityIdenticalTicks,
    69 ufmt.Sprintf("sqrtRatioAX96 (%s) and sqrtRatioBX96 (%s) are identical", sqrtRatioAX96.ToString(), sqrtRatioBX96.ToString()),
    70 ))
    71 }
    72 res := u256.MulDiv(amount1, consts.Q96(), diff)
    73 return SafeConvertToUint128(res)
    74}
    75
    76// GetLiquidityForAmounts calculates the maximum liquidity supported by two token amounts.
    77//
    78// The current square-root price determines which token amounts are active. Below
    79// the range only token0 is used, above it only token1 is used, and inside it the
    80// smaller of the token0- and token1-derived liquidities is returned.
    81//
    82// Parameters:
    83// - sqrtRatioX96: Current square-root price, encoded as a Q64.96 ratio.
    84// - sqrtRatioAX96: First price-range endpoint, encoded as a Q64.96 ratio.
    85// - sqrtRatioBX96: Second price-range endpoint, encoded as a Q64.96 ratio; the endpoints are sorted.
    86// - amount0: Available token0 amount.
    87// - amount1: Available token1 amount.
    88//
    89// Returns:
    90// - liquidity: Maximum liquidity supported by the amounts, constrained to uint128.
    91//
    92// Panics if a selected amount/range calculation has identical bounds or exceeds uint128.
    93func GetLiquidityForAmounts(sqrtRatioX96, sqrtRatioAX96, sqrtRatioBX96, amount0, amount1 *u256.Uint) (liquidity *u256.Uint) {
    94 sqrtRatioAX96, sqrtRatioBX96 = toAscendingOrder(sqrtRatioAX96, sqrtRatioBX96)
    95
    96 if sqrtRatioX96.Lte(sqrtRatioAX96) {
    97 liquidity = computeLiquidityForAmount0(sqrtRatioAX96, sqrtRatioBX96, amount0)
    98 } else if sqrtRatioX96.Lt(sqrtRatioBX96) {
    99 liquidity0 := computeLiquidityForAmount0(sqrtRatioX96, sqrtRatioBX96, amount0)
    100 liquidity1 := computeLiquidityForAmount1(sqrtRatioAX96, sqrtRatioX96, amount1)
    101
    102 if liquidity0.Lt(liquidity1) {
    103 liquidity = liquidity0
    104 } else {
    105 liquidity = liquidity1
    106 }
    107 } else {
    108 liquidity = computeLiquidityForAmount1(sqrtRatioAX96, sqrtRatioBX96, amount1)
    109 }
    110 return liquidity
    111}
    112
    113// computeAmount0ForLiquidity calculates the required amount of token0 for a given liquidity level
    114// within a specified price range (represented by sqrt ratios).
    115//
    116// This function determines the amount of token0 needed to provide a specified amount of liquidity
    117// within a price range defined by sqrtRatioAX96 (lower bound) and sqrtRatioBX96 (upper bound).
    118//
    119// Parameters:
    120// - sqrtRatioAX96: The lower bound of the price range as a square root ratio in Q64.96 format (*u256.Uint).
    121// - sqrtRatioBX96: The upper bound of the price range as a square root ratio in Q64.96 format (*u256.Uint).
    122// - liquidity: The liquidity to be provided (*u256.Uint).
    123//
    124// Returns:
    125// - *u256.Uint: The amount of token0 required to achieve the specified liquidity level.
    126//
    127// Notes:
    128// - This function assumes the price bounds are expressed in Q64.96 fixed-point format.
    129// - The function returns 0 if the liquidity is 0 or the price bounds are invalid.
    130// - Handles edge cases where sqrtRatioAX96 equals sqrtRatioBX96 by returning 0 (to prevent division by zero).
    131func computeAmount0ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity *u256.Uint) *u256.Uint {
    132 sqrtRatioAX96, sqrtRatioBX96 = toAscendingOrder(sqrtRatioAX96, sqrtRatioBX96)
    133 if sqrtRatioAX96.IsZero() || sqrtRatioBX96.IsZero() || liquidity.IsZero() || sqrtRatioAX96.Eq(sqrtRatioBX96) {
    134 return u256.Zero()
    135 }
    136
    137 val1 := u256.Zero().Lsh(liquidity, Q96_RESOLUTION)
    138 val2 := u256.Zero().Sub(sqrtRatioBX96, sqrtRatioAX96)
    139
    140 res := u256.MulDiv(val1, val2, sqrtRatioBX96)
    141 res = res.Div(res, sqrtRatioAX96)
    142
    143 return res
    144}
    145
    146// computeAmount1ForLiquidity calculates the required amount of token1 for a given liquidity level
    147// within a specified price range (represented by sqrt ratios).
    148//
    149// This function determines the amount of token1 needed to provide liquidity between the
    150// lower (sqrtRatioAX96) and upper (sqrtRatioBX96) price bounds. The calculation is performed
    151// in Q64.96 fixed-point format, which is standard for many liquidity calculations.
    152//
    153// Parameters:
    154// - sqrtRatioAX96: The lower bound of the price range as a square root ratio in Q64.96 format (*u256.Uint).
    155// - sqrtRatioBX96: The upper bound of the price range as a square root ratio in Q64.96 format (*u256.Uint).
    156// - liquidity: The liquidity amount to be used in the calculation (*u256.Uint).
    157//
    158// Returns:
    159// - *u256.Uint: The amount of token1 required to achieve the specified liquidity level.
    160//
    161// Notes:
    162// - This function handles edge cases where the liquidity is zero or when sqrtRatioAX96 equals sqrtRatioBX96
    163// to prevent division by zero.
    164// - The calculation assumes sqrtRatioAX96 is always less than or equal to sqrtRatioBX96 after the initial
    165// ascending order sorting.
    166func computeAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity *u256.Uint) *u256.Uint {
    167 sqrtRatioAX96, sqrtRatioBX96 = toAscendingOrder(sqrtRatioAX96, sqrtRatioBX96)
    168 if liquidity.IsZero() || sqrtRatioAX96.Eq(sqrtRatioBX96) {
    169 return u256.Zero()
    170 }
    171
    172 diff := u256.Zero().Sub(sqrtRatioBX96, sqrtRatioAX96)
    173 res := u256.MulDiv(liquidity, diff, consts.Q96())
    174
    175 return res
    176}
    177
    178// GetAmountsForLiquidity calculates the amounts of token0 and token1 represented
    179// by a specified liquidity within a price range.
    180//
    181// If the current price is below the lower bound, only token0 is required. If the
    182// current price is above the upper bound, only token1 is required. When the
    183// price is within the range, both token0 and token1 are calculated.
    184//
    185// Parameters:
    186// - sqrtRatioX96: Current square-root price in Q64.96 format.
    187// - sqrtRatioAX96: First price-range endpoint in Q64.96 format.
    188// - sqrtRatioBX96: Second price-range endpoint in Q64.96 format; the endpoints are ordered internally.
    189// - liquidity: Non-negative liquidity amount to value.
    190//
    191// Returns:
    192// - amount0: Token0 amount represented by liquidity; zero when the current price is at or above the upper endpoint.
    193// - amount1: Token1 amount represented by liquidity; zero when the current price is at or below the lower endpoint.
    194// Call ToString() on either value for decimal display.
    195//
    196// Notes:
    197// - If liquidity is zero, the function returns zero values for both tokens.
    198// - At a boundary, the corresponding out-of-range token amount is zero.
    199//
    200// Example:
    201// ```
    202// amount0, amount1 := GetAmountsForLiquidity(
    203//
    204// u256.MustFromDecimal("79228162514264337593543950336"), // sqrtRatioX96 (1.0 in Q64.96)
    205// u256.MustFromDecimal("39614081257132168796771975168"), // sqrtRatioAX96 (0.5 in Q64.96)
    206// u256.MustFromDecimal("158456325028528675187087900672"), // sqrtRatioBX96 (2.0 in Q64.96)
    207// u256.MustFromDecimal("1000000"), // Liquidity
    208//
    209// )
    210//
    211// println("Token0:", amount0.ToString(), "Token1:", amount1.ToString())
    212//
    213// // Output:
    214// Token0: 500000, Token1: 500000
    215// ```
    216func GetAmountsForLiquidity(sqrtRatioX96, sqrtRatioAX96, sqrtRatioBX96, liquidity *u256.Uint) (*u256.Uint, *u256.Uint) {
    217 if liquidity.IsZero() {
    218 return u256.Zero(), u256.Zero()
    219 }
    220
    221 sqrtRatioAX96, sqrtRatioBX96 = toAscendingOrder(sqrtRatioAX96, sqrtRatioBX96)
    222
    223 amount0 := u256.Zero()
    224 amount1 := u256.Zero()
    225
    226 if sqrtRatioX96.Lte(sqrtRatioAX96) {
    227 amount0 = computeAmount0ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity)
    228 } else if sqrtRatioX96.Lt(sqrtRatioBX96) {
    229 amount0 = computeAmount0ForLiquidity(sqrtRatioX96, sqrtRatioBX96, liquidity)
    230 amount1 = computeAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioX96, liquidity)
    231 } else {
    232 amount1 = computeAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity)
    233 }
    234
    235 return amount0, amount1
    236}
    237
    238// LiquidityMathAddDelta calculates the new liquidity after applying a signed delta.
    239// A negative delta subtracts its magnitude; a non-negative delta adds its magnitude.
    240//
    241// Parameters:
    242// - x: Current non-negative liquidity value.
    243// - y: Signed liquidity delta; positive values add and negative values subtract.
    244//
    245// Returns:
    246// - liquidity: Updated liquidity, constrained to the uint128 range.
    247//
    248// Panics if x or y is nil, subtraction underflows, addition overflows uint256,
    249// or the resulting liquidity exceeds MaxUint128.
    250func LiquidityMathAddDelta(x *u256.Uint, y *i256.Int) *u256.Uint {
    251 if x == nil || y == nil {
    252 panic("liquidity_math: x or y is nil")
    253 }
    254
    255 yAbs := y.Abs()
    256
    257 // Subtract or add based on the sign of y
    258 if y.Lt(i256.Zero()) {
    259 z := u256.Zero().Sub(x, yAbs)
    260 if z.Gte(x) {
    261 panic(ufmt.Sprintf(
    262 "liquidity_math: underflow (x: %s, y: %s, z:%s)",
    263 x.ToString(), y.ToString(), z.ToString()))
    264 }
    265 if z.Gt(consts.MaxUint128()) {
    266 panic(ufmt.Sprintf(
    267 "liquidity_math: result exceeds uint128 range (z: %s)",
    268 z.ToString()))
    269 }
    270 return z
    271 }
    272
    273 z := u256.Zero().Add(x, yAbs)
    274 if z.Lt(x) {
    275 panic(ufmt.Sprintf(
    276 "liquidity_math: overflow (x: %s, y: %s, z:%s)",
    277 x.ToString(), y.ToString(), z.ToString()))
    278 }
    279 if z.Gt(consts.MaxUint128()) {
    280 panic(ufmt.Sprintf(
    281 "liquidity_math: result exceeds uint128 range (z: %s)",
    282 z.ToString()))
    283 }
    284 return z
    285}
    286
    287// toAscendingOrder returns the two values in ascending order.
    288func toAscendingOrder(a, b *u256.Uint) (*u256.Uint, *u256.Uint) {
    289 if a.Gt(b) {
    290 return b, a
    291 }
    292
    293 return a, b
    294}
    295
    296// SafeConvertToUint128 verifies that value fits in the uint128 range.
    297//
    298// No representation conversion is performed: the original pointer is returned
    299// when its value is at most 2^128 - 1.
    300//
    301// Parameters:
    302// - value: Non-nil unsigned 256-bit value to validate.
    303//
    304// Returns:
    305// - converted: The same *u256.Uint pointer when value fits in uint128.
    306//
    307// Panics if value is nil or exceeds the maximum uint128 value.
    308func SafeConvertToUint128(value *u256.Uint) *u256.Uint {
    309 if value.Gt(consts.MaxUint128()) {
    310 panic(ufmt.Sprintf(
    311 "%v: amount(%s) overflows uint128 range",
    312 errLiquidityOverflow, value.ToString()))
    313 }
    314 return value
    315}
    316