Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

gnsmath source pure

Package gnsmath provides core mathematical operations for GnoSwap's concentrated liquidity AMM.

Readme View source

gnsmath

Core mathematical operations for GnoSwap's concentrated liquidity AMM.

Overview

This package provides the fundamental calculations for concentrated liquidity, including tick conversion, liquidity math calculations, sqrt price math, swap calculations, and bit manipulation utilities. All operations use Q96 and Q160 fixed-point arithmetic for precision.

The implementation follows Uniswap V3's mathematical model, ensuring compatibility and correctness for cross-chain liquidity operations.

Features

  • Bit Math: MSB/LSB calculations for tick bitmap operations
  • Tick Math: Tick and Q64.96 sqrt-price conversions
  • Liquidity Math: Liquidity and token amount conversions for price ranges
  • Sqrt Price Math: Token amount conversions using Q64.96 format
  • Swap Math: Single-step swap calculations with fee handling
  • Overflow Protection: Built-in int256 overflow detection
  • Rounding Control: Configurable rounding for AMM safety

Core Concepts

Q96 Fixed-Point Format

Square root prices use Q64.96 representation:

  • sqrtPriceX96 = sqrt(token1/token0) * 2^96
  • Enables precise integer arithmetic without floating-point

Rounding Directions

  • Round UP: Amounts owed TO pool (deposits, exact input)
  • Round DOWN: Amounts owed FROM pool (withdrawals, exact output)

Usage

 1import (
 2    "gno.land/p/gnoswap/gnsmath"
 3    i256 "gno.land/p/gnoswap/int256"
 4    u256 "gno.land/p/gnoswap/uint256"
 5)
 6
 7// Calculate token amounts for liquidity change
 8sqrtPriceA := u256.MustFromDecimal("79228162514264337593543950336")
 9sqrtPriceB := u256.MustFromDecimal("79625275426524748796330556128")
10liquidity := i256.MustFromDecimal("1000000000000000000")
11
12amount0 := gnsmath.GetAmount0Delta(sqrtPriceA, sqrtPriceB, liquidity)
13amount1 := gnsmath.GetAmount1Delta(sqrtPriceA, sqrtPriceB, liquidity)
14
15// Compute swap step
16feePips := uint64(3000) // 0.3% fee
17sqrtPriceNext, amountIn, amountOut, feeAmount := gnsmath.SwapMathComputeSwapStep(
18    currentPrice,
19    targetPrice,
20    liquidity,
21    amountRemaining,
22    feePips,
23)
24
25// Bit operations for tick bitmap
26tickBitmap := u256.NewUint(0xFF00)
27msb := gnsmath.BitMathMostSignificantBit(tickBitmap)
28println(msb) // Output: 15
29
30lsb := gnsmath.BitMathLeastSignificantBit(tickBitmap)
31println(lsb) // Output: 8

API

Bit Math

  • BitMathMostSignificantBit(x *u256.Uint) uint8 - Find MSB position (0-255)
  • BitMathLeastSignificantBit(x *u256.Uint) uint8 - Find LSB position (0-255)

Tick Math

  • TickMathGetSqrtRatioAtTick(tick int32) *u256.Uint - Convert tick to Q64.96 sqrt price
  • TickMathGetTickAtSqrtRatio(sqrtPriceX96 *u256.Uint) int32 - Convert Q64.96 sqrt price to tick

Liquidity Math

  • GetLiquidityForAmounts(sqrtRatioX96, sqrtRatioAX96, sqrtRatioBX96, amount0, amount1 *u256.Uint) *u256.Uint
    • Calculate max liquidity from token amounts and price range
  • GetAmountsForLiquidity(sqrtRatioX96, sqrtRatioAX96, sqrtRatioBX96, liquidity *u256.Uint) (*u256.Uint, *u256.Uint)
    • Calculate token amounts represented by liquidity and price range
  • LiquidityMathAddDelta(x *u256.Uint, y *i256.Int) *u256.Uint
    • Apply signed liquidity delta with overflow/underflow protection

Sqrt Price Math

  • GetAmount0Delta(sqrtRatioAX96, sqrtRatioBX96 *u256.Uint, liquidity *i256.Int) *i256.Int
    • Calculate token0 amount: liquidity * (1/√Pb - 1/√Pa)
  • GetAmount1Delta(sqrtRatioAX96, sqrtRatioBX96 *u256.Uint, liquidity *i256.Int) *i256.Int
    • Calculate token1 amount: liquidity * (√Pb - √Pa)

