Kind Realm (renderable)
Name v1
Namespace gnoswap / staker
Exported functions 14
Module gno.land/r/gnoswap/staker/v1
gno 0.9 unstaked_position.gno gno
⧉
1 package staker 2 3 import ( 4 "chain" 5 "chain/runtime" 6 "time" 7 8 NewDepositResolver (deposit *gno.land/r/gnoswap/staker.Deposit) *gno.land/r/gnoswap/staker/v1.DepositResolver
NewDeposits () *gno.land/r/gnoswap/staker/v1.Deposits
NewExternalIncentiveResolver (externalIncentive *gno.land/r/gnoswap/staker.ExternalIncentive) *gno.land/r/gnoswap/staker/v1.ExternalIncentiveResolver
NewExternalIncentives () *gno.land/r/gnoswap/staker/v1.ExternalIncentives
NewIncentivesResolver (incentives *gno.land/r/gnoswap/staker.Incentives) *gno.land/r/gnoswap/staker/v1.IncentivesResolver
NewPoolResolver (pool *gno.land/r/gnoswap/staker.Pool) *gno.land/r/gnoswap/staker/v1.PoolResolver
NewPools () *gno.land/r/gnoswap/staker/v1.Pools
NewPoolTier (pools *gno.land/r/gnoswap/staker/v1.Pools, currentTime int64, initialPoolPath string, getEmission func() (int64, .uverse.error), getHalvingBlocksInRange func(int64, int64) ([]int64, []int64, .uverse.error)) *gno.land/r/gnoswap/staker/v1.PoolTier
NewPoolTierBy (membership *gno.land/p/nt/bptree/v0.BPTree, tierRatio struct{Tier1 uint64; Tier2 uint64; Tier3 uint64}, counts [4]uint64, lastRewardCacheTimestamp int64, currentEmission int64, getEmission func() (int64, .uverse.error), getHalvingBlocksInRange func(int64, int64) ([]int64, []int64, .uverse.error)) *gno.land/r/gnoswap/staker/v1.PoolTier
NewStakerV1 (stakerStore interface {AddAllowedToken func(int, .uverse.realm, string) .uverse.error; AddDeniedRewardToken func(int, .uverse.realm, string) .uverse.error; GetAllowedTokens func() []string; GetCurrentSwapBatch func() *gno.land/r/gnoswap/staker.SwapBatchProcessor; GetDeniedRewardTokens func() []string; GetDepositGnsAmount func() int64; GetDeposits func() *gno.land/p/nt/bptree/v0.BPTree; GetExternalIncentives func() *gno.land/p/nt/bptree/v0.BPTree; GetIncentiveCounter func() *gno.land/r/gnoswap/staker.Counter; GetMinimumRewardAmount func() int64; GetPendingProtocolFee func(string) int64; GetPendingProtocolFees func() map[string]int64; GetPoolTierCounts func() [4]uint64; GetPoolTierCurrentEmission func() int64; GetPoolTierGetEmission func() func() (int64, .uverse.error); GetPoolTierGetHalvingBlocksInRange func() func(int64, int64) ([]int64, []int64, .uverse.error); GetPoolTierLastRewardCacheTimestamp func() int64; GetPoolTierMemberships func() *gno.land/p/nt/bptree/v0.BPTree; GetPoolTierRatio func() gno.land/r/gnoswap/staker.TierRatio; GetPools func() *gno.land/p/nt/bptree/v0.BPTree; GetTokenSpecificMinimumRewards func() map[string]int64; GetTotalEmissionSent func() int64; GetUncollectedIncentiveCounts func() *gno.land/p/nt/bptree/v0.BPTree; GetUnstakedPositions func() *gno.land/p/nt/bptree/v0.BPTree; GetUnstakingFee func() uint64; GetWarmupTemplate func() []gno.land/r/gnoswap/staker.Warmup; HasAllowedTokensStoreKey func() bool; HasCurrentSwapBatchStoreKey func() bool; HasDeniedRewardTokensStoreKey func() bool; HasDepositGnsAmountStoreKey func() bool; HasDepositsStoreKey func() bool; HasExternalIncentivesStoreKey func() bool; HasIncentiveCounterStoreKey func() bool; HasMinimumRewardAmountStoreKey func() bool; HasPendingProtocolFeesStoreKey func() bool; HasPoolTierCountsStoreKey func() bool; HasPoolTierCurrentEmissionStoreKey func() bool; HasPoolTierGetEmissionStoreKey func() bool; HasPoolTierGetHalvingBlocksInRangeStoreKey func() bool; HasPoolTierLastRewardCacheTimestampStoreKey func() bool; HasPoolTierMembershipsStoreKey func() bool; HasPoolTierRatioStoreKey func() bool; HasPoolsStoreKey func() bool; HasTokenSpecificMinimumRewardsStoreKey func() bool; HasTotalEmissionSentStoreKey func() bool; HasUncollectedIncentiveCountsStoreKey func() bool; HasUnstakedPositionsStoreKey func() bool; HasUnstakingFeeStoreKey func() bool; HasWarmupTemplateStoreKey func() bool; NextIncentiveID func(.uverse.address, int64) string; RemoveAllowedToken func(int, .uverse.realm, string) .uverse.error; RemoveDeniedRewardToken func(int, .uverse.realm, string) .uverse.error; RemovePendingProtocolFee func(int, .uverse.realm, string) .uverse.error; RemoveTokenSpecificMinimumRewardItem func(int, .uverse.realm, string) .uverse.error; SetAllowedTokens func(int, .uverse.realm, []string) .uverse.error; SetCurrentSwapBatch func(int, .uverse.realm, *gno.land/r/gnoswap/staker.SwapBatchProcessor) .uverse.error; SetDepositGnsAmount func(int, .uverse.realm, int64) .uverse.error; SetDeposits func(int, .uverse.realm, *gno.land/p/nt/bptree/v0.BPTree) .uverse.error; SetExternalIncentives func(int, .uverse.realm, *gno.land/p/nt/bptree/v0.BPTree) .uverse.error; SetIncentiveCounter func(int, .uverse.realm, *gno.land/r/gnoswap/staker.Counter) .uverse.error; SetMinimumRewardAmount func(int, .uverse.realm, int64) .uverse.error; SetPendingProtocolFee func(int, .uverse.realm, string, int64) .uverse.error; SetPendingProtocolFees func(int, .uverse.realm, map[string]int64) .uverse.error; SetPoolTierCounts func(int, .uverse.realm, [4]uint64) .uverse.error; SetPoolTierCurrentEmission func(int, .uverse.realm, int64) .uverse.error; SetPoolTierGetEmission func(int, .uverse.realm, func() (int64, .uverse.error)) .uverse.error; SetPoolTierGetHalvingBlocksInRange func(int, .uverse.realm, func(int64, int64) ([]int64, []int64, .uverse.error)) .uverse.error; SetPoolTierLastRewardCacheTimestamp func(int, .uverse.realm, int64) .uverse.error; SetPoolTierMemberships func(int, .uverse.realm, *gno.land/p/nt/bptree/v0.BPTree) .uverse.error; SetPoolTierRatio func(int, .uverse.realm, gno.land/r/gnoswap/staker.TierRatio) .uverse.error; SetPools func(int, .uverse.realm, *gno.land/p/nt/bptree/v0.BPTree) .uverse.error; SetTokenSpecificMinimumRewardItem func(int, .uverse.realm, string, int64) .uverse.error; SetTokenSpecificMinimumRewards func(int, .uverse.realm, map[string]int64) .uverse.error; SetTotalEmissionSent func(int, .uverse.realm, int64) .uverse.error; SetUncollectedIncentiveCounts func(int, .uverse.realm, *gno.land/p/nt/bptree/v0.BPTree) .uverse.error; SetUnstakedPositions func(int, .uverse.realm, *gno.land/p/nt/bptree/v0.BPTree) .uverse.error; SetUnstakingFee func(int, .uverse.realm, uint64) .uverse.error; SetWarmupTemplate func(int, .uverse.realm, []gno.land/r/gnoswap/staker.Warmup) .uverse.error}, poolAccessor interface {ExistsPoolPath func(string) bool; GetSlot0SqrtPriceX96 func(string) string; GetSlot0Tick func(string) int32; SetSwapEndHook func(int, .uverse.realm, func(int, .uverse.realm, string) .uverse.error); SetSwapStartHook func(int, .uverse.realm, func(int, .uverse.realm, string, int64)); SetTickCrossHook func(int, .uverse.realm, func(int, .uverse.realm, string, int32, bool, int64))}, emissionAccessor interface {GetStakerEmissionAmountPerSecond func() (int64, .uverse.error); GetStakerEmissionAmountPerSecondInRange func(int64, int64) ([]int64, []int64, .uverse.error); MintAndDistributeGns func(int, .uverse.realm) (int64, bool); SetOnDistributionPctChangeCallback func(int, .uverse.realm, func(int, .uverse.realm, int64))}, nftAccessor 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; MustOwnerOf func(gno.land/p/nt/grc721/v0.TokenID) .uverse.address; OwnerOf func(gno.land/p/nt/grc721/v0.TokenID) (.uverse.address, .uverse.error); TotalSupply func() int64; TransferFrom func(int, .uverse.realm, .uverse.address, .uverse.address, gno.land/p/nt/grc721/v0.TokenID) .uverse.error})
NewTickCrossEventInfo (tickID int32, stakedLiquidityGross *gno.land/p/gnoswap/uint256/v1.Uint, stakedLiquidityDelta *gno.land/p/gnoswap/int256/v1.Int, outsideAccumulation *gno.land/p/gnoswap/uint256/v1.Uint) *gno.land/r/gnoswap/staker/v1.tickCrossEventInfo
NewTickResolver (tick *gno.land/r/gnoswap/staker.Tick) *gno.land/r/gnoswap/staker/v1.TickResolver
NewUnstakedPositions () *gno.land/r/gnoswap/staker/v1.UnstakedPositions
TierRatioFromCounts (tier1Count uint64, tier2Count uint64, tier3Count uint64) struct{Tier1 uint64; Tier2 uint64; Tier3 uint64}
Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.
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.
bptree "gno.land/p/nt/bptree/v0"
9 ufmt "gno.land/p/nt/ufmt/v0"
10
11 "gno.land/p/gnoswap/gnsmath/v1"
12 "gno.land/p/gnoswap/utils/v1"
13
14 sr "gno.land/r/gnoswap/staker"
15 )
16
17 // UnstakedPositions manages exit checkpoints.
18 type UnstakedPositions struct {
19 tree *bptree.BPTree
20 }
21
22 // NewUnstakedPositions creates a new UnstakedPositions instance.
23 //
24 // Returns:
25 // - *UnstakedPositions: Empty exit-checkpoint manager backed by a new B+ tree.
26 func NewUnstakedPositions() *UnstakedPositions {
27 return &UnstakedPositions{
28 tree: sr.NewBPTreeN( 16 ), // positionId -> *UnstakedPosition
29 }
30 }
31
32 // Has checks if a position ID has an exit checkpoint.
33 //
34 // Parameters:
35 // - positionId: Position ID whose exit-checkpoint membership is checked.
36 //
37 // Returns:
38 // - bool: true when an exit checkpoint exists for positionId; false otherwise.
39 func (self *UnstakedPositions) Has(positionId uint64 ) bool {
40 return self.tree.Has(utils.EncodeUint64(positionId))
41 }
42
43 // get retrieves an exit checkpoint by position ID, or nil when there is none.
44 func (self *UnstakedPositions) get(positionId uint64 ) *sr.UnstakedPosition {
45 value := self.tree.Get(utils.EncodeUint64(positionId))
46 if value == nil {
47 return nil
48 }
49
50 position, ok := value.(*sr.UnstakedPosition)
51 if !ok {
52 panic(ufmt.Sprintf( "failed to cast value to *UnstakedPosition: %T" , value))
53 }
54
55 return position
56 }
57
58 // set stores an exit checkpoint for a position ID.
59 func (self *UnstakedPositions) set(positionId uint64 , position *sr.UnstakedPosition) {
60 self.tree.Set(utils.EncodeUint64(positionId), position)
61 }
62
63 // remove deletes an exit checkpoint by position ID.
64 func (self *UnstakedPositions) remove(positionId uint64 ) {
65 self.tree.Remove(utils.EncodeUint64(positionId))
66 }
67
68 // getUnstakedPositions returns the exit checkpoints backed by the store.
69 func (s *stakerV1) getUnstakedPositions() *UnstakedPositions {
70 return &UnstakedPositions{tree: s.store.GetUnstakedPositions()}
71 }
72
73 // uncollectedIncentiveCountOf returns how many checkpoints still owe the incentive.
74 //
75 // The count is per incentive, not per pool: one checkpoint that can never be funded would
76 // otherwise lock the refunds of every other incentive in the same pool.
77 func (s *stakerV1) uncollectedIncentiveCountOf(incentiveId string ) int64 {
78 value := s.store.GetUncollectedIncentiveCounts().Get(incentiveId)
79 if value == nil {
80 return 0
81 }
82
83 count, ok := value.( int64 )
84 if !ok {
85 panic(ufmt.Sprintf( "failed to cast uncollected incentive count to int64: %T" , value))
86 }
87
88 return count
89 }
90
91 // addUncollectedIncentiveCount moves the incentive's count by delta, dropping the entry at zero.
92 func (s *stakerV1) addUncollectedIncentiveCount(incentiveId string , delta int64 ) {
93 addUncollectedIncentiveCountTo(s.store.GetUncollectedIncentiveCounts(), incentiveId, delta)
94 }
95
96 func addUncollectedIncentiveCountTo(counts *bptree.BPTree, incentiveId string , delta int64 ) {
97 count := int64 ( 0 )
98 if value := counts.Get(incentiveId); value != nil {
99 casted, ok := value.( int64 )
100 if !ok {
101 panic(ufmt.Sprintf( "failed to cast uncollected incentive count to int64: %T" , value))
102 }
103 count = casted
104 }
105
106 next := gnsmath.SafeAddInt64(count, delta)
107 if next < 0 {
108 panic(makeErrorWithDetails(
109 errCalculationError,
110 ufmt.Sprintf( "uncollected count of incentive(%s) went negative" , incentiveId),
111 ))
112 }
113
114 if next == 0 {
115 counts.Remove(incentiveId)
116 return
117 }
118
119 counts.Set(incentiveId, next)
120 }
121
122 // recordUnstakedPosition writes the exit checkpoint before the teardown touches the pool.
123 // The deposit's incentive index is brought up to date first, so the checkpoint owes exactly
124 // the incentives the position accrued from.
125 func (s *stakerV1) recordUnstakedPosition(_ int , rlm realm, positionId uint64 , deposit *sr.Deposit, exitTime int64 ) *sr.UnstakedPosition {
126 poolPath := deposit.TargetPoolPath()
127
128 pool, ok := s.getPools().Get(poolPath)
129 if !ok {
130 panic(makeErrorWithDetails(
131 errDataNotFound,
132 ufmt.Sprintf( "pool(%s) does not exist" , poolPath),
133 ))
134 }
135
136 poolResolver := NewPoolResolver(pool)
137 depositResolver := NewDepositResolver(deposit)
138
139 lastUpdatedAt := depositResolver.LastExternalIncentiveUpdatedAt()
140 if lastUpdatedAt < exitTime {
141 poolResolver.IncentivesResolver().IterateIncentiveIdsByTime(lastUpdatedAt, exitTime, func (incentiveId string ) bool {
142 deposit.AddExternalIncentiveId(incentiveId)
143 return false
144 })
145 deposit.SetLastExternalIncentiveUpdatedAt(exitTime)
146 }
147
148 tier, tierRatio, tierCount, err := s.getPoolTier().tierContextOf(poolPath)
149 if err != nil {
150 panic(err)
151 }
152
153 lowerTick := poolResolver.GetOrNewTick(deposit.TickLower())
154 upperTick := poolResolver.GetOrNewTick(deposit.TickUpper())
155 incentiveIds := deposit.GetExternalIncentiveIdList()
156
157 position := sr.NewUnstakedPosition(
158 deposit,
159 exitTime,
160 poolResolver.CurrentTick(exitTime),
161 lowerTick,
162 upperTick,
163 NewTickResolver(lowerTick).CurrentOutsideAccumulation(exitTime).ToString(),
164 NewTickResolver(upperTick).CurrentOutsideAccumulation(exitTime).ToString(),
165 tier,
166 tierRatio,
167 tierCount,
168 s.GetUnstakingFee(),
169 incentiveIds,
170 )
171
172 s.getUnstakedPositions().set(positionId, position)
173
174 counts := s.store.GetUncollectedIncentiveCounts()
175 for _, incentiveId := range incentiveIds {
176 addUncollectedIncentiveCountTo(counts, incentiveId, 1 )
177 }
178
179 return position
180 }
181
182 // dropUnstakedPositionIfCollected removes the checkpoint once every reward source is collected.
183 func (s *stakerV1) dropUnstakedPositionIfCollected(_ int , rlm realm, target *collectTarget) {
184 if !target.checkpoint.FullyCollected() {
185 return
186 }
187
188 s.getUnstakedPositions().remove(target.positionId)
189
190 previousRealm := rlm.Previous()
191 chain.Emit(
192 "ClearUnstakedPosition" ,
193 "prevAddr" , previousRealm.Address().String(),
194 "prevRealm" , previousRealm.PkgPath(),
195 "positionId" , utils.FormatUint(target.positionId),
196 "poolPath" , target.deposit.TargetPoolPath(),
197 "exitTime" , utils.FormatInt(target.checkpoint.ExitTime()),
198 "currentTime" , utils.FormatInt(time.Now().Unix()),
199 "currentHeight" , utils.FormatInt(runtime.ChainHeight()),
200 )
201 }
202
203 // HasUnstakedPosition reports whether a position is staked no longer but still has uncollected rewards.
204 //
205 // Parameters:
206 // - positionId: Position ID whose exit-checkpoint membership is checked.
207 //
208 // Returns:
209 // - bool: true when positionId has an exit checkpoint; false otherwise.
210 func (s *stakerV1) HasUnstakedPosition(positionId uint64 ) bool {
211 return s.getUnstakedPositions().Has(positionId)
212 }
213
214 // GetUnstakedPositionExitTime returns when an unstaked position stopped accruing rewards.
215 //
216 // Parameters:
217 // - positionId: Position ID whose exit checkpoint is queried.
218 //
219 // Returns:
220 // - int64: Exit timestamp in Unix seconds.
221 // - error: Non-nil when positionId has no uncollected exit checkpoint; nil on success.
222 func (s *stakerV1) GetUnstakedPositionExitTime(positionId uint64 ) ( int64 , error ) {
223 position := s.getUnstakedPositions().get(positionId)
224 if position == nil {
225 return 0 , ufmt.Errorf( "%v: positionId(%d) has no uncollected reward" , errDataNotFound, positionId)
226 }
227
228 return position.ExitTime(), nil
229 }
230
231 // GetUnstakedPositionPendingIncentives returns the incentives an unstaked position has yet to
232 // collect.
233 //
234 // Parameters:
235 // - positionId: Position ID whose pending incentive IDs are queried.
236 //
237 // Returns:
238 // - []string: External incentive IDs with rewards still pending for the checkpoint.
239 // - error: Non-nil when positionId has no uncollected exit checkpoint; nil on success.
240 func (s *stakerV1) GetUnstakedPositionPendingIncentives(positionId uint64 ) ([] string , error ) {
241 position := s.getUnstakedPositions().get(positionId)
242 if position == nil {
243 return nil , ufmt.Errorf( "%v: positionId(%d) has no uncollected reward" , errDataNotFound, positionId)
244 }
245
246 return position.PendingIncentiveIdList(), nil
247 }
248
249 // GetUncollectedIncentiveCount returns how many unstaked positions still owe a reward from the
250 // incentive; EndExternalIncentive is refused while it is non-zero.
251 //
252 // Parameters:
253 // - incentiveId: External incentive identifier whose outstanding checkpoint count is queried.
254 //
255 // Returns:
256 // - int64: Number of exit checkpoints still owing incentiveId; zero permits incentive finalization.
257 func (s *stakerV1) GetUncollectedIncentiveCount(incentiveId string ) int64 {
258 return s.uncollectedIncentiveCountOf(incentiveId)
259 }
260
*gno.land/r/gnoswap/staker/v1.stakerV1