Kind Realm (renderable)
Name v1
Namespace gnoswap / position
Exported functions 1
Module gno.land/r/gnoswap/position/v1
gno 0.9 burn.gno gno
⧉
1 package position 2 3 import ( 4 "errors" 5 6 "gno.land/p/gnoswap/consts/v1" 7 "gno.land/p/gnoswap/gnsmath/v1" 8 NewPositionV1 (positionStore interface {GetPosition func(uint64) (gno.land/r/gnoswap/position.Position, bool); GetPositionNextID func() uint64; GetPositions func() *gno.land/p/nt/bptree/v0.BPTree; HasPosition func(uint64) bool; HasPositionNextIDStoreKey func() bool; HasPositionsStoreKey func() bool; RemovePosition func(int, .uverse.realm, uint64) .uverse.error; SetPosition func(int, .uverse.realm, uint64, gno.land/r/gnoswap/position.Position) .uverse.error; SetPositionNextID func(int, .uverse.realm, uint64) .uverse.error; SetPositions func(int, .uverse.realm, *gno.land/p/nt/bptree/v0.BPTree) .uverse.error}, accessor interface {Approve func(int, .uverse.realm, .uverse.address, gno.land/p/nt/grc721/v0.TokenID) .uverse.error; Burn func(int, .uverse.realm, gno.land/p/nt/grc721/v0.TokenID); Exists func(gno.land/p/nt/grc721/v0.TokenID) bool; Mint func(int, .uverse.realm, .uverse.address, gno.land/p/nt/grc721/v0.TokenID) gno.land/p/nt/grc721/v0.TokenID; OwnerOf func(gno.land/p/nt/grc721/v0.TokenID) (.uverse.address, .uverse.error); TotalSupply func() int64}) interface {CollectFee func(int, .uverse.realm, uint64) (uint64, string, string, string, string, string); DecreaseLiquidity func(int, .uverse.realm, uint64, string, string, string, int64) (uint64, string, string, string, string, string, string); GetPositionFeeGrowthInside0LastX128 func(uint64) (string, .uverse.error); GetPositionFeeGrowthInside1LastX128 func(uint64) (string, .uverse.error); GetPositionFeeGrowthInsideLastX128 func(uint64) (string, string, .uverse.error); GetPositionLiquidity func(uint64) (string, .uverse.error); GetPositionOperator func(uint64) (.uverse.address, .uverse.error); GetPositionOwner func(uint64) (.uverse.address, .uverse.error); GetPositionPoolKey func(uint64) (string, .uverse.error); GetPositionTickLower func(uint64) (int32, .uverse.error); GetPositionTickUpper func(uint64) (int32, .uverse.error); GetPositionTicks func(uint64) (int32, int32, .uverse.error); GetPositionTokenBalances func(uint64) (int64, int64, .uverse.error); GetPositionTokensOwed func(uint64) (int64, int64, .uverse.error); GetPositionTokensOwed0 func(uint64) (int64, .uverse.error); GetPositionTokensOwed1 func(uint64) (int64, .uverse.error); GetPositions func() *gno.land/p/nt/bptree/rotree/v0.ReadOnlyTree; GetUnclaimedFee func(uint64) (*gno.land/p/gnoswap/uint256/v1.Uint, *gno.land/p/gnoswap/uint256/v1.Uint, .uverse.error); IncreaseLiquidity func(int, .uverse.realm, uint64, string, string, string, string, int64) (uint64, string, string, string, string); IsBurned func(uint64) (bool, .uverse.error); IsInRange func(uint64) (bool, .uverse.error); Mint func(int, .uverse.realm, string, string, uint32, int32, int32, string, string, string, string, int64, .uverse.address, string) (uint64, string, string, string); Render func(string) string; Reposition func(int, .uverse.realm, uint64, int32, int32, string, string, string, string, int64) (uint64, string, int32, int32, string, string); SetPositionOperator func(int, .uverse.realm, uint64, .uverse.address)}
Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.
Render unavailable
rate limit exceeded — the render query is served by the Gnoland archive RPC.
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.
u256 "gno.land/p/gnoswap/uint256/v1"
9 "gno.land/p/gnoswap/utils/v1"
10 ufmt "gno.land/p/nt/ufmt/v0"
11
12 pl "gno.land/r/gnoswap/pool"
13 "gno.land/r/gnoswap/position"
14 )
15
16 // decreaseLiquidity reduces position liquidity and collects fees.
17 // Returns positionId, liquidity, fee0, fee1, amount0, amount1, poolPath.
18 func (p *positionV1) decreaseLiquidity(_ int , rlm realm, params DecreaseLiquidityParams) ( uint64 , string , string , string , string , string , string , error ) {
19 caller := params.caller
20
21 // before decrease liquidity, collect fee first
22 _, fee0Str, fee1Str, _, _, _ := p.collectFee( 0 , rlm, params.positionId, params.caller)
23
24 position := p.mustGetPosition(params.positionId)
25 positionLiquidity := u256.MustFromDecimal(position.Liquidity())
26 if positionLiquidity.IsZero() {
27 return params.positionId,
28 "" ,
29 fee0Str,
30 fee1Str,
31 "" , "" ,
32 position.PoolKey(),
33 makeErrorWithDetails(
34 errZeroLiquidity,
35 ufmt.Sprintf( "position(position ID:%d) has 0 liquidity" , params.positionId),
36 )
37 }
38
39 liquidityToRemove := u256.MustFromDecimal(params.liquidity)
40
41 if liquidityToRemove.Gt(positionLiquidity) {
42 return params.positionId,
43 liquidityToRemove.ToString(),
44 fee0Str,
45 fee1Str,
46 "" , "" ,
47 position.PoolKey(),
48 makeErrorWithDetails(
49 errInvalidLiquidity,
50 ufmt.Sprintf( "Liquidity requested(%s) is greater than liquidity held(%s)" , liquidityToRemove.ToString(), positionLiquidity.ToString()),
51 )
52 }
53
54 pToken0, pToken1, pFee := splitOf(position.PoolKey())
55 burn0, burn1 := pl.Burn(cross(rlm), pToken0, pToken1, pFee, position.TickLower(), position.TickUpper(), liquidityToRemove.ToString(), caller)
56
57 burnedAmount0 := utils.SafeParseInt64(burn0)
58 burnedAmount1 := utils.SafeParseInt64(burn1)
59
60 if burnedAmount0 < 0 || burnedAmount1 < 0 {
61 panic(errors.New(errUnderflow))
62 }
63
64 positionKey := computePositionKey(position.TickLower(), position.TickUpper())
65 feeGrowthInside0LastX128Str, feeGrowthInside1LastX128Str, err := pl.GetPositionFeeGrowthInsideLastX128(position.PoolKey(), positionKey)
66 if err != nil {
67 return 0 , "" , "" , "" , "" , "" , position.PoolKey(), err
68 }
69
70 // Add only burned amounts to tokensOwed since fees were already collected and processed in collectFee
71 tokensOwed0 := gnsmath.SafeAddInt64(position.TokensOwed0(), burnedAmount0)
72 tokensOwed1 := gnsmath.SafeAddInt64(position.TokensOwed1(), burnedAmount1)
73
74 newLiquidity, underflow := u256.Zero().SubOverflow(positionLiquidity, liquidityToRemove)
75 if underflow {
76 panic(newErrorWithDetail(errUnderflow, "positionLiquidity - liquidityToRemove underflow" ))
77 }
78
79 position.SetTokensOwed0(tokensOwed0)
80 position.SetTokensOwed1(tokensOwed1)
81 position.SetFeeGrowthInside0LastX128(feeGrowthInside0LastX128Str)
82 position.SetFeeGrowthInside1LastX128(feeGrowthInside1LastX128Str)
83 position.SetLiquidity(newLiquidity.ToString())
84
85 p.mustUpdatePosition( 0 , rlm, params.positionId, *position)
86
87 collect0, collect1 := pl.Collect(
88 cross(rlm),
89 pToken0,
90 pToken1,
91 pFee,
92 caller,
93 position.TickLower(),
94 position.TickUpper(),
95 burn0,
96 burn1,
97 )
98
99 collectAmount0 := u256.MustFromDecimal(collect0)
100 collectAmount1 := u256.MustFromDecimal(collect1)
101
102 // Slippage check on actually collected amounts to ensure user receives minimum expected tokens
103 if isSlippageExceeded(collectAmount0, collectAmount1, params.amount0Min, params.amount1Min) {
104 return params.positionId,
105 liquidityToRemove.ToString(),
106 fee0Str,
107 fee1Str,
108 collect0,
109 collect1,
110 position.PoolKey(),
111 makeErrorWithDetails(
112 errSlippage,
113 ufmt.Sprintf( "collectAmount0(%s) >= amount0Min(%s) && collectAmount1(%s) >= amount1Min(%s)" ,
114 collectAmount0.ToString(),
115 params.amount0Min.ToString(),
116 collectAmount1.ToString(),
117 params.amount1Min.ToString(),
118 ),
119 )
120 }
121
122 // Check for underflow when subtracting collected amounts from tokens owed
123 collectAmount0Int64 := gnsmath.SafeConvertToInt64(collectAmount0)
124 collectAmount1Int64 := gnsmath.SafeConvertToInt64(collectAmount1)
125
126 if position.TokensOwed0() < collectAmount0Int64 {
127 panic(ufmt.Sprintf( "[POSITION] burn.gno | collect() | tokensOwed0(%d) < collectAmount0(%d)" , position.TokensOwed0(), collectAmount0Int64))
128 }
129 position.SetTokensOwed0(gnsmath.SafeSubInt64(position.TokensOwed0(), collectAmount0Int64))
130
131 if position.TokensOwed1() < collectAmount1Int64 {
132 panic(ufmt.Sprintf( "[POSITION] burn.gno | collect() | tokensOwed1(%d) < collectAmount1(%d)" , position.TokensOwed1(), collectAmount1Int64))
133 }
134 position.SetTokensOwed1(gnsmath.SafeSubInt64(position.TokensOwed1(), collectAmount1Int64))
135
136 if position.IsClear() {
137 position.SetBurned( true ) // just update flag (we don't want to burn actual position)
138 }
139
140 p.mustUpdatePosition( 0 , rlm, params.positionId, *position)
141
142 return params.positionId, liquidityToRemove.ToString(), fee0Str, fee1Str, collect0, collect1, position.PoolKey(), nil
143 }
144
145 // calculateFees calculates the fees for the current position.
146 func (p *positionV1) calculateFees(position *position.Position, currentFeeGrowth FeeGrowthInside) ( int64 , int64 ) {
147 posLiquidity := u256.MustFromDecimal(position.Liquidity())
148 fee0 := calculateTokensOwed(
149 currentFeeGrowth.feeGrowthInside0LastX128,
150 u256.MustFromDecimal(position.FeeGrowthInside0LastX128()),
151 posLiquidity,
152 )
153
154 fee1 := calculateTokensOwed(
155 currentFeeGrowth.feeGrowthInside1LastX128,
156 u256.MustFromDecimal(position.FeeGrowthInside1LastX128()),
157 posLiquidity,
158 )
159
160 return gnsmath.SafeAddInt64(position.TokensOwed0(), gnsmath.SafeConvertToInt64(fee0)), gnsmath.SafeAddInt64(position.TokensOwed1(), gnsmath.SafeConvertToInt64(fee1))
161 }
162
163 func calculateTokensOwed(
164 feeGrowthInsideLastX128 *u256.Uint,
165 positionFeeGrowthInsideLastX128 *u256.Uint,
166 positionLiquidity *u256.Uint,
167 ) *u256.Uint {
168 diff := u256.Zero().Sub(feeGrowthInsideLastX128, positionFeeGrowthInsideLastX128)
169 return u256.MulDiv(diff, positionLiquidity, consts.Q128())
170 }
171