PathrockNetwork Gno Explorer
HomeBlocksTransactionsTokensRealmsPackagesValidatorsAnalytics

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/staker/v1

Realm
Open in gnoweb ↗

Overview

Kind
Realm (renderable)
Name
v1
Namespace
gnoswap / staker
Files
28 (README)(gnomod.toml)
Exported functions
14
Module
gno.land/r/gnoswap/staker/v1
gno
0.9

Files (28)

  • README.mdmarkdown
  • gnomod.tomltoml
  • assert.gnogno
  • calculate_pool_position_reward.gnogno
  • consts.gnogno
  • doc.gnogno
  • emits.gnogno
  • errors.gnogno
  • event_info.gnogno
  • external_deposit_fee.gnogno
  • external_incentive.gnogno
  • external_token_list.gnogno
  • getter_utils.gnogno
  • getter.gnogno
  • init.gnogno
  • instance.gnogno
  • manage_pool_tier_and_warmup.gnogno
  • protocol_fee_unstaking.gnogno
  • render.gnogno
  • reward_calculation_incentives.gnogno
  • reward_calculation_pool_tier.gnogno
  • reward_calculation_pool.gnogno
  • reward_calculation_tick.gnogno
  • reward_calculation_warmup.gnogno
  • staker.gnogno
  • type.gnogno
  • unstaked_position.gnogno
  • utils.gnogno
  • reward_calculation_incentives.gnogno
    1package staker23import (4	"gno.land/p/gnoswap/gnsmath/v1"5	u256 "gno.land/p/gnoswap/uint256/v1"6	bptree "gno.land/p/nt/bptree/v0"78

    Functions

    • 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.

    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.

    sr "gno.land/r/gnoswap/staker"
    9)
    10
    11type IncentivesResolver struct {
    12 *sr.Incentives
    13}
    14
    15// NewIncentivesResolver wraps the persisted external-incentive state for lookup and mutation.
    16//
    17// Parameters:
    18// - incentives: External incentive state containing the incentive tree and unclaimable periods.
    19//
    20// Returns:
    21// - resolver: Resolver backed by incentives.
    22func NewIncentivesResolver(incentives *sr.Incentives) *IncentivesResolver {
    23 return &IncentivesResolver{
    24 Incentives: incentives,
    25 }
    26}
    27
    28// Get resolves an external incentive by its identifier.
    29//
    30// Parameters:
    31// - incentiveId: External incentive identifier used as the tree key.
    32//
    33// Returns:
    34// - incentive: Stored external incentive pointer when the ID exists; nil when it is absent.
    35// - found: True when incentiveId is present in the tree; false otherwise.
    36func (self *IncentivesResolver) Get(incentiveId string) (*sr.ExternalIncentive, bool) {
    37 return retrieveIncentive(self.IncentiveTrees(), incentiveId)
    38}
    39
    40// GetIncentiveResolver resolves an incentive ID to its field accessor.
    41//
    42// Parameters:
    43// - incentiveId: External incentive identifier to resolve.
    44//
    45// Returns:
    46// - resolver: Resolver for the stored incentive when found; nil when incentiveId is absent.
    47// - found: True when incentiveId resolves to a stored incentive; false otherwise.
    48func (self *IncentivesResolver) GetIncentiveResolver(incentiveId string) (*ExternalIncentiveResolver, bool) {
    49 if incentive, ok := self.Get(incentiveId); ok {
    50 return NewExternalIncentiveResolver(incentive), true
    51 }
    52 return nil, false
    53}
    54
    55func retrieveIncentive(tree *bptree.BPTree, id string) (*sr.ExternalIncentive, bool) {
    56 value := tree.Get(id)
    57 if value == nil {
    58 return nil, false
    59 }
    60 v, ok := value.(*sr.ExternalIncentive)
    61 if !ok {
    62 panic("failed to cast value to *sr.ExternalIncentive")
    63 }
    64 return v, true
    65}
    66
    67// Create a new external incentive
    68// Panics if the incentive already exists.
    69func (self *IncentivesResolver) create(incentive *sr.ExternalIncentive) {
    70 self.Incentives.SetIncentive(incentive.IncentiveId(), incentive)
    71 self.Incentives.AddIncentiveByStartTime(incentive.StartTimestamp(), incentive.IncentiveId())
    72}
    73
    74// update updates an existing incentive with new information
    75func (self *IncentivesResolver) update(incentive *sr.ExternalIncentive) {
    76 self.Incentives.SetIncentive(incentive.IncentiveId(), incentive)
    77}
    78
    79// remove drops an incentive from both the incentive tree and the start-time
    80// discovery index. It is only valid for an incentive that has not started: no
    81// deposit can reference it yet, so nothing is left pointing at a missing record.
    82func (self *IncentivesResolver) remove(incentive *sr.ExternalIncentive) {
    83 self.Incentives.RemoveIncentive(incentive.IncentiveId())
    84 self.Incentives.RemoveIncentiveByStartTime(incentive.StartTimestamp(), incentive.IncentiveId())
    85}
    86
    87// starts incentive unclaimable period for this pool
    88func (self *IncentivesResolver) startUnclaimablePeriod(startTimestamp int64) {
    89 self.Incentives.SetUnclaimablePeriod(startTimestamp, int64(0))
    90}
    91
    92// ends incentive unclaimable period for this pool
    93// ignores if currently not in unclaimable period
    94func (self *IncentivesResolver) endUnclaimablePeriod(endTimestamp int64) {
    95 startTimestamp := int64(0)
    96 self.UnclaimablePeriods().ReverseIterate(0, endTimestamp, func(key int64, value any) bool {
    97 v, ok := value.(int64)
    98 if !ok {
    99 panic("failed to cast value to int64")
    100 }
    101 if v != 0 {
    102 // Already ended, no need to update
    103 // keeping startTimestamp as 0 to indicate this
    104 return true
    105 }
    106 startTimestamp = key
    107 return true
    108 })
    109
    110 if startTimestamp == 0 {
    111 // No ongoing unclaimable period found
    112 return
    113 }
    114
    115 if startTimestamp == endTimestamp {
    116 self.Incentives.RemoveUnclaimablePeriod(startTimestamp)
    117 } else {
    118 self.Incentives.SetUnclaimablePeriod(startTimestamp, endTimestamp)
    119 }
    120
    121 // Accumulate the just-closed period into every active incentive
    122 self.accumulateUnclaimableSeconds(startTimestamp, endTimestamp)
    123}
    124
    125// accumulateUnclaimableSeconds adds the unclaimable duration between
    126// startTimestamp and endTimestamp to every non-refunded incentive whose window
    127// overlaps the period. The accumulator is updated in place on the stored
    128// incentive pointers, so no tree write is required here.
    129func (self *IncentivesResolver) accumulateUnclaimableSeconds(startTimestamp, endTimestamp int64) {
    130 self.Incentives.IterateIncentives(func(_ string, incentive *sr.ExternalIncentive) bool {
    131 if incentive.Refunded() {
    132 return false
    133 }
    134
    135 duration := calculateUnClaimableDuration(
    136 startTimestamp,
    137 endTimestamp,
    138 incentive.StartTimestamp(),
    139 incentive.EndTimestamp(),
    140 )
    141 if duration > 0 {
    142 incentive.SetUnclaimableSeconds(gnsmath.SafeAddInt64(incentive.UnclaimableSeconds(), duration))
    143 }
    144 return false
    145 })
    146}
    147
    148// calculate unclaimable reward from the per-incentive unclaimable seconds
    149// accumulator instead of scanning the unbounded unclaimable periods tree.
    150func (self *IncentivesResolver) calculateUnclaimableReward(incentiveId string) int64 {
    151 incentive, ok := self.Get(incentiveId)
    152 if !ok {
    153 return 0
    154 }
    155
    156 // The accumulator holds the duration of every closed unclaimable period
    157 // that overlaps the incentive window.
    158 timeDiff := incentive.UnclaimableSeconds()
    159
    160 // Ongoing unclaimable periods (end == 0) are not yet accumulated because
    161 // their end is unknown. They are resolved here by treating them as
    162 // extending to the incentive end. Unclaimable periods never overlap and
    163 // are recorded in ascending order, so an ongoing period is always the
    164 // most recently started one and therefore the highest key in the tree.
    165 // ReverseIterate visits the highest key first, so each scan below finds
    166 // the only ongoing period that can affect the reward (if any) on its
    167 // first visit and stops - the scan is bounded regardless of how many
    168 // periods exist in the tree.
    169 //
    170 // Tail 1: the ongoing period that started before the incentive window
    171 // (e.g. the initial pool-creation period). If the highest period starting
    172 // before the window is already closed, no ongoing period can overlap the
    173 // incentive start and there is nothing to add.
    174 self.UnclaimablePeriods().ReverseIterate(0, incentive.StartTimestamp()-1, func(startTimestamp int64, value any) bool {
    175 endTimestamp, ok := value.(int64)
    176 if !ok {
    177 panic("failed to cast value to int64")
    178 }
    179 if endTimestamp != 0 {
    180 // Already closed - the duration is already accumulated in
    181 // UnclaimableSeconds(), and being the highest key it is also the
    182 // latest period, so no ongoing period can exist below it.
    183 return true
    184 }
    185
    186 timeDiff = gnsmath.SafeAddInt64(timeDiff, calculateUnClaimableDuration(
    187 startTimestamp,
    188 incentive.EndTimestamp(),
    189 incentive.StartTimestamp(),
    190 incentive.EndTimestamp(),
    191 ))
    192 return true
    193 })
    194
    195 // Tail 2: the ongoing period that started within the incentive window.
    196 // The upper bound is endTime-1 to mirror the Iterate(start, end)
    197 // half-open range, which excludes a period starting exactly at endTime
    198 // (e.g. the initial pool-creation period that coincides with endTime).
    199 self.UnclaimablePeriods().ReverseIterate(incentive.StartTimestamp(), incentive.EndTimestamp()-1, func(startTimestamp int64, value any) bool {
    200 endTimestamp, ok := value.(int64)
    201 if !ok {
    202 panic("failed to cast value to int64")
    203 }
    204 if endTimestamp != 0 {
    205 // Already closed - the duration is already accumulated in
    206 // UnclaimableSeconds(), and being the highest key it is also the
    207 // latest period, so no ongoing period can exist below it.
    208 return true
    209 }
    210
    211 timeDiff = gnsmath.SafeAddInt64(timeDiff, calculateUnClaimableDuration(
    212 startTimestamp,
    213 incentive.EndTimestamp(),
    214 incentive.StartTimestamp(),
    215 incentive.EndTimestamp(),
    216 ))
    217 return true
    218 })
    219
    220 // rewardPerSecondX128 = rps << 128, so dividing by q128 here recovers the
    221 // floor of (timeDiff * rps) without the truncation that an int64 rps would
    222 // have introduced at incentive-creation time.
    223 unclaimable := u256.MulDiv(
    224 u256.NewUintFromInt64(timeDiff),
    225 incentive.RewardPerSecondX128(),
    226 q128,
    227 )
    228 return gnsmath.SafeConvertToInt64(unclaimable)
    229}
    230
    231// calculateUnClaimableDuration calculates the duration of overlap between an unclaimable period and incentive period
    232func calculateUnClaimableDuration(unclaimableStart, unclaimableEnd, incentiveStartTimestamp, incentiveEndTimestamp int64) int64 {
    233 // Use later timestamp between unclaimable start and incentive start
    234 startTime := unclaimableStart
    235 if startTime < incentiveStartTimestamp {
    236 startTime = incentiveStartTimestamp
    237 }
    238
    239 // Use earlier timestamp between unclaimable end and incentive end
    240 endTime := unclaimableEnd
    241 if endTime > incentiveEndTimestamp {
    242 endTime = incentiveEndTimestamp
    243 }
    244
    245 // Return 0 if no overlap
    246 if endTime < startTime {
    247 return 0
    248 }
    249
    250 // Calculate overlap duration
    251 return gnsmath.SafeSubInt64(endTime, startTime)
    252}
    253
    *gno.land/r/gnoswap/staker/v1.stakerV1