Swap Math

  • SwapMathComputeSwapStep(sqrtRatioCurrentX96, sqrtRatioTargetX96, liquidity *u256.Uint, amountRemaining *i256.Int, feePips uint64) (*u256.Uint, *u256.Uint, *u256.Uint, *u256.Uint)
    • Returns: (nextSqrtPrice, amountIn, amountOut, feeAmount)
    • Handles both exact input and exact output swaps

Overview

Package gnsmath provides core mathematical operations for GnoSwap's concentrated liquidity AMM.

## Overview

This package provides the fundamental calculations for concentrated liquidity, including tick conversion, liquidity math calculations, sqrt price math, swap calculations, and bit manipulation utilities. All operations use Q64.96, Q128.128, and Q160 fixed-point arithmetic where appropriate.

The implementation follows Uniswap V3's mathematical model.

## Features

  • Bit Math: MSB/LSB calculations for tick bitmap operations
  • Tick Math: tick and Q64.96 sqrt-price conversions
  • Liquidity Math: liquidity and token amount math for price ranges
  • Sqrt Price Math: token amount conversions using Q64.96 format
  • Swap Math: single-step swap calculations with fee handling
  • Overflow Protection: explicit int256/uint256 overflow checks
  • Rounding Control: configurable rounding for AMM safety

## Core Concepts

### Q64.96 Fixed-Point Format

Square root prices use Q64.96 representation:

  • sqrtPriceX96 = sqrt(token1/token0) * 2^96
  • Enables precise integer arithmetic without floating-point

### Rounding Directions

  • Round UP: amounts owed TO pool (deposits, exact input)
  • Round DOWN: amounts owed FROM pool (withdrawals, exact output)

## API

### Bit Math

  • BitMathMostSignificantBit(x *u256.Uint) uint8
  • BitMathLeastSignificantBit(x *u256.Uint) uint8

### Tick Math

  • TickMathGetSqrtRatioAtTick(tick int32) *u256.Uint
  • TickMathGetTickAtSqrtRatio(sqrtPriceX96 *u256.Uint) int32

### Liquidity Math

  • GetLiquidityForAmounts(sqrtRatioX96, sqrtRatioAX96, sqrtRatioBX96, amount0, amount1 *u256.Uint) *u256.Uint
  • GetAmountsForLiquidity(sqrtRatioX96, sqrtRatioAX96, sqrtRatioBX96, liquidity *u256.Uint) (*u256.Uint, *u256.Uint)
  • LiquidityMathAddDelta(x *u256.Uint, y *i256.Int) *u256.Uint

### Sqrt Price Math

  • GetAmount0Delta(sqrtRatioAX96, sqrtRatioBX96 *u256.Uint, liquidity *i256.Int) *i256.Int
  • GetAmount1Delta(sqrtRatioAX96, sqrtRatioBX96 *u256.Uint, liquidity *i256.Int) *i256.Int

### Swap Math

  • SwapMathComputeSwapStep(sqrtRatioCurrentX96, sqrtRatioTargetX96, liquidity *u256.Uint, amountRemaining *i256.Int, feePips uint64) (*u256.Uint, *u256.Uint, *u256.Uint, *u256.Uint)

Constants 1

const minTick, maxTick, Q96_RESOLUTION, Q160_RESOLUTION, MAX_UINT128, Q96

 1const (
 2	// minTick is the minimum valid tick index in the concentrated liquidity model.
 3	// Represents the lowest possible price: 1.0001^(-887272) ≈ 0
 4	minTick = -887272
 5
 6	// maxTick is the maximum valid tick index in the concentrated liquidity model.
 7	// Represents the highest possible price: 1.0001^887272 ≈ infinity
 8	maxTick = 887272
 9
10	Q96_RESOLUTION  uint = 96
11	Q160_RESOLUTION uint = 160
12
13	MAX_UINT128 = "340282366920938463463374607431768211455" // 2^128 - 1
14	Q96         = "79228162514264337593543950336"           // 2^96
15)
source

Functions 24

func BitMathLeastSignificantBit

1func BitMathLeastSignificantBit(x *u256.Uint) uint8
source

BitMathLeastSignificantBit returns the 0-based position of the least significant bit in x. This function is used in AMM calculations for efficient bit manipulation and range queries.

