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/r/gnoswap/pool/v1

Realm
Open in gnoweb ↗

Overview

Kind
Realm (renderable)
Name
v1
Namespace
gnoswap / pool
Files
24 (README)(gnomod.toml)
Exported functions
3
Module
gno.land/r/gnoswap/pool/v1
gno
0.9

Files (24)

  • README.mdmarkdown
  • gnomod.tomltoml
  • assert.gnogno
  • doc.gnogno
  • errors.gnogno
  • event_info.gnogno
  • factory_param.gnogno
  • getter_utils.gnogno
  • getter.gnogno
  • init.gnogno
  • instance.gnogno
  • lock.gnogno
  • manager.gnogno
  • oracle.gnogno
  • pool.gnogno
  • position.gnogno
  • protocol_fee.gnogno
  • render.gnogno
  • swap.gnogno
  • tick_bitmap.gnogno
  • tick.gnogno
  • transfer.gnogno
  • type.gnogno
  • utils.gnogno
  • position.gnogno
    1package pool23import (4	"errors"5	"time"67	"gno.land/p/gnoswap/gnsmath/v1"8

    Functions

    • GetPoolPath(token0Path string, token1Path string, fee uint32) string

    • NewPoolV1(store interface {GetFeeAmountTickSpacing func() map[uint32]int32; GetObservations func() *gno.land/p/nt/bptree/v0.BPTree; GetPendingProtocolFee func(string) int64; GetPendingProtocolFees func() map[string]int64; GetPoolCreationFee func() int64; GetPools func() *gno.land/p/nt/bptree/v0.BPTree; GetSlot0FeeProtocol func() uint8; GetSwapEndHook func() func(.uverse.realm, string) .uverse.error; GetSwapStartHook func() func(.uverse.realm, string, int64); GetTickCrossHook func() func(.uverse.realm, string, int32, bool, int64); GetUnlocked func() bool; GetWithdrawalFeeBPS func() uint64; HasFeeAmountTickSpacing func() bool; HasObservations func() bool; HasPendingProtocolFees func() bool; HasPoolCreationFee func() bool; HasPools func() bool; HasSlot0FeeProtocol func() bool; HasSwapEndHook func() bool; HasSwapStartHook func() bool; HasTickCrossHook func() bool; HasUnlocked func() bool; HasWithdrawalFeeBPS func() bool; RemovePendingProtocolFee func(int, .uverse.realm, string) .uverse.error; SetFeeAmountTickSpacing func(int, .uverse.realm, map[uint32]int32) .uverse.error; SetObservations func(int, .uverse.realm, *gno.land/p/nt/bptree/v0.BPTree) .uverse.error; SetPendingProtocolFee func(int, .uverse.realm, string, int64) .uverse.error; SetPendingProtocolFees func(int, .uverse.realm, map[string]int64) .uverse.error; SetPoolCreationFee func(int, .uverse.realm, int64) .uverse.error; SetPools func(int, .uverse.realm, *gno.land/p/nt/bptree/v0.BPTree) .uverse.error; SetSlot0FeeProtocol func(int, .uverse.realm, uint8) .uverse.error; SetSwapEndHook func(int, .uverse.realm, func(.uverse.realm, string) .uverse.error) .uverse.error; SetSwapStartHook func(int, .uverse.realm, func(.uverse.realm, string, int64)) .uverse.error; SetTickCrossHook func(int, .uverse.realm, func(.uverse.realm, string, int32, bool, int64)) .uverse.error; SetUnlocked func(int, .uverse.realm, bool) .uverse.error; SetWithdrawalFeeBPS func(int, .uverse.realm, uint64) .uverse.error}) interface {Burn func(int, .uverse.realm, string, string, uint32, int32, int32, string, .uverse.address) (string, string); Collect func(int, .uverse.realm, string, string, uint32, .uverse.address, int32, int32, string, string) (string, string); CollectProtocol func(int, .uverse.realm, string, string, uint32, .uverse.address, string, string) (string, string); CollectSwapFee func(int, .uverse.realm, string, string, uint32, .uverse.address, int32, int32, string, string) (string, string, string, string); CreatePool func(int, .uverse.realm, string, string, uint32, string); DrySwap func(string, string, uint32, bool, string, string) (string, string, .uverse.error); ExistsPoolPath func(string) bool; GetBalanceToken0 func(string) (int64, .uverse.error); GetBalanceToken1 func(string) (int64, .uverse.error); GetFee func(string) (uint32, .uverse.error); GetFeeAmountTickSpacing func(uint32) (int32, .uverse.error); GetFeeAmountTickSpacings func() map[uint32]int32; GetFeeGrowthGlobal0X128 func(string) (*gno.land/p/gnoswap/uint256/v1.Uint, .uverse.error); GetFeeGrowthGlobal1X128 func(string) (*gno.land/p/gnoswap/uint256/v1.Uint, .uverse.error); GetFeeGrowthGlobalX128 func(string) (*gno.land/p/gnoswap/uint256/v1.Uint, *gno.land/p/gnoswap/uint256/v1.Uint, .uverse.error); GetInitializedTicksInRange func(string, int32, int32) ([]int32, .uverse.error); GetLiquidity func(string) (*gno.land/p/gnoswap/uint256/v1.Uint, .uverse.error); GetObservationAt func(string, uint16) (gno.land/r/gnoswap/pool.Observation, .uverse.error); GetPendingProtocolFees func() map[string]int64; GetPoolCreationFee func() int64; GetPoolPositions func(string) *gno.land/p/nt/bptree/rotree/v0.ReadOnlyTree; GetPools func() *gno.land/p/nt/bptree/rotree/v0.ReadOnlyTree; GetPositionFeeGrowthInside0LastX128 func(string, string) (string, .uverse.error); GetPositionFeeGrowthInside1LastX128 func(string, string) (string, .uverse.error); GetPositionFeeGrowthInsideLastX128 func(string, string) (string, string, .uverse.error); GetPositionLiquidity func(string, string) (string, .uverse.error); GetPositionTokensOwed0 func(string, string) (int64, .uverse.error); GetPositionTokensOwed1 func(string, string) (int64, .uverse.error); GetProtocolFeesToken0 func(string) (int64, .uverse.error); GetProtocolFeesToken1 func(string) (int64, .uverse.error); GetSlot0 func(string) gno.land/r/gnoswap/pool.Slot0; GetSlot0FeeProtocol func(string) (uint8, .uverse.error); GetSlot0SqrtPriceX96 func(string) (*gno.land/p/gnoswap/uint256/v1.Uint, .uverse.error); GetSlot0Tick func(string) (int32, .uverse.error); GetSlot0Unlocked func(string) (bool, .uverse.error); GetTickBitmaps func(string, int16) (string, .uverse.error); GetTickCumulativeOutside func(string, int32) (int64, .uverse.error); GetTickFeeGrowthOutside0X128 func(string, int32) (string, .uverse.error); GetTickFeeGrowthOutside1X128 func(string, int32) (string, .uverse.error); GetTickFeeGrowthOutsideX128 func(string, int32) (string, string, .uverse.error); GetTickInfo func(string, int32) (gno.land/r/gnoswap/pool.TickInfo, .uverse.error); GetTickInitialized func(string, int32) (bool, .uverse.error); GetTickLiquidityGross func(string, int32) (string, .uverse.error); GetTickLiquidityNet func(string, int32) (string, .uverse.error); GetTickSecondsOutside func(string, int32) (uint32, .uverse.error); GetTickSecondsPerLiquidityOutsideX128 func(string, int32) (string, .uverse.error); GetTickSpacing func(string) (int32, .uverse.error); GetToken0Path func(string) (string, .uverse.error); GetToken1Path func(string) (string, .uverse.error); GetWithdrawalFee func() uint64; IncreaseObservationCardinalityNext func(int, .uverse.realm, string, string, uint32, uint16); Mint func(int, .uverse.realm, string, string, uint32, int32, int32, string, .uverse.address) (string, string); Observe func(string, []uint32) ([]int64, []string, .uverse.error); OracleConsult func(string, uint32) (int32, *gno.land/p/gnoswap/uint256/v1.Uint, .uverse.error); Render func(string) string; SetFeeProtocol func(int, .uverse.realm, uint8, uint8); SetPoolCreationFee func(int, .uverse.realm, int64); SetSwapEndHook func(int, .uverse.realm, func(.uverse.realm, string) .uverse.error); SetSwapStartHook func(int, .uverse.realm, func(.uverse.realm, string, int64)); SetTickCrossHook func(int, .uverse.realm, func(.uverse.realm, string, int32, bool, int64)); SetWithdrawalFee func(int, .uverse.realm, uint64); SnapshotCumulativesInside func(string, int32, int32) (int64, *gno.land/p/gnoswap/uint256/v1.Uint, uint32, .uverse.error); Swap func(int, .uverse.realm, string, string, uint32, .uverse.address, bool, string, string, func(.uverse.realm, int64, int64, *gno.land/r/gnoswap/pool.CallbackMarker) .uverse.error) (string, string)}

    • NewTickEventInfo(tickID int32, tickInfo struct{liquidityGross string; liquidityNet string; feeGrowthOutside0X128 string; feeGrowthOutside1X128 string; tickCumulativeOutside int64; secondsPerLiquidityOutsideX128 string; secondsOutside uint32; initialized bool}) *gno.land/r/gnoswap/pool/v1.tickEventInfo

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

    Rendered

    RenderedRawgnoweb ↗
    This realm does not provide renderable output (vm/qrender → NoRenderDeclError). View on gnoweb ↗

    vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.

    i256 "gno.land/p/gnoswap/int256/v1"
    9 u256 "gno.land/p/gnoswap/uint256/v1"
    10 ufmt "gno.land/p/nt/ufmt/v0"
    11
    12 pl "gno.land/r/gnoswap/pool"
    13)
    14
    15// getPositionKey generates a compact deterministic key for a liquidity position.
    16//
    17// Creates deterministic identifier for position tracking.
    18// Ensures unique positions per price range while preserving lexical ordering.
    19//
    20// Used internally for position state management.
    21//
    22// Parameters:
    23// - tickLower: Lower boundary tick of position range
    24// - tickUpper: Upper boundary tick of position range
    25//
    26// Key Format: EncodePositionKey(tickLower, tickUpper)
    27func getPositionKey(
    28 tickLower int32,
    29 tickUpper int32,
    30) string {
    31 return pl.EncodePositionKey(tickLower, tickUpper)
    32}
    33
    34// positionUpdate updates a position's liquidity and calculates fees owed.
    35// Returns the updated position information and any error.
    36func positionUpdate(
    37 position pl.PositionInfo,
    38 liquidityDelta *i256.Int,
    39 feeGrowthInside0X128 *u256.Uint,
    40 feeGrowthInside1X128 *u256.Uint,
    41) (pl.PositionInfo, error) {
    42 isZeroLiquidityDelta := liquidityDelta.IsZero()
    43
    44 posLiquidity := u256.MustFromDecimal(position.Liquidity())
    45 if posLiquidity.IsZero() && isZeroLiquidityDelta {
    46 return pl.NewDefaultPositionInfo(), makeErrorWithDetails(
    47 errZeroLiquidity,
    48 "both liquidityDelta and current position's liquidity are zero",
    49 )
    50 }
    51
    52 if liquidityDelta.IsNeg() {
    53 absDelta := i256.Zero().Set(liquidityDelta).Abs()
    54 if absDelta.Gt(posLiquidity) {
    55 return pl.NewDefaultPositionInfo(), makeErrorWithDetails(
    56 errZeroLiquidity,
    57 ufmt.Sprintf("liquidity delta(%s) is greater than current liquidity(%s)",
    58 liquidityDelta.ToString(), posLiquidity.ToString()),
    59 )
    60 }
    61 }
    62
    63 var liquidityNext *u256.Uint
    64 if isZeroLiquidityDelta {
    65 liquidityNext = posLiquidity
    66 } else {
    67 liquidityNext = gnsmath.LiquidityMathAddDelta(posLiquidity, liquidityDelta)
    68 }
    69
    70 feeGrowthLast0 := u256.MustFromDecimal(position.FeeGrowthInside0LastX128())
    71 feeGrowthLast1 := u256.MustFromDecimal(position.FeeGrowthInside1LastX128())
    72
    73 diff0 := u256.Zero().Sub(feeGrowthInside0X128, feeGrowthLast0)
    74 diff1 := u256.Zero().Sub(feeGrowthInside1X128, feeGrowthLast1)
    75
    76 tokensOwed0 := u256.Zero()
    77 if !diff0.IsZero() {
    78 tokensOwed0 = u256.MulDiv(diff0, posLiquidity, q128FromDecimal)
    79 }
    80
    81 tokensOwed1 := u256.Zero()
    82 if !diff1.IsZero() {
    83 tokensOwed1 = u256.MulDiv(diff1, posLiquidity, q128FromDecimal)
    84 }
    85
    86 if !isZeroLiquidityDelta {
    87 position.SetLiquidity(liquidityNext.ToString())
    88 }
    89
    90 position.SetFeeGrowthInside0LastX128(feeGrowthInside0X128.ToString())
    91 position.SetFeeGrowthInside1LastX128(feeGrowthInside1X128.ToString())
    92
    93 if tokensOwed0.Gt(zero) || tokensOwed1.Gt(zero) {
    94 owed0 := gnsmath.SafeAddInt64(position.TokensOwed0(), gnsmath.SafeConvertToInt64(tokensOwed0))
    95 owed1 := gnsmath.SafeAddInt64(position.TokensOwed1(), gnsmath.SafeConvertToInt64(tokensOwed1))
    96
    97 position.SetTokensOwed0(owed0)
    98 position.SetTokensOwed1(owed1)
    99 }
    100
    101 return position, nil
    102}
    103
    104// calculateToken0Amount calculates the amount of token0 based on price range and liquidity delta.
    105func calculateToken0Amount(sqrtPriceLower, sqrtPriceUpper *u256.Uint, liquidityDelta *i256.Int) *i256.Int {
    106 return gnsmath.GetAmount0Delta(sqrtPriceLower, sqrtPriceUpper, liquidityDelta)
    107}
    108
    109// calculateToken1Amount calculates the amount of token1 based on price range and liquidity delta.
    110func calculateToken1Amount(sqrtPriceLower, sqrtPriceUpper *u256.Uint, liquidityDelta *i256.Int) *i256.Int {
    111 return gnsmath.GetAmount1Delta(sqrtPriceLower, sqrtPriceUpper, liquidityDelta)
    112}
    113
    114// positionUpdateWithKey updates a position in the pool and returns the updated position.
    115func positionUpdateWithKey(
    116 p *pl.Pool,
    117 positionKey string,
    118 liquidityDelta *i256.Int,
    119 feeGrowthInside0X128, feeGrowthInside1X128 *u256.Uint,
    120) (pl.PositionInfo, error) {
    121 // if position does not exist, create a new position
    122 //
    123 // Note: The positionUpdate function is designed to handle both new positions and existing positions,
    124 // so there's no need to check for existence in GetPosition.
    125 positionToUpdate, err := p.GetPosition(positionKey)
    126 if err != nil {
    127 positionToUpdate = pl.NewDefaultPositionInfo()
    128 }
    129
    130 positionAfterUpdate, err := positionUpdate(positionToUpdate, liquidityDelta, feeGrowthInside0X128, feeGrowthInside1X128)
    131 if err != nil {
    132 return pl.NewDefaultPositionInfo(), err
    133 }
    134
    135 setPosition(p, positionKey, positionAfterUpdate)
    136
    137 return positionAfterUpdate, nil
    138}
    139
    140// setPosition sets the position info for a given key.
    141func setPosition(p *pl.Pool, posKey string, positionInfo pl.PositionInfo) {
    142 p.SetPosition(posKey, positionInfo)
    143}
    144
    145// modifyPosition updates a position in the pool and calculates the amount of tokens
    146// needed (for minting) or returned (for burning). The calculation depends on the current
    147// price (tick) relative to the position's price range.
    148//
    149// The function handles three cases:
    150// 1. Current price below range (tick < tickLower): only token0 is used/returned
    151// 2. Current price in range (tickLower <= tick < tickUpper): both tokens are used/returned
    152// 3. Current price above range (tick >= tickUpper): only token1 is used/returned
    153//
    154// Parameters:
    155// - params: ModifyPositionParams containing owner, tickLower, tickUpper, and liquidityDelta
    156//
    157// Returns:
    158// - PositionInfo: updated position information
    159// - *u256.Uint: amount of token0 needed/returned
    160// - *u256.Uint: amount of token1 needed/returned
    161func modifyPosition(p *pl.Pool, observations *pl.ObservationTree, params ModifyPositionParams) (pl.PositionInfo, *u256.Uint, *u256.Uint, error) {
    162 if err := validateTicks(params.tickLower, params.tickUpper); err != nil {
    163 return pl.NewDefaultPositionInfo(), zero, zero, err
    164 }
    165
    166 // get current state and price bounds
    167 tick := p.Slot0Tick()
    168 // update position state
    169 position, err := updatePosition(p, observations, params, tick)
    170 if err != nil {
    171 return pl.NewDefaultPositionInfo(), zero, zero, err
    172 }
    173
    174 liqDelta := params.liquidityDelta
    175 if liqDelta.IsZero() {
    176 return position, zero, zero, nil
    177 }
    178
    179 amount0, amount1 := i256.Zero(), i256.Zero()
    180
    181 // covert ticks to sqrt price to use in amount calculations
    182 // price = 1.0001^tick, but we use sqrtPriceX96
    183 sqrtRatioLower := gnsmath.TickMathGetSqrtRatioAtTick(params.tickLower)
    184 sqrtRatioUpper := gnsmath.TickMathGetSqrtRatioAtTick(params.tickUpper)
    185 sqrtPriceX96 := p.Slot0SqrtPriceX96()
    186
    187 // calculate token amounts based on current price position relative to range
    188 switch {
    189 case tick < params.tickLower:
    190 // case 1
    191 // full range between lower and upper tick is used for token0
    192 // current tick is below the passed range; liquidity can only become in range by crossing from left to
    193 // right, when we'll need _more_ token0 (it's becoming more valuable) so user must provide it
    194 amount0 = calculateToken0Amount(sqrtRatioLower, sqrtRatioUpper, liqDelta)
    195
    196 case tick < params.tickUpper:
    197 // case 2: Current price is within the position range
    198 liquidityBefore := p.Liquidity()
    199 currentTime := time.Now().Unix()
    200 // Update oracle BEFORE liquidity changes
    201 if observations == nil {
    202 return pl.NewDefaultPositionInfo(), zero, zero, errors.New("observations not initialized")
    203 }
    204 slot0 := p.Slot0()
    205 observationIndex, observationCardinality, err := writeObservation(
    206 observations,
    207 slot0.ObservationIndex(),
    208 currentTime,
    209 tick,
    210 liquidityBefore,
    211 slot0.ObservationCardinality(),
    212 slot0.ObservationCardinalityNext(),
    213 )
    214 if err != nil {
    215 return pl.NewDefaultPositionInfo(), zero, zero, err
    216 }
    217 slot0.SetObservationIndex(observationIndex)
    218 slot0.SetObservationCardinality(observationCardinality)
    219 p.SetSlot0(slot0)
    220
    221 // token0 used from current price to upper tick
    222 amount0 = calculateToken0Amount(sqrtPriceX96, sqrtRatioUpper, liqDelta)
    223 // token1 used from lower tick to current price
    224 amount1 = calculateToken1Amount(sqrtRatioLower, sqrtPriceX96, liqDelta)
    225 // update pool's active liquidity since price is in range
    226 p.SetLiquidity(gnsmath.LiquidityMathAddDelta(liquidityBefore, liqDelta))
    227
    228 default:
    229 // case 3
    230 // full range between lower and upper tick is used for token1
    231 // current tick is above the passed range; liquidity can only become in range by crossing from right to
    232 // left, when we'll need _more_ token1 (it's becoming more valuable) so user must provide it
    233 amount1 = calculateToken1Amount(sqrtRatioLower, sqrtRatioUpper, liqDelta)
    234 }
    235
    236 return position, amount0.Abs(), amount1.Abs(), nil
    237}
    238
    239// updatePosition modifies the position's liquidity and updates the corresponding tick states.
    240//
    241// This function updates the position data based on the specified liquidity delta and tick range.
    242// It also manages the fee growth, tick state flipping, and cleanup of unused tick data.
    243//
    244// Parameters:
    245// - positionParams: ModifyPositionParams, the parameters for the position modification, which include:
    246// - owner: The address of the position owner.
    247// - tickLower: The lower tick boundary of the position.
    248// - tickUpper: The upper tick boundary of the position.
    249// - liquidityDelta: The change in liquidity (positive or negative).
    250// - tick: int32, the current tick position.
    251//
    252// Returns:
    253// - PositionInfo: The updated position information.
    254//
    255// Workflow:
    256// 1. Clone the global fee growth values (token 0 and token 1).
    257// 2. If the liquidity delta is non-zero:
    258// - Update the lower and upper ticks using `tickUpdate`, flipping their states if necessary.
    259// - If a tick's state was flipped, update the tick bitmap to reflect the new state.
    260// 3. Calculate the fee growth inside the tick range using `getFeeGrowthInside`.
    261// 4. Generate a unique position key and update the position data using `positionUpdateWithKey`.
    262// 5. If liquidity is being removed (negative delta), clean up unused tick data by deleting the tick entries.
    263// 6. Return the updated position.
    264//
    265// Notes:
    266// - The function flips the tick states and cleans up unused tick data when liquidity is removed.
    267// - It ensures fee growth and position data remain accurate after the update.
    268//
    269// Example Usage:
    270//
    271// ```gno
    272//
    273// updatedPosition := pool.updatePosition(positionParams, currentTick)
    274// println("Updated Position Info:", updatedPosition)
    275//
    276// ```
    277func updatePosition(p *pl.Pool, observations *pl.ObservationTree, positionParams ModifyPositionParams, tick int32) (pl.PositionInfo, error) {
    278 feeGrowthGlobal0X128 := p.FeeGrowthGlobal0X128().Clone()
    279 feeGrowthGlobal1X128 := p.FeeGrowthGlobal1X128().Clone()
    280 liquidityDelta := positionParams.liquidityDelta
    281
    282 var flippedLower, flippedUpper bool
    283 if !liquidityDelta.IsZero() {
    284 blockTimestamp := time.Now().Unix()
    285 if observations == nil {
    286 return pl.NewDefaultPositionInfo(), errors.New("observations not initialized")
    287 }
    288 slot0 := p.Slot0()
    289 tickCumulative, secondsPerLiquidityStr, err := observeSingle(
    290 observations,
    291 blockTimestamp,
    292 0,
    293 slot0.Tick(),
    294 slot0.ObservationIndex(),
    295 p.Liquidity(),
    296 slot0.ObservationCardinality(),
    297 )
    298 if err != nil {
    299 return pl.NewDefaultPositionInfo(), err
    300 }
    301
    302 secondsPerLiquidityCumulativeX128 := u256.MustFromDecimal(secondsPerLiquidityStr)
    303
    304 flippedLower = tickUpdate(
    305 p,
    306 positionParams.tickLower,
    307 tick,
    308 liquidityDelta,
    309 feeGrowthGlobal0X128,
    310 feeGrowthGlobal1X128,
    311 secondsPerLiquidityCumulativeX128,
    312 tickCumulative,
    313 blockTimestamp,
    314 false,
    315 calculateMaxLiquidityPerTick(p.TickSpacing()),
    316 )
    317
    318 flippedUpper = tickUpdate(
    319 p,
    320 positionParams.tickUpper,
    321 tick,
    322 liquidityDelta,
    323 feeGrowthGlobal0X128,
    324 feeGrowthGlobal1X128,
    325 secondsPerLiquidityCumulativeX128,
    326 tickCumulative,
    327 blockTimestamp,
    328 true,
    329 calculateMaxLiquidityPerTick(p.TickSpacing()),
    330 )
    331
    332 if flippedLower {
    333 tickBitmapFlipTick(p, positionParams.tickLower, p.TickSpacing())
    334 }
    335
    336 if flippedUpper {
    337 tickBitmapFlipTick(p, positionParams.tickUpper, p.TickSpacing())
    338 }
    339 }
    340
    341 feeGrowthInside0X128, feeGrowthInside1X128 := getFeeGrowthInside(
    342 p,
    343 positionParams.tickLower,
    344 positionParams.tickUpper,
    345 tick,
    346 feeGrowthGlobal0X128,
    347 feeGrowthGlobal1X128,
    348 )
    349
    350 positionKey := getPositionKey(positionParams.tickLower, positionParams.tickUpper)
    351
    352 position, err := positionUpdateWithKey(
    353 p,
    354 positionKey,
    355 liquidityDelta,
    356 feeGrowthInside0X128.Clone(),
    357 feeGrowthInside1X128.Clone(),
    358 )
    359 if err != nil {
    360 return pl.NewDefaultPositionInfo(), err
    361 }
    362
    363 // clear any tick data that is no longer needed
    364 if liquidityDelta.IsNeg() {
    365 if flippedLower {
    366 deleteTick(p, positionParams.tickLower)
    367 }
    368 if flippedUpper {
    369 deleteTick(p, positionParams.tickUpper)
    370 }
    371 }
    372
    373 return position, nil
    374}
    375