PathrockNetwork Gno Explorer
HomeBlocksTransactionsRealmsPackagesValidatorsAnalytics

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
  • sqrt_price_math.gnogno
    1package gnsmath23import (4	"gno.land/p/gnoswap/consts/v1"5	i256 "gno.land/p/gnoswap/int256/v1"6	u256 "gno.land/p/gnoswap/uint256/v1"7)8

    Functions

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

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

    9// MIN_SQRT_RATIO returns the minimum valid Q64.96 square-root price ratio.
    10//
    11// Returns:
    12// - minSqrtRatio: A fresh *u256.Uint containing 4,295,128,739, the lower
    13// boundary accepted by the pool's square-root price math.
    14func MIN_SQRT_RATIO() *u256.Uint { return consts.MinSqrtRatio() }
    15
    16// MAX_SQRT_RATIO returns the upper boundary used by Q64.96 square-root price math.
    17//
    18// Returns:
    19// - maxSqrtRatio: A fresh *u256.Uint containing
    20// 1461446703485210103287273052203988822378723970342. Inverse tick conversion
    21// treats this boundary as exclusive.
    22func MAX_SQRT_RATIO() *u256.Uint { return consts.MaxSqrtRatio() }
    23
    24// getNextPriceAmount0Add calculates the next sqrt price when adding token0 liquidity,
    25// rounding up to ensure conservative pricing for the protocol.
    26// This internal function handles the case where token0 is being added to the pool.
    27func getNextPriceAmount0Add(
    28 currentSqrtPriceX96, liquidity, amountToAdd *u256.Uint,
    29) *u256.Uint {
    30 // liquidityShifted = liquidity << 96
    31 liquidityShifted := u256.Zero().Lsh(liquidity, Q96_RESOLUTION)
    32 // amountTimesSqrtPrice = amount * sqrtPrice
    33 amountTimesSqrtPrice := u256.Zero().Mul(amountToAdd, currentSqrtPriceX96)
    34
    35 // Overflow check: Ensure (amountTimesSqrtPrice / amountToAdd) == currentSqrtPriceX96
    36 quotientCheck := u256.Zero().Div(amountTimesSqrtPrice, amountToAdd)
    37 if quotientCheck.Eq(currentSqrtPriceX96) {
    38 // denominator = liquidityShifted + amountTimesSqrtPrice
    39 denominator := u256.Zero().Add(liquidityShifted, amountTimesSqrtPrice)
    40 // only take this path when denominator >= liquidityShifted
    41 if denominator.Gte(liquidityShifted) {
    42 return u256.MulDivRoundingUp(liquidityShifted, currentSqrtPriceX96, denominator)
    43 }
    44 }
    45
    46 // fallback: liquidityShifted / ((liquidityShifted / sqrtPrice) + amount)
    47 divValue := u256.Zero().Div(liquidityShifted, currentSqrtPriceX96)
    48 denominator, overflow := u256.Zero().AddOverflow(divValue, amountToAdd)
    49 if overflow {
    50 panic(errSafeMathOverflow)
    51 }
    52 return u256.DivRoundingUp(liquidityShifted, denominator)
    53}
    54
    55// getNextPriceAmount0Remove calculates the next sqrt price when removing token0 liquidity,
    56// rounding up to ensure conservative pricing for the protocol.
    57// This internal function handles the case where token0 is being removed from the pool.
    58// Panics if validation checks fail (invalid pool sqrt price calculation).
    59func getNextPriceAmount0Remove(
    60 currentSqrtPriceX96, liquidity, amountToRemove *u256.Uint,
    61) *u256.Uint {
    62 // liquidityShifted = liquidity << 96
    63 liquidityShifted := u256.Zero().Lsh(liquidity, Q96_RESOLUTION)
    64 // amountTimesSqrtPrice = amountToRemove * currentSqrtPriceX96
    65 amountTimesSqrtPrice := u256.Zero().Mul(amountToRemove, currentSqrtPriceX96)
    66
    67 // Validation checks
    68 quotientCheck := u256.Zero().Div(amountTimesSqrtPrice, amountToRemove)
    69 if !quotientCheck.Eq(currentSqrtPriceX96) || !liquidityShifted.Gt(amountTimesSqrtPrice) {
    70 panic(errInvalidPoolSqrtPrice)
    71 }
    72
    73 denominator := u256.Zero().Sub(liquidityShifted, amountTimesSqrtPrice)
    74 return u256.MulDivRoundingUp(liquidityShifted, currentSqrtPriceX96, denominator)
    75}
    76
    77// getNextSqrtPriceFromAmount0RoundingUp calculates the next sqrt price based on token0 amount,
    78// always rounding up to ensure conservative pricing in both exact output and exact input cases.
    79// The add parameter determines whether liquidity is being added (true) or removed (false).
    80func getNextSqrtPriceFromAmount0RoundingUp(
    81 sqrtPX96 *u256.Uint,
    82 liquidity *u256.Uint,
    83 amount *u256.Uint,
    84 add bool,
    85) *u256.Uint {
    86 // Shortcut: if no amount, return original price
    87 if amount.IsZero() {
    88 return sqrtPX96
    89 }
    90
    91 if add {
    92 return getNextPriceAmount0Add(sqrtPX96, liquidity, amount)
    93 }
    94 return getNextPriceAmount0Remove(sqrtPX96, liquidity, amount)
    95}
    96
    97// getNextPriceAmount1Add calculates the next sqrt price when adding token1,
    98// preserving rounding-down logic for the final result.
    99// This internal function handles the case where token1 is being added to the pool.
    100func getNextPriceAmount1Add(
    101 sqrtPX96, liquidity, amount *u256.Uint,
    102) *u256.Uint {
    103 var quotient *u256.Uint
    104
    105 if amount.Lte(consts.Max160()) {
    106 // Use local variables to avoid allocation conflicts
    107 shifted := u256.Zero().Lsh(amount, Q96_RESOLUTION)
    108 quotient = u256.Zero().Div(shifted, liquidity)
    109 } else {
    110 quotient = u256.MulDiv(amount, consts.Q96(), liquidity)
    111 }
    112
    113 result, overflow := u256.Zero().AddOverflow(sqrtPX96, quotient)
    114 if overflow || result.Gt(consts.Max160()) {
    115 panic(errSqrtPriceOverflow)
    116 }
    117
    118 return result
    119}
    120
    121// getNextPriceAmount1Remove calculates the next sqrt price when removing token1,
    122// preserving rounding-down logic for the final result.
    123// This internal function handles the case where token1 is being removed from the pool.
    124// Panics if sqrt price would exceed quotient.
    125func getNextPriceAmount1Remove(
    126 sqrtPX96, liquidity, amount *u256.Uint,
    127) *u256.Uint {
    128 var quotient *u256.Uint
    129
    130 if amount.Lte(consts.Max160()) {
    131 shifted := u256.Zero().Lsh(amount, Q96_RESOLUTION)
    132 quotient = u256.DivRoundingUp(shifted, liquidity)
    133 } else {
    134 quotient = u256.MulDivRoundingUp(amount, consts.Q96(), liquidity)
    135 }
    136
    137 if !sqrtPX96.Gt(quotient) {
    138 panic(errSqrtPriceExceedsQuotient)
    139 }
    140
    141 return u256.Zero().Sub(sqrtPX96, quotient)
    142}
    143
    144// getNextSqrtPriceFromAmount1RoundingDown calculates the next sqrt price based on token1 amount,
    145// always rounding down to ensure conservative pricing in both exact output and exact input cases.
    146// The add parameter determines whether liquidity is being added (true) or removed (false).
    147func getNextSqrtPriceFromAmount1RoundingDown(
    148 sqrtPX96,
    149 liquidity,
    150 amount *u256.Uint,
    151 add bool,
    152) *u256.Uint {
    153 // Shortcut: if no amount, return original price
    154 if amount.IsZero() {
    155 return sqrtPX96
    156 }
    157
    158 if add {
    159 return getNextPriceAmount1Add(sqrtPX96, liquidity, amount)
    160 }
    161 return getNextPriceAmount1Remove(sqrtPX96, liquidity, amount)
    162}
    163
    164// getNextSqrtPriceFromInput calculates the next sqrt price after adding tokens to the pool,
    165// rounding up for conservative pricing in both swap directions.
    166// The zeroForOne parameter indicates swap direction (token0 for token1 when true).
    167// Panics if sqrtPX96 or liquidity is zero.
    168func getNextSqrtPriceFromInput(
    169 sqrtPX96, liquidity, amountIn *u256.Uint,
    170 zeroForOne bool,
    171) *u256.Uint {
    172 if sqrtPX96.IsZero() {
    173 panic(errSqrtPriceZero)
    174 }
    175
    176 if liquidity.IsZero() {
    177 panic(errLiquidityZero)
    178 }
    179
    180 if zeroForOne {
    181 return getNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountIn, true)
    182 }
    183
    184 return getNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountIn, true)
    185}
    186
    187// getNextSqrtPriceFromOutput calculates the next sqrt price after removing tokens from the pool,
    188// using different rounding directions based on swap direction.
    189// The zeroForOne parameter indicates swap direction (token0 for token1 when true).
    190// Panics if sqrtPX96 or liquidity is zero.
    191func getNextSqrtPriceFromOutput(
    192 sqrtPX96, liquidity, amountOut *u256.Uint,
    193 zeroForOne bool,
    194) *u256.Uint {
    195 if sqrtPX96.IsZero() {
    196 panic(errSqrtPriceZero)
    197 }
    198
    199 if liquidity.IsZero() {
    200 panic(errLiquidityZero)
    201 }
    202
    203 if zeroForOne {
    204 return getNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountOut, false)
    205 }
    206
    207 return getNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountOut, false)
    208}
    209
    210// getAmount0DeltaHelper calculates the absolute token0 amount difference between two price ranges,
    211// automatically swapping inputs to ensure correct ordering. The roundUp parameter controls
    212// rounding direction for the final result to ensure conservative AMM calculations.
    213// Panics if sqrtRatioAX96 is zero.
    214func getAmount0DeltaHelper(
    215 sqrtRatioAX96, sqrtRatioBX96, liquidity *u256.Uint,
    216 roundUp bool,
    217) *u256.Uint {
    218 if sqrtRatioAX96.Gt(sqrtRatioBX96) {
    219 sqrtRatioAX96, sqrtRatioBX96 = sqrtRatioBX96, sqrtRatioAX96
    220 }
    221
    222 // Use local variables for thread safety
    223 numerator := u256.Zero().Lsh(liquidity, Q96_RESOLUTION)
    224 difference := u256.Zero().Sub(sqrtRatioBX96, sqrtRatioAX96)
    225
    226 if sqrtRatioAX96.IsZero() {
    227 panic(errSqrtRatioAX96Zero)
    228 }
    229
    230 if roundUp {
    231 intermediate := u256.MulDivRoundingUp(numerator, difference, sqrtRatioBX96)
    232 return u256.DivRoundingUp(intermediate, sqrtRatioAX96)
    233 }
    234
    235 intermediate := u256.MulDiv(numerator, difference, sqrtRatioBX96)
    236 return u256.Zero().Div(intermediate, sqrtRatioAX96)
    237}
    238
    239// getAmount1DeltaHelper calculates the absolute token1 amount difference between two price ranges,
    240// automatically swapping inputs to ensure correct ordering. The roundUp parameter controls
    241// rounding direction for the final result to ensure conservative AMM calculations.
    242func getAmount1DeltaHelper(
    243 sqrtRatioAX96, sqrtRatioBX96, liquidity *u256.Uint,
    244 roundUp bool,
    245) *u256.Uint {
    246 if sqrtRatioAX96.Gt(sqrtRatioBX96) {
    247 sqrtRatioAX96, sqrtRatioBX96 = sqrtRatioBX96, sqrtRatioAX96
    248 }
    249
    250 // amount1 = liquidity * (sqrtB - sqrtA) / 2^96
    251 // Use local variable for thread safety
    252 difference := u256.Zero().Sub(sqrtRatioBX96, sqrtRatioAX96)
    253
    254 if roundUp {
    255 return u256.MulDivRoundingUp(liquidity, difference, consts.Q96())
    256 }
    257
    258 return u256.MulDiv(liquidity, difference, consts.Q96())
    259}
    260
    261// GetAmount0Delta computes the signed token0 amount represented between two prices.
    262// Positive liquidity rounds the amount up; negative liquidity returns a negative amount
    263// rounded down after applying the magnitude.
    264//
    265// Parameters:
    266// - sqrtRatioAX96: First price endpoint in Q64.96 square-root format.
    267// - sqrtRatioBX96: Second price endpoint in Q64.96 square-root format.
    268// - liquidity: Signed liquidity value; its sign determines the result sign and rounding.
    269//
    270// Returns:
    271// - amount0Delta: Signed int256 token0 amount represented by the range.
    272//
    273// Panics if an input is nil or the computed magnitude cannot be represented by int256.
    274func GetAmount0Delta(
    275 sqrtRatioAX96, sqrtRatioBX96 *u256.Uint,
    276 liquidity *i256.Int,
    277) *i256.Int {
    278 if sqrtRatioAX96 == nil || sqrtRatioBX96 == nil || liquidity == nil {
    279 panic(errGetAmount0DeltaNilInput)
    280 }
    281
    282 if liquidity.IsNeg() {
    283 u := getAmount0DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs(), false)
    284 if u.Gt(consts.MaxInt256()) {
    285 // if u > (2**255 - 1), cannot cast to int256
    286 panic(errAmount0DeltaOverflow)
    287 }
    288
    289 // Convert to i256 and negate properly
    290 return i256.Zero().Neg(i256.FromUint256(u))
    291 }
    292
    293 u := getAmount0DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs(), true)
    294 if u.Gt(consts.MaxInt256()) {
    295 // if u > (2**255 - 1), cannot cast to int256
    296 panic(errAmount0DeltaOverflow)
    297 }
    298
    299 return i256.FromUint256(u)
    300}
    301
    302// GetAmount1Delta computes the signed token1 amount represented between two prices.
    303// Positive liquidity rounds the amount up; negative liquidity returns a negative amount
    304// rounded down after applying the magnitude.
    305//
    306// Parameters:
    307// - sqrtRatioAX96: First price endpoint in Q64.96 square-root format.
    308// - sqrtRatioBX96: Second price endpoint in Q64.96 square-root format.
    309// - liquidity: Signed liquidity value; its sign determines the result sign and rounding.
    310//
    311// Returns:
    312// - amount1Delta: Signed int256 token1 amount represented by the range.
    313//
    314// Panics if an input is nil or the computed magnitude cannot be represented by int256.
    315func GetAmount1Delta(
    316 sqrtRatioAX96, sqrtRatioBX96 *u256.Uint,
    317 liquidity *i256.Int,
    318) *i256.Int {
    319 if sqrtRatioAX96 == nil || sqrtRatioBX96 == nil || liquidity == nil {
    320 panic(errGetAmount1DeltaNilInput)
    321 }
    322
    323 if liquidity.IsNeg() {
    324 u := getAmount1DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs(), false)
    325 if u.Gt(consts.MaxInt256()) {
    326 // if u > (2**255 - 1), cannot cast to int256
    327 panic(errAmount1DeltaOverflow)
    328 }
    329
    330 // Convert to i256 and negate properly
    331 return i256.Zero().Neg(i256.FromUint256(u))
    332 }
    333
    334 u := getAmount1DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs(), true)
    335 if u.Gt(consts.MaxInt256()) {
    336 // if u > (2**255 - 1), cannot cast to int256
    337 panic(errAmount1DeltaOverflow)
    338 }
    339
    340 return i256.FromUint256(u)
    341}
    342