Parameters:

  • x: the value for which to compute the least significant bit

Returns the index of the least significant bit (0-255).

Panics if x is zero.

func BitMathMostSignificantBit

1func BitMathMostSignificantBit(x *u256.Uint) uint8
source

BitMathMostSignificantBit returns the 0-based position of the most significant bit in x. This function is essential for AMM calculations involving price ranges and tick boundaries.

Parameters:

  • x: the value for which to compute the most significant bit

Returns the index of the most significant bit (0-255).

Panics if x is zero.

func GetAmount0Delta

1func GetAmount0Delta(
2	sqrtRatioAX96, sqrtRatioBX96 *u256.Uint,
3	liquidity *i256.Int,
4) *i256.Int
source

GetAmount0Delta calculates the token0 amount difference within a price range, returning a signed int256 value that is negative when liquidity is negative. Rounds down for negative liquidity and up for positive liquidity.

Parameters:

  • sqrtRatioAX96: first sqrt price in Q96 format
  • sqrtRatioBX96: second sqrt price in Q96 format
  • liquidity: signed liquidity value

Returns the token0 amount difference as a signed int256 value.

Panics if any input is nil or if the result overflows int256.

func GetAmount1Delta

1func GetAmount1Delta(
2	sqrtRatioAX96, sqrtRatioBX96 *u256.Uint,
3	liquidity *i256.Int,
4) *i256.Int
source

GetAmount1Delta calculates the token1 amount difference within a price range, returning a signed int256 value that is negative when liquidity is negative. Rounds down for negative liquidity and up for positive liquidity.

Parameters:

  • sqrtRatioAX96: first sqrt price in Q96 format
  • sqrtRatioBX96: second sqrt price in Q96 format
  • liquidity: signed liquidity value

Returns the token1 amount difference as a signed int256 value.

Panics if any input is nil or if the result overflows int256.

func GetAmountsForLiquidity

1func GetAmountsForLiquidity(sqrtRatioX96, sqrtRatioAX96, sqrtRatioBX96, liquidity *u256.Uint) (*u256.Uint, *u256.Uint)
source

GetAmountsForLiquidity calculates the amounts of token0 and token1 required to provide a specified liquidity within a price range.

This function determines the quantities of token0 and token1 necessary to achieve a given liquidity level, depending on the current price (sqrtRatioX96) and the bounds of the price range (sqrtRatioAX96 and sqrtRatioBX96). The function returns the calculated amounts of token0 and token1 as strings.

If the current price is below the lower bound of the price range, only token0 is required. If the current price is above the upper bound, only token1 is required. When the price is within the range, both token0 and token1 are calculated.

Parameters: - sqrtRatioX96: The current price represented as a square root ratio in Q64.96 format (*u256.Uint). - sqrtRatioAX96: The lower bound of the price range as a square root ratio in Q64.96 format (*u256.Uint). - sqrtRatioBX96: The upper bound of the price range as a square root ratio in Q64.96 format (*u256.Uint). - liquidity: The amount of liquidity to be provided (*u256.Uint).

Returns: - string: The calculated amount of token0 required to achieve the specified liquidity. - string: The calculated amount of token1 required to achieve the specified liquidity.

Notes:

  • If liquidity is zero, the function returns "0" for both token0 and token1.
  • The function guarantees that sqrtRatioAX96 is always the lower bound and sqrtRatioBX96 is the upper bound by calling toAscendingOrder().
  • Edge cases where the current price is exactly on the bounds are handled without division by zero.

Example: ``` amount0, amount1 := GetAmountsForLiquidity(

Example
1u256.MustFromDecimal("79228162514264337593543950336"),  // sqrtRatioX96 (1.0 in Q64.96)
2u256.MustFromDecimal("39614081257132168796771975168"),  // sqrtRatioAX96 (0.5 in Q64.96)
3u256.MustFromDecimal("158456325028528675187087900672"), // sqrtRatioBX96 (2.0 in Q64.96)
4u256.MustFromDecimal("1000000"),                        // Liquidity

)

println("Token0:", amount0, "Token1:", amount1)

// Output: Token0: 500000, Token1: 250000 ```

func GetLiquidityForAmounts

1func GetLiquidityForAmounts(sqrtRatioX96, sqrtRatioAX96, sqrtRatioBX96, amount0, amount1 *u256.Uint) (liquidity *u256.Uint)
source

