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

swap_inner.gno

3.23 Kb · 124 lines
  1package router
  2
  3import (
  4	"gno.land/r/gnoswap/access/v1"
  5	"gno.land/r/gnoswap/router"
  6
  7	i256 "gno.land/p/gnoswap/int256/v1"
  8	u256 "gno.land/p/gnoswap/uint256/v1"
  9	"gno.land/p/gnoswap/utils/v1"
 10
 11	pl "gno.land/r/gnoswap/pool"
 12)
 13
 14const (
 15	MIN_SQRT_RATIO_PLUS_ONE  string = "4295128740"
 16	MAX_SQRT_RATIO_MINUS_ONE string = "1461446703485210103287273052203988822378723970341"
 17)
 18
 19// swapInner executes the core swap logic by interacting with the pool contract.
 20// Returns poolRecv (tokens received by pool) and poolOut (tokens sent by pool).
 21func (r *routerV1) swapInner(
 22	_ int,
 23	rlm realm,
 24	amountSpecified int64,
 25	recipient address,
 26	sqrtPriceLimitX96 *u256.Uint,
 27	data SwapCallbackData,
 28) (int64, int64) {
 29	token0Path, token1Path := data.tokenIn, data.tokenOut
 30	zeroForOne := data.tokenIn < data.tokenOut
 31
 32	if !zeroForOne {
 33		token0Path, token1Path = token1Path, token0Path
 34	}
 35
 36	sqrtPriceLimitStr := calculateSqrtPriceLimitToStr(zeroForOne, sqrtPriceLimitX96)
 37
 38	amount0Str, amount1Str := pl.Swap(
 39		cross(rlm),
 40		token0Path,
 41		token1Path,
 42		data.fee,
 43		recipient,
 44		zeroForOne,
 45		utils.FormatInt(amountSpecified),
 46		sqrtPriceLimitStr,
 47		func(cur realm, amount0Delta, amount1Delta int64, _ *pl.CallbackMarker) error {
 48			// assert is pool to prevent unauthorized callback
 49			caller := cur.Previous().Address()
 50			access.AssertIsPool(caller)
 51
 52			return router.SwapCallback(cross(cur), token0Path, token1Path, amount0Delta, amount1Delta, data.payer)
 53		},
 54	)
 55
 56	amount0 := i256.MustFromDecimal(amount0Str)
 57	amount1 := i256.MustFromDecimal(amount1Str)
 58
 59	poolOut, poolRecv := i256MinMax(amount0, amount1)
 60	if poolRecv.IsOverflow() || poolOut.IsOverflow() {
 61		panic("overflow in swapInner")
 62	}
 63
 64	return poolRecv.Int64(), poolOut.Int64()
 65}
 66
 67// swapDryInner performs a dry-run of a swap operation without executing it.
 68func (r *routerV1) swapDryInner(
 69	amountSpecified int64,
 70	sqrtPriceLimitX96 *u256.Uint,
 71	data SwapCallbackData,
 72) (int64, int64) {
 73	token0Path, token1Path := data.tokenIn, data.tokenOut
 74	zeroForOne := data.tokenIn < data.tokenOut
 75
 76	if !zeroForOne {
 77		token0Path, token1Path = token1Path, token0Path
 78	}
 79
 80	sqrtPriceLimitStr := calculateSqrtPriceLimitToStr(zeroForOne, sqrtPriceLimitX96)
 81
 82	// check possible
 83	amount0Str, amount1Str, err := pl.DrySwap(
 84		token0Path,
 85		token1Path,
 86		data.fee,
 87		zeroForOne,
 88		utils.FormatInt(amountSpecified),
 89		sqrtPriceLimitStr,
 90	)
 91	if err != nil {
 92		panic(err)
 93	}
 94
 95	amount0 := i256.MustFromDecimal(amount0Str)
 96	amount1 := i256.MustFromDecimal(amount1Str)
 97	if amount0.Sign() <= 0 && amount1.Sign() <= 0 {
 98		panic(makeErrorWithDetails(
 99			errInsufficientLiquidity,
100			"swap entirely within 0-liquidity region",
101		))
102	}
103
104	poolOut, poolRecv := i256MinMax(amount0, amount1)
105	if poolRecv.IsOverflow() || poolOut.IsOverflow() {
106		panic("overflow in swapDryInner")
107	}
108
109	return poolRecv.Int64(), poolOut.Int64()
110}
111
112// calculateSqrtPriceLimitToStr returns the price-limit string for a swap operation.
113// A non-zero caller limit is formatted as-is; a zero limit uses the global
114// TickMath boundary for the swap direction.
115func calculateSqrtPriceLimitToStr(zeroForOne bool, sqrtPriceLimitX96 *u256.Uint) string {
116	if !sqrtPriceLimitX96.IsZero() {
117		return sqrtPriceLimitX96.ToString()
118	}
119
120	if zeroForOne {
121		return MIN_SQRT_RATIO_PLUS_ONE
122	}
123	return MAX_SQRT_RATIO_MINUS_ONE
124}