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

swap_inner.gno

3.26 Kb · 126 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	assertIsRouterProxyRealm(0, rlm)
 30
 31	token0Path, token1Path := data.tokenIn, data.tokenOut
 32	zeroForOne := data.tokenIn < data.tokenOut
 33
 34	if !zeroForOne {
 35		token0Path, token1Path = token1Path, token0Path
 36	}
 37
 38	sqrtPriceLimitStr := calculateSqrtPriceLimitToStr(zeroForOne, sqrtPriceLimitX96)
 39
 40	amount0Str, amount1Str := pl.Swap(
 41		cross(rlm),
 42		token0Path,
 43		token1Path,
 44		data.fee,
 45		recipient,
 46		zeroForOne,
 47		utils.FormatInt(amountSpecified),
 48		sqrtPriceLimitStr,
 49		func(cur realm, amount0Delta, amount1Delta int64, _ *pl.CallbackMarker) error {
 50			// assert is pool to prevent unauthorized callback
 51			caller := cur.Previous().Address()
 52			access.AssertIsPool(caller)
 53
 54			return router.SwapCallback(cross(cur), token0Path, token1Path, amount0Delta, amount1Delta, data.payer)
 55		},
 56	)
 57
 58	amount0 := i256.MustFromDecimal(amount0Str)
 59	amount1 := i256.MustFromDecimal(amount1Str)
 60
 61	poolOut, poolRecv := i256MinMax(amount0, amount1)
 62	if poolRecv.IsOverflow() || poolOut.IsOverflow() {
 63		panic("overflow in swapInner")
 64	}
 65
 66	return poolRecv.Int64(), poolOut.Int64()
 67}
 68
 69// swapDryInner performs a dry-run of a swap operation without executing it.
 70func (r *routerV1) swapDryInner(
 71	amountSpecified int64,
 72	sqrtPriceLimitX96 *u256.Uint,
 73	data SwapCallbackData,
 74) (int64, int64) {
 75	token0Path, token1Path := data.tokenIn, data.tokenOut
 76	zeroForOne := data.tokenIn < data.tokenOut
 77
 78	if !zeroForOne {
 79		token0Path, token1Path = token1Path, token0Path
 80	}
 81
 82	sqrtPriceLimitStr := calculateSqrtPriceLimitToStr(zeroForOne, sqrtPriceLimitX96)
 83
 84	// check possible
 85	amount0Str, amount1Str, err := pl.DrySwap(
 86		token0Path,
 87		token1Path,
 88		data.fee,
 89		zeroForOne,
 90		utils.FormatInt(amountSpecified),
 91		sqrtPriceLimitStr,
 92	)
 93	if err != nil {
 94		panic(err)
 95	}
 96
 97	amount0 := i256.MustFromDecimal(amount0Str)
 98	amount1 := i256.MustFromDecimal(amount1Str)
 99	if amount0.Sign() <= 0 && amount1.Sign() <= 0 {
100		panic(makeErrorWithDetails(
101			errInsufficientLiquidity,
102			"swap entirely within 0-liquidity region",
103		))
104	}
105
106	poolOut, poolRecv := i256MinMax(amount0, amount1)
107	if poolRecv.IsOverflow() || poolOut.IsOverflow() {
108		panic("overflow in swapDryInner")
109	}
110
111	return poolRecv.Int64(), poolOut.Int64()
112}
113
114// calculateSqrtPriceLimitToStr returns the price-limit string for a swap operation.
115// A non-zero caller limit is formatted as-is; a zero limit uses the global
116// TickMath boundary for the swap direction.
117func calculateSqrtPriceLimitToStr(zeroForOne bool, sqrtPriceLimitX96 *u256.Uint) string {
118	if !sqrtPriceLimitX96.IsZero() {
119		return sqrtPriceLimitX96.ToString()
120	}
121
122	if zeroForOne {
123		return MIN_SQRT_RATIO_PLUS_ONE
124	}
125	return MAX_SQRT_RATIO_MINUS_ONE
126}