GetLiquidityForAmounts calculates the maximum liquidity given the current price (sqrtRatioX96), upper and lower price bounds (sqrtRatioAX96 and sqrtRatioBX96), and token amounts (amount0, amount1).

This function evaluates how much liquidity can be obtained for specified amounts of token0 and token1 within the provided price range. It returns the lesser liquidity based on available token0 or token1 to ensure the pool remains balanced.

Parameters: - sqrtRatioX96: The current price as a square root ratio in Q64.96 format (*u256.Uint). - sqrtRatioAX96: The lower bound of the price range as a square root ratio in Q64.96 format (*u256.Uint). - sqrtRatioBX96: The upper bound of the price range as a square root ratio in Q64.96 format (*u256.Uint). - amount0: The amount of token0 available to provide liquidity (*u256.Uint). - amount1: The amount of token1 available to provide liquidity (*u256.Uint).

Returns: - *u256.Uint: The maximum possible liquidity that can be minted.

Notes:

  • The `Clone` method is used to prevent modification of the original values during computation.
  • The function ensures that liquidity calculations handle edge cases when the current price is outside the specified range by returning liquidity based on the dominant token.

func LiquidityMathAddDelta

1func LiquidityMathAddDelta(x *u256.Uint, y *i256.Int) *u256.Uint
source

LiquidityMathAddDelta calculates the new liquidity by applying the delta liquidity to the current liquidity. If delta liquidity is negative, it subtracts the absolute value of delta liquidity from the current liquidity. If delta liquidity is positive, it adds the absolute value of delta liquidity to the current liquidity.

Parameters:

  • x: current liquidity as unsigned 256-bit integer
  • y: delta liquidity as signed 256-bit integer (positive to add, negative to subtract)

Returns the new liquidity as a uint256 value.

Panics if x or y is nil, or if the operation would result in underflow or overflow.

func MAX_SQRT_RATIO

1func MAX_SQRT_RATIO() *u256.Uint
source

MAX_SQRT_RATIO returns the maximum valid sqrt price ratio (1461446703485210103287273052203988822378723970342). See MIN_SQRT_RATIO.

func MIN_SQRT_RATIO

1func MIN_SQRT_RATIO() *u256.Uint
source

MIN_SQRT_RATIO returns the minimum valid sqrt price ratio (4295128739). It is a constructor (not a package-level var) so each caller receives a fresh instance rather than sharing a mutable singleton.

func MaxInt128

1func MaxInt128() *i256.Int
source

maxInt128 is the largest value representable in a signed 128-bit integer. It is used by SafeConvertToInt128 to bound liquidity deltas.

func SafeAbsInt64

1func SafeAbsInt64(a int64) int64
source

SafeAbsInt64 returns the absolute value of a, panicking when a is math.MinInt64 since its absolute value is not representable in int64.

func SafeAddInt64

1func SafeAddInt64(a, b int64) int64
source

SafeAddInt64 returns a + b, panicking on int64 overflow or underflow.

func SafeAddUint64

1func SafeAddUint64(a, b uint64) uint64
source

SafeAddUint64 returns a + b, panicking on uint64 overflow.

func SafeConvertToInt128

1func SafeConvertToInt128(value *u256.Uint) *i256.Int
source

SafeConvertToInt128 converts a *u256.Uint to an *i256.Int, panicking when the value exceeds the signed int128 range (2^127 - 1).

func SafeConvertToInt64

1func SafeConvertToInt64(value *u256.Uint) int64
source

SafeConvertToInt64 converts a *u256.Uint to int64, panicking when the value is nil or exceeds the int64 range (2^63 - 1).

func SafeConvertToUint128

1func SafeConvertToUint128(value *u256.Uint) *u256.Uint
source

SafeConvertToUint128 safely ensures a *u256.Uint value fits within the uint128 range.

This function verifies that the provided unsigned 256-bit integer does not exceed the maximum value for uint128 (`2^128 - 1`). If the value is within the uint128 range, it is returned as is; otherwise, the function triggers a panic.

Parameters: - value (*u256.Uint): The unsigned 256-bit integer to be checked.

Returns: - *u256.Uint: The same value if it is within the uint128 range.

Panics:

  • If the value exceeds the maximum uint128 value (`2^128 - 1`), the function will panic with a descriptive error indicating the overflow and the original value.

