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

reposition.gno

5.38 Kb · 160 lines
  1package position
  2
  3import (
  4	"chain"
  5
  6	"gno.land/r/gnoswap/access/v1"
  7
  8	u256 "gno.land/p/gnoswap/uint256/v1"
  9	"gno.land/p/gnoswap/utils/v1"
 10	ufmt "gno.land/p/nt/ufmt/v0"
 11
 12	"gno.land/r/gnoswap/common"
 13	"gno.land/r/gnoswap/emission"
 14	"gno.land/r/gnoswap/halt/v1"
 15)
 16
 17// Reposition adjusts the price range and liquidity of an existing position.
 18//
 19// Parameters:
 20//   - _: leading integer discriminator; callers pass 0
 21//   - rlm: current realm context forwarded from the public wrapper; the implementation validates it as current
 22//   - positionId: NFT token ID to reposition
 23//   - tickLower: new lower tick boundary of the position's price range
 24//   - tickUpper: new upper tick boundary of the position's price range
 25//   - amount0DesiredStr: desired token0 amount for the new position, represented as a decimal string
 26//   - amount1DesiredStr: desired token1 amount for the new position, represented as a decimal string
 27//   - amount0MinStr: minimum acceptable token0 amount for slippage protection
 28//   - amount1MinStr: minimum acceptable token1 amount for slippage protection
 29//   - deadline: transaction expiration timestamp
 30//
 31// Returns:
 32//   - positionId: NFT token ID that was repositioned
 33//   - liquidity: new liquidity amount, represented as a decimal string
 34//   - tickLower: lower tick boundary applied to the position
 35//   - tickUpper: upper tick boundary applied to the position
 36//   - amount0: actual token0 amount added to the new range, represented as a decimal string
 37//   - amount1: actual token1 amount added to the new range, represented as a decimal string
 38func (p *positionV1) Reposition(
 39	_ int,
 40	rlm realm,
 41	positionId uint64,
 42	tickLower int32,
 43	tickUpper int32,
 44	amount0DesiredStr string,
 45	amount1DesiredStr string,
 46	amount0MinStr string,
 47	amount1MinStr string,
 48	deadline int64,
 49) (uint64, string, int32, int32, string, string) {
 50	access.AssertIsRlmCurrent(0, rlm)
 51
 52	halt.AssertIsNotHaltedPosition()
 53
 54	previousRealm := rlm.Previous()
 55	caller := previousRealm.Address()
 56	assertIsOwnerForToken(p, positionId, caller)
 57	assertIsNotExpired(deadline)
 58
 59	emission.MintAndDistributeGns(cross(rlm))
 60
 61	// The position must be clear (zero liquidity and zero tokens owed) before
 62	// it can be repositioned.
 63	position := p.mustGetPosition(positionId)
 64
 65	token0, token1, _ := splitOf(position.PoolKey())
 66	common.AssertIsNotHandleNativeCoin()
 67
 68	oldTickLower := position.TickLower()
 69	oldTickUpper := position.TickUpper()
 70
 71	if !position.IsClear() {
 72		panic(newErrorWithDetail(
 73			errNotClear,
 74			ufmt.Sprintf(
 75				"position(%d) isn't clear(liquidity:%s, tokensOwed0:%d, tokensOwed1:%d)",
 76				positionId,
 77				position.Liquidity(),
 78				position.TokensOwed0(),
 79				position.TokensOwed1(),
 80			),
 81		))
 82	}
 83
 84	if err := validateTokenPath(token0, token1); err != nil {
 85		panic(newErrorWithDetail(err.Error(), ufmt.Sprintf("token0(%s), token1(%s)", token0, token1)))
 86	}
 87
 88	poolKey := position.PoolKey()
 89
 90	liquidity, amount0, amount1 := p.addLiquidity(
 91		0,
 92		rlm,
 93		AddLiquidityParams{
 94			poolKey:        poolKey,
 95			tickLower:      tickLower,
 96			tickUpper:      tickUpper,
 97			amount0Desired: u256.MustFromDecimal(amount0DesiredStr),
 98			amount1Desired: u256.MustFromDecimal(amount1DesiredStr),
 99			amount0Min:     u256.MustFromDecimal(amount0MinStr),
100			amount1Min:     u256.MustFromDecimal(amount1MinStr),
101			caller:         caller,
102		},
103	)
104
105	// update position tickLower, tickUpper to new value
106	// because getCurrentFeeGrowth() uses tickLower, tickUpper
107	position.SetTickLower(tickLower)
108	position.SetTickUpper(tickUpper)
109
110	currentFeeGrowth, err := p.getCurrentFeeGrowth(position, caller)
111	if err != nil {
112		panic(newErrorWithDetail(err.Error(), "failed to get current fee growth"))
113	}
114	position.SetFeeGrowthInside0LastX128(currentFeeGrowth.feeGrowthInside0LastX128.ToString())
115	position.SetFeeGrowthInside1LastX128(currentFeeGrowth.feeGrowthInside1LastX128.ToString())
116
117	position.SetLiquidity(liquidity.ToString())
118
119	// Do not reset the fee-growth checkpoints: a full decrease followed by
120	// repositioning must not create an unintended unclaimed-fee balance.
121	position.SetTokensOwed0(0)
122	position.SetTokensOwed1(0)
123	position.SetBurned(false)
124	p.mustUpdatePosition(0, rlm, positionId, *position)
125
126	pool := mustGetPool(poolKey)
127	positionLiquidity, err := p.GetPositionLiquidity(positionId)
128	if err != nil {
129		panic(err)
130	}
131	tickCumulative, secondsPerLiquidityCumulativeX128, observationTimestamp, err := currentPoolObservation(poolKey)
132	if err != nil {
133		panic(err)
134	}
135
136	chain.Emit(
137		"Reposition",
138		"prevAddr", previousRealm.Address().String(),
139		"prevRealm", previousRealm.PkgPath(),
140		"lpPositionId", utils.FormatUint(positionId),
141		"tickLower", utils.FormatInt(tickLower),
142		"tickUpper", utils.FormatInt(tickUpper),
143		"liquidityDelta", liquidity.ToString(),
144		"amount0", amount0.ToString(),
145		"amount1", amount1.ToString(),
146		"prevTickLower", utils.FormatInt(oldTickLower),
147		"prevTickUpper", utils.FormatInt(oldTickUpper),
148		"poolPath", poolKey,
149		"sqrtPriceX96", pool.Slot0SqrtPriceX96().ToString(),
150		"positionLiquidity", positionLiquidity,
151		"poolLiquidity", pool.Liquidity().ToString(),
152		"token0Balance", utils.FormatInt(pool.BalanceToken0()),
153		"token1Balance", utils.FormatInt(pool.BalanceToken1()),
154		"tickCumulative", utils.FormatInt(tickCumulative),
155		"secondsPerLiquidityCumulativeX128", secondsPerLiquidityCumulativeX128,
156		"observationTimestamp", utils.FormatInt(observationTimestamp),
157	)
158
159	return positionId, liquidity.ToString(), tickLower, tickUpper, amount0.ToString(), amount1.ToString()
160}