Notes: - The constant `MAX_UINT128` is defined as `340282366920938463463374607431768211455` (the largest uint128 value). - No actual conversion occurs since the function works directly with *u256.Uint types.

Example: validUint128 := SafeConvertToUint128(u256.MustFromDecimal("340282366920938463463374607431768211455")) // Valid SafeConvertToUint128(u256.MustFromDecimal("340282366920938463463374607431768211456")) // Panics due to overflow

func SafeMulDivInt64

1func SafeMulDivInt64(a, b, c int64) int64
source

SafeMulDivInt64 returns (a * b) / c, computing the intermediate product in 256-bit signed arithmetic so a*b need not fit in int64. The final quotient must fit in int64, otherwise it panics. It panics on overflow.

func SafeMulInt64

1func SafeMulInt64(a, b int64) int64
source

SafeMulInt64 returns a * b, panicking on int64 overflow or underflow.

func SafeSubInt64

1func SafeSubInt64(a, b int64) int64
source

SafeSubInt64 returns a - b, panicking on int64 overflow or underflow.

func SafeSubUint64

1func SafeSubUint64(a, b uint64) uint64
source

SafeSubUint64 returns a - b, panicking on uint64 underflow.

func SafeUint64ToInt64

1func SafeUint64ToInt64(value uint64) int64
source

SafeUint64ToInt64 converts a uint64 to int64, panicking when the value exceeds the int64 range (2^63 - 1).

func SwapMathComputeSwapStep

1func SwapMathComputeSwapStep(
2	sqrtRatioCurrentX96 *u256.Uint,
3	sqrtRatioTargetX96 *u256.Uint,
4	liquidity *u256.Uint,
5	amountRemaining *i256.Int,
6	feePips uint64,
7) (*u256.Uint, *u256.Uint, *u256.Uint, *u256.Uint)
source

SwapMathComputeSwapStep computes the next sqrt price, amount in, amount out, and fee amount for a swap step within a single tick range.

Parameters:

  • sqrtRatioCurrentX96: current sqrt price in Q96 format
  • sqrtRatioTargetX96: target sqrt price (tick boundary)
  • liquidity: available liquidity in the range
  • amountRemaining: amount left to swap (positive=exact in, negative=exact out)
  • feePips: fee in hundredths of a bip (3000 = 0.3%)

Returns sqrtRatioNextX96, amountIn, amountOut, feeAmount.

Panics if any input parameter is nil or if feePips >= 1000000.

func TickMathGetSqrtRatioAtTick

1func TickMathGetSqrtRatioAtTick(tick int32) *u256.Uint
source

TickMathGetSqrtRatioAtTick calculates sqrt price ratio for given tick.

Converts tick index to square root price in Q64.96 fixed-point format. Based on Uniswap V3's mathematical formula: price = 1.0001^tick. Uses bit manipulation for gas-efficient calculation.

Parameters:

  • tick: Tick index in range [-887272, 887272]

Returns:

  • Square root of price ratio as Q64.96 fixed-point
  • Result represents sqrt(token1/token0) price

Mathematical formula:

Example
1sqrtPriceX96 = sqrt(1.0001^tick) * 2^96

Panics if tick outside valid range. Critical for all price calculations in concentrated liquidity.

func TickMathGetTickAtSqrtRatio

1func TickMathGetTickAtSqrtRatio(sqrtPriceX96 *u256.Uint) int32
source

TickMathGetTickAtSqrtRatio calculates the tick index for a given square root price ratio.

Converts a square root price ratio in Q64.96 format back to its tick index, returning the greatest tick where TickMathGetSqrtRatioAtTick(tick) <= sqrtPriceX96. This matches Uniswap V3's behavior exactly.

Parameters:

  • sqrtPriceX96: Square root price ratio in Q64.96 format

Returns:

  • Tick index corresponding to the price

Algorithm:

  1. Scales ratio from Q64.96 to Q96.128 by left-shifting 32 bits
  2. Finds MSB (most significant bit) to determine magnitude
  3. Calculates log_2 using fixed-point arithmetic
  4. Converts log_2 to log_sqrt(1.0001) to get tick
  5. Returns appropriate tick based on bounds checking

Panics if sqrtPriceX96 is nil or outside valid range [minSqrtRatio, maxSqrtRatio). Critical for converting prices to ticks for position management.

Imports 6

Source Files 11