Transaction

A92489E4C845F5…D7AFFA1C127B

Block 77,258 · index 0 · indexed

Summary

Hash
A92489E4C845F512188F45E9A11EBCF4C35739E3A219BAB1AFBAD7AFFA1C127B
Block
77,258
Size
271544 bytes
Gas used
340,156,853 / 408,188,164
Fee
408189ugnot
Status
success

Messages

#1AddPackagegno.land/r/gnoswap/staker24 arguments

Arguments · 24

  1. #1staker
  2. #2README.md
  3. #3# Staker Liquidity mining and reward distribution for LP positions. ## Overview Staker manages distribution of internal (GNS emission) and external (user-provided) rewards to staked LP positions, with time-weighted rewards and warmup periods. ## Gnoweb The root `Render("")` delegates to the active implementation and shows realm identity, the halt flag, stored record counts, cumulative GNS emissions, the cached emission rate, incentive requirements, tier allocations, unstaking fees, and warmup stages. GNS amounts use six-decimal base units; external rewards use their token's base units. Warmup durations are per-stage seconds, with the final stage shown as unbounded. Rendering reads stored counts and fixed configuration without traversing positions or incentives. Unsupported paths return `404`. ## Configuration - **Deposit GNS Amount**: 100,000 GNS per external incentive (default; governance-adjustable) - **Minimum Reward Amount**: 1,000 token units (default for external incentive creation) - **Unstaking Fee**: 1% default (100 basis points; configurable from 0 to 10%) - **Internal Pool Tiers**: 1, 2, or 3 (assigned per pool); external-only pools can also be stakeable - **Warmup Schedule**: 30/50/70/100% over default cumulative windows of 0-5, 5-15, 15-45, and 45+ days - **External Token Policy**: Approved reward tokens; pool-pair tokens are also accepted for their own pool unless explicitly denied ## Core Features ### Internal Rewards (GNS Emission) - Allocated to tiered pools (tiers 1, 2, 3) - Split across tiers by TierRatio - Distributed proportionally to in-range liquidity - Unclaimed rewards go to community pool ### External Rewards (User Incentives) - Created for specific pools - Constant reward per second over the incentive window; the stored rate is Q128-scaled as `(rewardAmount << 128) / duration` - Proportional to staked liquidity - `EndExternalIncentive` returns only the unclaimable/remainder portion and GNS deposit to its explicit refund address; rewards still owed by live positions remain claimable ### Warmup Periods Every staked position progresses through warmup periods. The default finite durations are 5, 10, and 30 days, followed by a final `math.MaxInt64` tier: - 0-5 days: 30% of the calculated reward - 5-15 days: 50% of the calculated reward - 15-45 days: 70% of the calculated reward - 45+ days: 100% of the calculated reward Governance may change the finite durations. Warmup ratios are applied before the staking-reward fee: internal GNS penalties go to the community pool, while external penalties accumulate on the incentive and are collected separately to an explicit address after `EndExternalIncentive`. ## Key Functions ### `StakeToken` Stakes LP position NFT to earn rewards. ### `UnStakeToken` Unstakes a position and records an exit checkpoint for its rewards. It neither calculates nor pays them: withdrawing must never depend on the reward side. ### `CollectReward` Collects accumulated rewards. Takes a position that was unstaked without collecting as well as a staked one, so withdrawing is `UnStakeToken` plus one collect. A collect on an unstaked position is permissionless, since it can only ever pay that position's owner. ### `CreateExternalIncentive` Creates an external reward program for a specific pool. Any caller may create one after satisfying the reward-token allowlist/denial, duration, start-time, reward-minimum, and GNS-deposit checks. ### `EndExternalIncentive` Ends an incentive after its end timestamp and finalizes its refundable unclaimable/remainder amount. The reward tokens and GNS deposit are sent to the caller-supplied `refundAddress`; only the creator or admin may call it, and an outstanding exit checkpoint for that incentive blocks ending. ### `CancelExternalIncentive` Removes an incentive that has not started and refunds its reward tokens and GNS deposit to the creator. Callable by admin, governance, or the creator; the reward-token refund is capped by the balance held by the staker. ## Reward Calculation Logic ### Tier Ratio Distribution Emission split across tiers based on active pools: ``` If only tier 1 has pools: [100%, 0%, 0%] If tiers 1 & 3 have pools: [80%, 0%, 20%] If tiers 1 & 2 have pools: [70%, 30%, 0%] If all tiers have pools: [50%, 30%, 20%] ``` Mathematical representation: ```math TierRatio(t) = [100, 0, 0] if Count(2) = 0 ∧ Count(3) = 0 [80, 0, 20] if Count(2) = 0 [70, 30, 0] if Count(3) = 0 [50, 30, 20] otherwise ``` ### Pool Reward Formula ```math poolReward(pool) = (emission × TierRatio[tier(pool)] / 100) / Count(tier(pool)) ``` Here `emission` is the already-allocated per-second GNS amount returned by the emission module for liquidity stakers. It is split by the tier percentage and then divided among pools in that tier: ```math emission = GetStakerEmissionAmountPerSecond() ``` ### Position Reward Calculation The reward for each position is calculated through: 1. **Resolve the persisted/halving per-second reward schedule** (read-only) 2. **Retrieve position state** from deposit records or an exit checkpoint 3. **Calculate internal rewards** if the pool has an internal tier 4. **Calculate external rewards** for the incentive IDs 5. **Apply warmup ratios and penalties** based on stake duration Collection may separately advance reward caches and persist newly discovered incentive IDs; the read-only calculation itself does not write those caches. Mathematical formula for total reward ratio: ```math TotalRewardRatio(s,e) = Σ[i=0 to m-1] ΔRaw(αᵢ, βᵢ) × rᵢ where: αᵢ = max(s, Hᵢ₋₁) βᵢ = min(e, Hᵢ) ΔRaw(a, b) = CalcRaw(b) - CalcRaw(a) CalcRaw(h) = L(h) - U(h) if tick(h) < ℓ U(h) - L(h) if tick(h) ≥ u G(h) - (L(h) + U(h)) otherwise where: L(h) = tickLower.OutsideAccumulation(h) U(h) = tickUpper.OutsideAccumulation(h) G(h) = globalRewardRatioAccumulation(h) ℓ = tickLower.id u = tickUpper.id ``` Final position reward: ```math finalReward = TotalRewardRatio × poolReward × positionLiquidity = ∫[s to e] (poolReward × positionLiquidity) / TotalStakedLiquidity(h) dh ``` ### Tick Cross Hook When price crosses an initialized tick with staked positions: 1. **Updates staked liquidity** - Adjusts total staked liquidity 2. **Updates reward accumulation** - Recalculates `globalRewardRatioAccumulation` 3. **Manages unclaimable periods** - Starts/ends periods with no in-range liquidity 4. **Updates tick accumulation** - Adjusts `CurrentOutsideAccumulation` The `globalRewardRatioAccumulation` tracks the integral: ```math globalRewardRatioAccumulation = ∫ 1/TotalStakedLiquidity(h) dh ``` This integral is only computed when `TotalStakedLiquidity(h) ≠ 0`, enabling precise reward calculation even as liquidity changes. ### Reward State Tracking The system maintains: - **Global accumulation**: Tracks reward ratio across all positions - **Tick accumulation**: Tracks rewards "outside" each tick - **Position state**: Individual reward calculation parameters ## Approval Requirements - `StakeToken` moves the position NFT to the staker realm through `gnft.TransferFrom`, so the caller must approve the staker on that NFT first with `gnft.Approve(cross(cur), stakerAddress, positionId)`, or grant `gnft.SetApprovalForAll(cross(cur), stakerAddress, true)`. - `CreateExternalIncentive` pulls two amounts into the staker realm: the reward token amount and the GNS deposit. Approve the staker realm for both token contracts before calling. - `UnStakeToken`, the reward-collection functions, `EndExternalIncentive`, and `CancelExternalIncentive` pay out to the caller or to a supplied address and require no approval. ```go // Approve the staker on the position NFT, then stake stakerAddress := access.MustGetAddress(prabc.ROLE_STAKER.String()) gnft.Approve(cross(cur), stakerAddress, grc721.TokenID("123")) StakeToken(cross(cur), 123, "") // GNS pays both the external reward and the required deposit gns.Approve(cross(cur), stakerAddress, 1_000_000_000+GetDepositGnsAmount()) ``` ## Usage The proxy functions receive a realm argument. From a caller realm with `cur realm`, pass `cross(cur)` as that first argument: ```go // Stake an existing position StakeToken(cross(cur), 123, "g1referrer...") // Create an external incentive (rewardAmount is an int64 token-unit amount) CreateExternalIncentive( cross(cur), "gno.land/r/gnoland/wugnot.wugnot:gno.land/r/gnoswap/gns.GNS:3000", "gno.land/r/gnoswap/gns.GNS", 1_000_000_000, startTime, endTime, ) // Collect while the position is staked CollectReward(cross(cur), 123) // Unstake: this returns the NFT and creates an exit checkpoint; it does not collect UnStakeToken(cross(cur), 123) // Collect the checkpoint, either per source or all at once CollectEmissionReward(cross(cur), 123) CollectExternalIncentiveReward(cross(cur), 123, incentiveId) ``` ## Security - Positions locked during staking - External incentives require GNS deposit - Warmup periods prevent gaming - Unclaimed rewards properly redirected - Hook integration ensures accurate tracking
  4. #4accessor.gno
  5. #5package staker import ( "errors" "gno.land/p/nt/grc721/v0" "gno.land/r/gnoswap/access/v1" "gno.land/r/gnoswap/emission" "gno.land/r/gnoswap/gnft" "gno.land/r/gnoswap/pool" ) type PoolAccessor interface { // ExistsPoolPath reports whether a pool is registered at poolPath. // // Parameters: // - poolPath: Pool path whose registration is checked. // // Returns: // - bool: true when a pool is registered at poolPath; false otherwise. ExistsPoolPath(poolPath string) bool // GetSlot0Tick returns the current slot-0 tick for a registered pool. // // Parameters: // - poolPath: Pool path whose current tick is queried. // // Returns: // - int32: Current signed slot-0 tick; the accessor panics if the underlying pool query fails. GetSlot0Tick(poolPath string) int32 // GetSlot0SqrtPriceX96 returns a pool's current Q96-scaled square-root price. // // Parameters: // - poolPath: Pool path whose current square-root price is queried. // // Returns: // - string: Decimal representation of the Q96-scaled square-root price; the accessor panics if the underlying query fails. GetSlot0SqrtPriceX96(poolPath string) string // SetTickCrossHook registers a callback for pool tick-crossing events. // // Parameters: // - _: Internal call discriminator; callers pass 0. // - rlm: Propagated realm context; it must be current before the hook is registered. // - hook: Callback invoked with the internal discriminator, current pool realm, pool path, crossed tick ID, swap direction (zeroForOne), and the event timestamp in Unix seconds. SetTickCrossHook(_ int, rlm realm, hook func(_ int, rlm realm, poolPath string, tickId int32, zeroForOne bool, timestamp int64)) // SetSwapStartHook registers a callback invoked when a pool swap starts. // // Parameters: // - _: Internal call discriminator; callers pass 0. // - rlm: Propagated realm context; it must be current before the hook is registered. // - hook: Callback invoked with the internal discriminator, current pool realm, pool path, and swap-start timestamp in Unix seconds. SetSwapStartHook(_ int, rlm realm, hook func(_ int, rlm realm, poolPath string, timestamp int64)) // SetSwapEndHook registers a callback invoked when a pool swap ends. // // Parameters: // - _: Internal call discriminator; callers pass 0. // - rlm: Propagated realm context; it must be current before the hook is registered. // - hook: Callback invoked with the internal discriminator, current pool realm, and pool path; its error is propagated by the pool hook. SetSwapEndHook(_ int, rlm realm, hook func(_ int, rlm realm, poolPath string) error) } type poolAccessor struct{} // ExistsPoolPath reports whether a pool is registered at poolPath. // // Parameters: // - poolPath: Pool path whose registration is checked. // // Returns: // - bool: true when a pool is registered at poolPath; false otherwise. func (p *poolAccessor) ExistsPoolPath(poolPath string) bool { return pool.ExistsPoolPath(poolPath) } // GetSlot0Tick returns the current slot-0 tick for a registered pool. // // Parameters: // - poolPath: Pool path whose current tick is queried. // // Returns: // - int32: Current signed slot-0 tick; the accessor panics if the underlying pool query fails. func (p *poolAccessor) GetSlot0Tick(poolPath string) int32 { tick, err := pool.GetSlot0Tick(poolPath) if err != nil { panic(err) } return tick } // GetSlot0SqrtPriceX96 returns a pool's current Q96-scaled square-root price. // // Parameters: // - poolPath: Pool path whose current square-root price is queried. // // Returns: // - string: Decimal representation of the Q96-scaled square-root price; the accessor panics if the underlying query fails. func (p *poolAccessor) GetSlot0SqrtPriceX96(poolPath string) string { sqrtPriceX96, err := pool.GetSlot0SqrtPriceX96(poolPath) if err != nil { panic(err) } return sqrtPriceX96 } // SetTickCrossHook registers a callback for pool tick-crossing events. // // Parameters: // - _: Internal call discriminator; callers pass 0. // - rlm: Propagated realm context; it must be current before the hook is registered. // - hook: Callback invoked with the internal discriminator, current pool realm, pool path, crossed tick ID, swap direction (zeroForOne), and the event timestamp in Unix seconds. func (p *poolAccessor) SetTickCrossHook(_ int, rlm realm, hook func(_ int, rlm realm, poolPath string, tickId int32, zeroForOne bool, timestamp int64)) { access.AssertIsRlmCurrent(0, rlm) pool.SetTickCrossHook(cross(rlm), func(cur realm, poolPath string, tickId int32, zeroForOne bool, timestamp int64) { hook(0, cur, poolPath, tickId, zeroForOne, timestamp) }) } // SetSwapStartHook registers a callback invoked when a pool swap starts. // // Parameters: // - _: Internal call discriminator; callers pass 0. // - rlm: Propagated realm context; it must be current before the hook is registered. // - hook: Callback invoked with the internal discriminator, current pool realm, pool path, and swap-start timestamp in Unix seconds. func (p *poolAccessor) SetSwapStartHook(_ int, rlm realm, hook func(_ int, rlm realm, poolPath string, timestamp int64)) { access.AssertIsRlmCurrent(0, rlm) pool.SetSwapStartHook(cross(rlm), func(cur realm, poolPath string, timestamp int64) { hook(0, cur, poolPath, timestamp) }) } // SetSwapEndHook registers a callback invoked when a pool swap ends. // // Parameters: // - _: Internal call discriminator; callers pass 0. // - rlm: Propagated realm context; it must be current before the hook is registered. // - hook: Callback invoked with the internal discriminator, current pool realm, and pool path; its error is propagated by the pool hook. func (p *poolAccessor) SetSwapEndHook(_ int, rlm realm, hook func(_ int, rlm realm, poolPath string) error) { access.AssertIsRlmCurrent(0, rlm) pool.SetSwapEndHook(cross(rlm), func(cur realm, poolPath string) error { return hook(0, cur, poolPath) }) } func newPoolAccessor() PoolAccessor { return &poolAccessor{} } type EmissionAccessor interface { // MintAndDistributeGns mints and distributes scheduled GNS emission through the emission realm. // // Parameters: // - _: Internal call discriminator; callers pass 0. // - rlm: Propagated realm context; it must be current before crossing into the emission realm. // // Returns: // - int64: GNS amount distributed during this call, including any carried-forward amount. // - bool: false only when emission is halted; true when processing completes, including a no-op call. MintAndDistributeGns(_ int, rlm realm) (int64, bool) // GetStakerEmissionAmountPerSecond returns the current GNS emission rate allocated to liquidity stakers. // // Returns: // - int64: Current staker allocation in GNS units per second. // - error: Non-nil when the emission distribution configuration cannot provide a staker rate; nil otherwise. GetStakerEmissionAmountPerSecond() (int64, error) // GetStakerEmissionAmountPerSecondInRange returns staker emission-rate change points over an inclusive time range. // // Parameters: // - start: Inclusive lower bound as a Unix timestamp. // - end: Inclusive upper bound as a Unix timestamp. // // Returns: // - []int64: Unix timestamps at which the underlying GNS emission rate changes. // - []int64: Staker emission amounts in GNS units per second at the corresponding timestamps. // - error: Non-nil when the emission distribution configuration is invalid; nil when both slices are produced. GetStakerEmissionAmountPerSecondInRange(start, end int64) ([]int64, []int64, error) // SetOnDistributionPctChangeCallback registers a callback for staker distribution-percentage changes. // // Parameters: // - _: Internal call discriminator; callers pass 0. // - rlm: Propagated realm context; it must be current before the callback is registered. // - callback: Callback invoked with the internal discriminator, current emission realm, and the new staker emission amount per second. SetOnDistributionPctChangeCallback(_ int, rlm realm, callback func(_ int, rlm realm, emissionAmountPerSecond int64)) } type emissionAccessor struct{} // MintAndDistributeGns mints and distributes scheduled GNS emission through the emission realm. // // Parameters: // - _: Internal call discriminator; callers pass 0. // - rlm: Propagated realm context; it must be current before crossing into the emission realm. // // Returns: // - int64: GNS amount distributed during this call, including any carried-forward amount. // - bool: false only when emission is halted; true when processing completes, including a no-op call. func (e *emissionAccessor) MintAndDistributeGns(_ int, rlm realm) (int64, bool) { access.AssertIsRlmCurrent(0, rlm) return emission.MintAndDistributeGns(cross(rlm)) } // GetStakerEmissionAmountPerSecond returns the current GNS emission rate allocated to liquidity stakers. // // Returns: // - int64: Current staker allocation in GNS units per second. // - error: Non-nil when the emission distribution configuration cannot provide a staker rate; nil otherwise. func (e *emissionAccessor) GetStakerEmissionAmountPerSecond() (int64, error) { return emission.GetStakerEmissionAmountPerSecond() } // GetStakerEmissionAmountPerSecondInRange returns staker emission-rate change points over an inclusive time range. // // Parameters: // - start: Inclusive lower bound as a Unix timestamp. // - end: Inclusive upper bound as a Unix timestamp. // // Returns: // - []int64: Unix timestamps at which the underlying GNS emission rate changes. // - []int64: Staker emission amounts in GNS units per second at the corresponding timestamps. // - error: Non-nil when the emission distribution configuration is invalid; nil when both slices are produced. func (e *emissionAccessor) GetStakerEmissionAmountPerSecondInRange(start, end int64) ([]int64, []int64, error) { return emission.GetStakerEmissionAmountPerSecondInRange(start, end) } // SetOnDistributionPctChangeCallback registers a callback for staker distribution-percentage changes. // // Parameters: // - _: Internal call discriminator; callers pass 0. // - rlm: Propagated realm context; it must be current before the callback is registered. // - callback: Callback invoked with the internal discriminator, current emission realm, and the new staker emission amount per second. func (e *emissionAccessor) SetOnDistributionPctChangeCallback(_ int, rlm realm, callback func(_ int, rlm realm, emissionAmountPerSecond int64)) { access.AssertIsRlmCurrent(0, rlm) // Wrap the caller-provided callback in an adapter constructed HERE, inside // the /r/gnoswap/staker domain package. By borrow rule #3 the wrapper // closure is owned by /r/gnoswap/staker (its construction realm), not by the // v1 implementation that passed `callback` in. This mirrors the swap/tick // hook accessors above and lets emission persist the callback into its // package-level var without hitting "cannot persist realm value" (which // fired when a v1-constructed closure was stored there directly). emission.SetOnDistributionPctChangeCallback(cross(rlm), func(cur realm, emissionAmountPerSecond int64) { callback(0, cur, emissionAmountPerSecond) }) } func newEmissionAccessor() EmissionAccessor { return &emissionAccessor{} } type NFTAccessor interface { // Approve grants an address permission to transfer a specific NFT. // // Parameters: // - _: Internal call discriminator; callers pass 0. // - rlm: Propagated realm context; it must be current before crossing into the NFT realm. // - approved: Address receiving permission for tid. // - tid: NFT token ID whose approval is changed. // // Returns: // - error: Non-nil when the NFT realm rejects the approval or the realm context is spoofed; nil on success. Approve(_ int, rlm realm, approved address, tid grc721.TokenID) error // Mint creates an NFT with tid and transfers it to to. // // Parameters: // - _: Internal call discriminator; callers pass 0. // - rlm: Propagated realm context; it must be current before crossing into the NFT realm. // - to: Address receiving the newly minted NFT. // - tid: Token ID to mint. // // Returns: // - grc721.TokenID: The minted token ID, equal to tid. Mint(_ int, rlm realm, to address, tid grc721.TokenID) grc721.TokenID // Burn destroys an NFT. // // Parameters: // - _: Internal call discriminator; callers pass 0. // - rlm: Propagated realm context; it must be current before crossing into the NFT realm. // - tid: NFT token ID to burn. Burn(_ int, rlm realm, tid grc721.TokenID) // TransferFrom moves an NFT from its current owner to another address. // // Parameters: // - _: Internal call discriminator; callers pass 0. // - rlm: Propagated realm context; it must be current before crossing into the NFT realm. // - from: Current owner address of tid. // - to: Recipient address for tid. // - tid: NFT token ID to transfer. // // Returns: // - error: Non-nil when the NFT realm rejects the transfer or the realm context is spoofed; nil on success. TransferFrom(_ int, rlm realm, from, to address, tid grc721.TokenID) error // TotalSupply returns the number of NFTs currently minted and not burned. // // Returns: // - int64: Current NFT collection supply. TotalSupply() int64 // Exists reports whether an NFT token ID is currently minted. // // Parameters: // - tid: NFT token ID to look up. // // Returns: // - bool: true when tid has an owner in the NFT ledger; false when it does not exist. Exists(tid grc721.TokenID) bool // MustOwnerOf returns the owner of an NFT and panics when tid is invalid. // // Parameters: // - tid: NFT token ID whose owner is required. // // Returns: // - address: Current owner address of tid; the accessor panics if tid does not exist. MustOwnerOf(tid grc721.TokenID) address // OwnerOf returns the owner of an NFT without panicking on lookup failure. // // Parameters: // - tid: NFT token ID whose owner is queried. // // Returns: // - address: Current owner address, or the zero address when lookup fails. // - error: Non-nil when tid does not exist or the NFT realm cannot resolve its owner. OwnerOf(tid grc721.TokenID) (address, error) } type gnftAccessor struct{} // Approve grants an address permission to transfer a specific NFT. // // Parameters: // - _: Internal call discriminator; callers pass 0. // - rlm: Propagated realm context; it must be current before crossing into the NFT realm. // - approved: Address receiving permission for tid. // - tid: NFT token ID whose approval is changed. // // Returns: // - error: Non-nil when the NFT realm rejects the approval or the realm context is spoofed; nil on success. func (n *gnftAccessor) Approve(_ int, rlm realm, approved address, tid grc721.TokenID) error { if !rlm.IsCurrent() { return errors.New(ErrSpoofedRealm) } return gnft.Approve(cross(rlm), approved, tid) } // Mint creates an NFT with tid and transfers it to to. // // Parameters: // - _: Internal call discriminator; callers pass 0. // - rlm: Propagated realm context; it must be current before crossing into the NFT realm. // - to: Address receiving the newly minted NFT. // - tid: Token ID to mint. // // Returns: // - grc721.TokenID: The minted token ID, equal to tid. func (n *gnftAccessor) Mint(_ int, rlm realm, to address, tid grc721.TokenID) grc721.TokenID { access.AssertIsRlmCurrent(0, rlm) return gnft.Mint(cross(rlm), to, tid) } // Burn destroys an NFT. // // Parameters: // - _: Internal call discriminator; callers pass 0. // - rlm: Propagated realm context; it must be current before crossing into the NFT realm. // - tid: NFT token ID to burn. func (n *gnftAccessor) Burn(_ int, rlm realm, tid grc721.TokenID) { access.AssertIsRlmCurrent(0, rlm) gnft.Burn(cross(rlm), tid) } // TransferFrom moves an NFT from its current owner to another address. // // Parameters: // - _: Internal call discriminator; callers pass 0. // - rlm: Propagated realm context; it must be current before crossing into the NFT realm. // - from: Current owner address of tid. // - to: Recipient address for tid. // - tid: NFT token ID to transfer. // // Returns: // - error: Non-nil when the NFT realm rejects the transfer or the realm context is spoofed; nil on success. func (n *gnftAccessor) TransferFrom(_ int, rlm realm, from, to address, tid grc721.TokenID) error { if !rlm.IsCurrent() { return errors.New(ErrSpoofedRealm) } return gnft.TransferFrom(cross(rlm), from, to, tid) } // TotalSupply returns the number of NFTs currently minted and not burned. // // Returns: // - int64: Current NFT collection supply. func (n *gnftAccessor) TotalSupply() int64 { return gnft.TotalSupply() } // Exists reports whether an NFT token ID is currently minted. // // Parameters: // - tid: NFT token ID to look up. // // Returns: // - bool: true when tid has an owner in the NFT ledger; false when it does not exist. func (n *gnftAccessor) Exists(tid grc721.TokenID) bool { return gnft.Exists(tid) } // MustOwnerOf returns the owner of an NFT and panics when tid is invalid. // // Parameters: // - tid: NFT token ID whose owner is required. // // Returns: // - address: Current owner address of tid; the accessor panics if tid does not exist. func (n *gnftAccessor) MustOwnerOf(tid grc721.TokenID) address { owner, err := gnft.OwnerOf(tid) if err != nil { panic(err.Error()) } return owner } // OwnerOf returns the owner of an NFT without panicking on lookup failure. // // Parameters: // - tid: NFT token ID whose owner is queried. // // Returns: // - address: Current owner address, or the zero address when lookup fails. // - error: Non-nil when tid does not exist or the NFT realm cannot resolve its owner. func (n *gnftAccessor) OwnerOf(tid grc721.TokenID) (address, error) { return gnft.OwnerOf(tid) } func newNFTAccessor() NFTAccessor { return &gnftAccessor{} }
  6. #6counter.gno
  7. #7package staker type Counter struct { id int64 } // NewCounter creates a counter initialized at zero. // // Returns: // - counter: Counter whose next generated identifier is 1. func NewCounter() *Counter { return &Counter{ id: 0, } } // Next increments the counter and returns the new identifier. // // Returns: // - id: Counter value after incrementing by one. func (c *Counter) Next() int64 { c.id++ return c.id } // Get returns the counter's current identifier without incrementing it. // // Returns: // - id: Current counter value. func (c *Counter) Get() int64 { return c.id }
  8. #8deposit.gno
  9. #9package staker import ( "math" u256 "gno.land/p/gnoswap/uint256/v1" ) type Deposit struct { warmups []Warmup // warmup information liquidity *u256.Uint // liquidity targetPoolPath string // staked position's pool path owner address // owner address stakeTime int64 // staked time internalRewardLastCollectTime int64 // last collect time for internal reward collectedInternalReward int64 // collected internal reward collectedExternalRewards map[string]int64 // collected external reward by incentive id (incentiveID -> int64) externalRewardLastCollectTimes map[string]int64 // last collect time for external rewards by incentive id (incentiveID -> int64) externalIncentiveIds map[string]bool // external incentive ids for this deposit (incentiveID -> bool) lastExternalIncentiveUpdatedAt int64 // last time when external incentive ids were synced tickLower int32 // tick lower tickUpper int32 // tick upper } // Owner returns the address that owns the staked position. // // Returns: // - owner: Address recorded as the deposit owner. func (d *Deposit) Owner() address { return d.owner } // SetOwner updates the address recorded as the deposit owner. // // Parameters: // - owner: Address that should own the deposit. func (d *Deposit) SetOwner(owner address) { d.owner = owner } // TargetPoolPath returns the pool path associated with the staked position. // // Returns: // - targetPoolPath: Pool identifier used to resolve the position's pool. func (d *Deposit) TargetPoolPath() string { return d.targetPoolPath } // SetTargetPoolPath updates the pool path associated with the staked position. // // Parameters: // - targetPoolPath: Pool identifier to associate with the deposit. func (d *Deposit) SetTargetPoolPath(targetPoolPath string) { d.targetPoolPath = targetPoolPath } // Liquidity returns the LP liquidity recorded for the deposit. // // Returns: // - liquidity: Liquidity amount represented by the staked position. func (d *Deposit) Liquidity() *u256.Uint { return d.liquidity } // SetLiquidity replaces the LP liquidity recorded for the deposit. // // Parameters: // - liquidity: New liquidity amount; the setter copies this value into the deposit. func (d *Deposit) SetLiquidity(liquidity *u256.Uint) { d.liquidity = u256.Zero().Set(liquidity) } // StakeTime returns the Unix timestamp at which the position was staked. // // Returns: // - stakeTime: Stake start time in Unix seconds. func (d *Deposit) StakeTime() int64 { return d.stakeTime } // SetStakeTime updates the Unix timestamp at which the position was staked. // // Parameters: // - stakeTime: Stake start time in Unix seconds. func (d *Deposit) SetStakeTime(stakeTime int64) { d.stakeTime = stakeTime } // InternalRewardLastCollectTime returns the internal-reward collection cursor. // // Returns: // - internalRewardLastCollectTime: Last internal reward collection time in Unix seconds. func (d *Deposit) InternalRewardLastCollectTime() int64 { return d.internalRewardLastCollectTime } // SetInternalRewardLastCollectTime updates the internal-reward collection cursor. // // Parameters: // - internalRewardLastCollectTime: New last internal reward collection time in Unix seconds. func (d *Deposit) SetInternalRewardLastCollectTime(internalRewardLastCollectTime int64) { d.internalRewardLastCollectTime = internalRewardLastCollectTime } // CollectedInternalReward returns the cumulative internal reward recorded for the deposit. // // Returns: // - collectedInternalReward: Accumulated internal reward amount in the reward token's smallest units. func (d *Deposit) CollectedInternalReward() int64 { return d.collectedInternalReward } // SetCollectedInternalReward replaces the cumulative internal reward recorded for the deposit. // // Parameters: // - collectedInternalReward: Cumulative internal reward amount in the reward token's smallest units. func (d *Deposit) SetCollectedInternalReward(collectedInternalReward int64) { d.collectedInternalReward = collectedInternalReward } // CollectedExternalRewards returns cumulative external rewards keyed by incentive ID. // // Returns: // - collectedExternalRewards: Map from incentive ID to the amount collected for that incentive. func (d *Deposit) CollectedExternalRewards() map[string]int64 { return d.collectedExternalRewards } // SetCollectedExternalRewards replaces the cumulative external-reward map. // // Parameters: // - collectedExternalRewards: Map from incentive ID to its collected reward amount. func (d *Deposit) SetCollectedExternalRewards(collectedExternalRewards map[string]int64) { d.collectedExternalRewards = collectedExternalRewards } // GetCollectedExternalReward returns the collected external reward for the given incentive ID. // Returns 0 if the incentive ID does not exist. // // Parameters: // - incentiveID: External incentive ID whose collected amount should be looked up. // // Returns: // - reward: Collected amount for the incentive, or 0 when the ID is absent. // - exists: True when the map contains incentiveID; false when it is absent. func (d *Deposit) GetCollectedExternalReward(incentiveID string) (int64, bool) { reward, exists := d.collectedExternalRewards[incentiveID] if !exists { return 0, false } return reward, true } // SetCollectedExternalReward records the cumulative amount collected for one incentive. // // Parameters: // - incentiveID: External incentive ID whose collected amount should be set. // - reward: Cumulative collected amount for incentiveID. func (d *Deposit) SetCollectedExternalReward(incentiveID string, reward int64) { if d.collectedExternalRewards == nil { d.collectedExternalRewards = make(map[string]int64) } d.collectedExternalRewards[incentiveID] = reward } // ExternalRewardLastCollectTimes returns per-incentive external collection cursors. // // Returns: // - externalRewardLastCollectTimes: Map from incentive ID to its last collection time in Unix seconds. func (d *Deposit) ExternalRewardLastCollectTimes() map[string]int64 { return d.externalRewardLastCollectTimes } // SetExternalRewardLastCollectTimes replaces the per-incentive external collection cursors. // // Parameters: // - externalRewardLastCollectTimes: Map from incentive ID to its last collection time in Unix seconds. func (d *Deposit) SetExternalRewardLastCollectTimes(externalRewardLastCollectTimes map[string]int64) { d.externalRewardLastCollectTimes = externalRewardLastCollectTimes } // GetExternalRewardLastCollectTime returns the last collect time for the given incentive ID. // Returns 0 if the incentive ID does not exist. // // Parameters: // - incentiveID: External incentive ID whose collection cursor should be looked up. // // Returns: // - time: Last collection time for the incentive in Unix seconds, or 0 when the ID is absent. // - exists: True when the map contains incentiveID; false when it is absent. func (d *Deposit) GetExternalRewardLastCollectTime(incentiveID string) (int64, bool) { time, exists := d.externalRewardLastCollectTimes[incentiveID] if !exists { return 0, false } return time, true } // SetExternalRewardLastCollectTime records the collection cursor for one incentive. // // Parameters: // - incentiveID: External incentive ID whose cursor should be set. // - currentTime: New collection time for incentiveID in Unix seconds. func (d *Deposit) SetExternalRewardLastCollectTime(incentiveID string, currentTime int64) { if d.externalRewardLastCollectTimes == nil { d.externalRewardLastCollectTimes = make(map[string]int64) } d.externalRewardLastCollectTimes[incentiveID] = currentTime } // TickLower returns the lower signed tick boundary of the staked position. // // Returns: // - tickLower: Lower tick boundary used by the position's price range. func (d *Deposit) TickLower() int32 { return d.tickLower } // SetTickLower updates the lower signed tick boundary of the staked position. // // Parameters: // - tickLower: Lower tick boundary to store for the position's price range. func (d *Deposit) SetTickLower(tickLower int32) { d.tickLower = tickLower } // TickUpper returns the upper signed tick boundary of the staked position. // // Returns: // - tickUpper: Upper tick boundary used by the position's price range. func (d *Deposit) TickUpper() int32 { return d.tickUpper } // SetTickUpper updates the upper signed tick boundary of the staked position. // // Parameters: // - tickUpper: Upper tick boundary to store for the position's price range. func (d *Deposit) SetTickUpper(tickUpper int32) { d.tickUpper = tickUpper } // ExternalIncentiveIds returns the deposit's indexed external incentive IDs. // // Returns: // - externalIncentiveIds: Map from each indexed incentive ID to its membership flag. func (d *Deposit) ExternalIncentiveIds() map[string]bool { return d.externalIncentiveIds } // SetExternalIncentiveIds replaces the deposit's indexed external incentive IDs. // // Parameters: // - externalIncentiveIds: Map of incentive IDs to their membership flags. func (d *Deposit) SetExternalIncentiveIds(externalIncentiveIds map[string]bool) { d.externalIncentiveIds = externalIncentiveIds } // AddExternalIncentiveId adds an external incentive id to the deposit. // // Parameters: // - incentiveId: External incentive ID to add to the deposit's index. func (d *Deposit) AddExternalIncentiveId(incentiveId string) { if d.externalIncentiveIds == nil { d.externalIncentiveIds = make(map[string]bool) } d.externalIncentiveIds[incentiveId] = true } // HasExternalIncentiveId checks if the deposit has the given external incentive id. // // Parameters: // - incentiveId: External incentive ID whose membership should be checked. // // Returns: // - hasIncentive: True when incentiveId is indexed on the deposit; false otherwise. func (d *Deposit) HasExternalIncentiveId(incentiveId string) bool { if d.externalIncentiveIds == nil { return false } return d.externalIncentiveIds[incentiveId] } // RemoveExternalIncentiveId removes an external incentive id from the deposit. // // Parameters: // - incentiveId: External incentive ID to remove from the deposit's index. func (d *Deposit) RemoveExternalIncentiveId(incentiveId string) { if d.externalIncentiveIds == nil { return } delete(d.externalIncentiveIds, incentiveId) } // GetExternalIncentiveIdList returns a list of external incentive ids for the deposit. // // Returns: // - incentiveIds: Slice containing the incentive IDs currently indexed on the deposit; order follows map iteration and is not guaranteed. func (d *Deposit) GetExternalIncentiveIdList() []string { if d.externalIncentiveIds == nil { return []string{} } ids := make([]string, 0, len(d.externalIncentiveIds)) for incentiveId := range d.externalIncentiveIds { ids = append(ids, incentiveId) } return ids } // IterateExternalIncentiveIds iterates over external incentive IDs without allocating a slice. // The callback function receives each incentive ID and should return false to continue iteration, // or true to stop early. This method is more memory-efficient than GetExternalIncentiveIdList // for cases where you only need to process IDs sequentially. // // Parameters: // - fn: Callback invoked with each indexed incentive ID; return true to stop iteration early or false to continue. func (d *Deposit) IterateExternalIncentiveIds(fn func(incentiveId string) bool) { if d.externalIncentiveIds == nil { return } for incentiveId := range d.externalIncentiveIds { if fn(incentiveId) { return } } } // Warmups returns a copy of the deposit's warmup schedule. // // Returns: // - warmups: Warmup tiers applied to rewards for this deposit, or nil when no schedule is stored. func (d *Deposit) Warmups() []Warmup { return cloneWarmups(d.warmups) } // SetWarmups replaces the deposit's warmup schedule with a copied slice. // // Parameters: // - warmups: Warmup tiers to use for subsequent reward calculations. func (d *Deposit) SetWarmups(warmups []Warmup) { d.warmups = cloneWarmups(warmups) } // LastExternalIncentiveUpdatedAt returns the timestamp of the last external-incentive index refresh. // // Returns: // - timestamp: Last refresh time in Unix seconds. func (d *Deposit) LastExternalIncentiveUpdatedAt() int64 { return d.lastExternalIncentiveUpdatedAt } // SetLastExternalIncentiveUpdatedAt updates the external-incentive index refresh timestamp. // // Parameters: // - timestamp: Refresh time to record in Unix seconds. func (d *Deposit) SetLastExternalIncentiveUpdatedAt(timestamp int64) { d.lastExternalIncentiveUpdatedAt = timestamp } // Clone returns a deep copy of the deposit. // // Returns: // - deposit: Deep copy of the deposit, or nil when the receiver is nil. func (d *Deposit) Clone() *Deposit { if d == nil { return nil } return &Deposit{ warmups: cloneWarmups(d.warmups), liquidity: d.liquidity.Clone(), targetPoolPath: d.targetPoolPath, owner: d.owner, stakeTime: d.stakeTime, internalRewardLastCollectTime: d.internalRewardLastCollectTime, collectedInternalReward: d.collectedInternalReward, collectedExternalRewards: cloneStringInt64Map(d.collectedExternalRewards), externalRewardLastCollectTimes: cloneStringInt64Map(d.externalRewardLastCollectTimes), externalIncentiveIds: cloneStringBoolMap(d.externalIncentiveIds), lastExternalIncentiveUpdatedAt: d.lastExternalIncentiveUpdatedAt, tickLower: d.tickLower, tickUpper: d.tickUpper, } } // NewDeposit creates a deposit for a staked LP position and initializes its reward cursors and maps. // // Parameters: // - owner: Address that owns the staked position. // - targetPoolPath: Pool identifier associated with the position. // - liquidity: LP liquidity amount represented by the position. // - currentTime: Staking and initial reward-cursor time in Unix seconds. // - tickLower: Lower signed tick boundary of the position's range. // - tickUpper: Upper signed tick boundary of the position's range. // - warmups: Warmup schedule to apply to this position's rewards. // // Returns: // - deposit: Newly initialized deposit containing the supplied position and warmup state. func NewDeposit( owner address, targetPoolPath string, liquidity *u256.Uint, currentTime int64, tickLower, tickUpper int32, warmups []Warmup, ) *Deposit { return &Deposit{ owner: owner, targetPoolPath: targetPoolPath, liquidity: liquidity, warmups: warmups, stakeTime: currentTime, tickLower: tickLower, tickUpper: tickUpper, internalRewardLastCollectTime: currentTime, externalRewardLastCollectTimes: make(map[string]int64), collectedInternalReward: 0, collectedExternalRewards: make(map[string]int64), externalIncentiveIds: make(map[string]bool), lastExternalIncentiveUpdatedAt: 0, } } type Warmup struct { TimeDuration int64 NextWarmupTime int64 // time when this warmup period ends WarmupRatio uint64 } // NewWarmup creates one warmup tier. // // Parameters: // - timeDuration: Duration of this tier in seconds. // - nextWarmupTime: Unix timestamp at which this tier ends. // - warmupRatio: Percentage of the calculated reward credited to the position, from 0 to 100. // // Returns: // - warmup: Warmup tier initialized with the supplied duration, end time, and ratio. func NewWarmup(timeDuration, nextWarmupTime int64, warmupRatio uint64) Warmup { return Warmup{ TimeDuration: timeDuration, NextWarmupTime: nextWarmupTime, WarmupRatio: warmupRatio, } } // SetNextWarmupTime updates the Unix timestamp at which this warmup tier ends. // // Parameters: // - nextWarmupTime: Tier end time in Unix seconds. func (w *Warmup) SetNextWarmupTime(nextWarmupTime int64) { w.NextWarmupTime = nextWarmupTime } // SetWarmupRatio updates the percentage of calculated reward credited to the position. // // Parameters: // - warmupRatio: Reward percentage for this tier, expressed from 0 to 100. func (w *Warmup) SetWarmupRatio(warmupRatio uint64) { w.WarmupRatio = warmupRatio } // SetTimeDuration updates the duration of this warmup tier. // // Parameters: // - timeDuration: Tier duration in seconds. func (w *Warmup) SetTimeDuration(timeDuration int64) { w.TimeDuration = timeDuration } // DefaultWarmupTemplate returns the built-in four-tier warmup schedule. // // Returns: // - warmups: Template with 5-day, 10-day, 30-day, and final-unbounded tiers using 30%, 50%, 70%, and 100% ratios; NextWarmupTime values are zero until instantiated. func DefaultWarmupTemplate() []Warmup { secondsInDay := int64(86400) secondsIn5Days := int64(5 * secondsInDay) secondsIn10Days := int64(10 * secondsInDay) secondsIn30Days := int64(30 * secondsInDay) // NextWarmupTime is set to 0 for template. // They will be set by InstantiateWarmup() return []Warmup{ { TimeDuration: secondsIn5Days, // NextWarmupTime will be set based on currentTime // NextWarmupTime: currentTime + secondsIn5Days, WarmupRatio: 30, }, { TimeDuration: secondsIn10Days, // NextWarmupTime will be set based on currentTime // NextWarmupTime: currentTime + secondsIn10Days, WarmupRatio: 50, }, { TimeDuration: secondsIn30Days, // NextWarmupTime will be set based on currentTime // NextWarmupTime: currentTime + secondsIn30Days, WarmupRatio: 70, }, { TimeDuration: math.MaxInt64, // NextWarmupTime will be set to math.MaxInt64 // NextWarmupTime: math.MaxInt64, WarmupRatio: 100, }, } } const ( GNS_PATH string = "gno.land/r/gnoswap/gns.GNS" WUGNOT_PATH string = "gno.land/r/gnoland/wugnot.wugnot" ) // DefaultAllowedTokens returns the token paths accepted by the staker's default configuration. // // Returns: // - tokenPaths: Slice containing the GNS and wrapped-GNOT token paths. func DefaultAllowedTokens() []string { return []string{GNS_PATH, WUGNOT_PATH} }
  10. #10doc.gno
  11. #11// Package staker manages liquidity mining rewards for GnoSwap positions. // // The staker distributes GNS emissions and external incentives to liquidity // providers based on their position size, price range, and staking duration. // It supports both internal GNS rewards and external token incentives. // // Reward calculations combine elapsed-time rates with tick/range accumulation, and // collection flows are integrated into the staking lifecycle. package staker
  12. #12getter.gno
  13. #13package staker import ( u256 "gno.land/p/gnoswap/uint256/v1" rotree "gno.land/p/nt/bptree/rotree/v0" ) // IStakerGetter functions // GetPool returns a copy of the staking state for a pool. // // Parameters: // - poolPath: pool realm path // // Returns: // - pool: independent pool copy, or nil when an implementation has no pool value // - err: implementation resolution error; the current v1 implementation returns not-found for a missing pool func GetPool(poolPath string) (*Pool, error) { pool, err := getImplementation().GetPool(poolPath) if err != nil { return nil, err } if pool == nil { return nil, nil } return pool.Clone(), nil } // GetDeposit returns a copy of a staked position's deposit. // // Parameters: // - lpTokenId: staked position NFT token ID // // Returns: // - deposit: independent deposit copy, or nil when an implementation has no deposit value // - err: implementation resolution error; the current v1 implementation returns not-found for a missing deposit func GetDeposit(lpTokenId uint64) (*Deposit, error) { deposit, err := getImplementation().GetDeposit(lpTokenId) if err != nil { return nil, err } if deposit == nil { return nil, nil } return deposit.Clone(), nil } // CollectableEmissionReward returns the claimable internal GNS reward for a live staked deposit or // an exit checkpoint left by UnStakeToken. // // Parameters: // - positionId: staked position NFT token ID or position with an exit checkpoint // // Returns: // - amount: claimable internal reward amount // - err: non-nil when positionId cannot be resolved func CollectableEmissionReward(positionId uint64) (int64, error) { return getImplementation().CollectableEmissionReward(positionId) } // CollectableExternalIncentiveReward returns a position's claimable external reward for a live // staked deposit or an exit checkpoint left by UnStakeToken. // // Parameters: // - positionId: staked position NFT token ID or position with an exit checkpoint // - incentiveId: external incentive identifier // // Returns: // - amount: claimable external reward amount // - err: non-nil when the position or incentive cannot be resolved func CollectableExternalIncentiveReward(positionId uint64, incentiveId string) (int64, error) { return getImplementation().CollectableExternalIncentiveReward(positionId, incentiveId) } // GetCreatedHeightOfIncentive returns an incentive's creation block height. // // Parameters: // - poolPath: pool realm path // - incentiveId: external incentive identifier // // Returns: // - height: creation block height // - err: non-nil when the incentive cannot be resolved func GetCreatedHeightOfIncentive(poolPath string, incentiveId string) (int64, error) { return getImplementation().GetCreatedHeightOfIncentive(poolPath, incentiveId) } // GetIncentiveCreatedTimestamp returns an incentive's creation timestamp. // // Parameters: // - poolPath: pool realm path // - incentiveId: external incentive identifier // // Returns: // - timestamp: creation Unix timestamp // - err: non-nil when the incentive cannot be resolved func GetIncentiveCreatedTimestamp(poolPath string, incentiveId string) (int64, error) { return getImplementation().GetIncentiveCreatedTimestamp(poolPath, incentiveId) } // GetIncentiveTotalRewardAmount returns the total reward amount of an incentive. // // Parameters: // - poolPath: Pool path containing the incentive record. // - incentiveId: External incentive identifier to resolve. // // Returns: // - amount: Total reward amount configured when the incentive was created, in token units. // - err: Non-nil when poolPath or incentiveId cannot be resolved. func GetIncentiveTotalRewardAmount(poolPath string, incentiveId string) (int64, error) { return getImplementation().GetIncentiveTotalRewardAmount(poolPath, incentiveId) } // GetIncentiveDistributedRewardAmount returns the distributed reward amount of an incentive. // // Parameters: // - poolPath: Pool path containing the incentive record. // - incentiveId: External incentive identifier to resolve. // // Returns: // - amount: Reward amount already delivered to positions or refunded at incentive end, in token units. // - err: Non-nil when poolPath or incentiveId cannot be resolved. func GetIncentiveDistributedRewardAmount(poolPath string, incentiveId string) (int64, error) { return getImplementation().GetIncentiveDistributedRewardAmount(poolPath, incentiveId) } // GetIncentiveRemainingRewardAmount returns the remaining reward amount of an incentive. // // Parameters: // - poolPath: Pool path containing the incentive record. // - incentiveId: External incentive identifier to resolve. // // Returns: // - amount: Mutable reward balance remaining after distributions and refunds, in token units. // - err: Non-nil when poolPath or incentiveId cannot be resolved. func GetIncentiveRemainingRewardAmount(poolPath string, incentiveId string) (int64, error) { return getImplementation().GetIncentiveRemainingRewardAmount(poolPath, incentiveId) } // GetIncentiveAccumulatedPenaltyAmount returns the accumulated warmup penalty amount of an incentive. // // Parameters: // - poolPath: Pool path containing the incentive record. // - incentiveId: External incentive identifier to resolve. // // Returns: // - amount: Warmup penalty accumulated from collections for the incentive, in reward-token units. // - err: Non-nil when poolPath or incentiveId cannot be resolved. func GetIncentiveAccumulatedPenaltyAmount(poolPath string, incentiveId string) (int64, error) { return getImplementation().GetIncentiveAccumulatedPenaltyAmount(poolPath, incentiveId) } // GetIncentiveDepositGnsAmount returns the deposited GNS amount of an incentive. // // Parameters: // - poolPath: Pool path containing the incentive record. // - incentiveId: External incentive identifier to resolve. // // Returns: // - amount: GNS deposit locked by the incentive, in token units. // - err: Non-nil when poolPath or incentiveId cannot be resolved. func GetIncentiveDepositGnsAmount(poolPath string, incentiveId string) (int64, error) { return getImplementation().GetIncentiveDepositGnsAmount(poolPath, incentiveId) } // GetIncentiveRefunded returns whether an incentive has been refunded. // // Parameters: // - poolPath: Pool path containing the incentive record. // - incentiveId: External incentive identifier to resolve. // // Returns: // - refunded: True when the incentive has been finalized as refunded; false while it remains open. // - err: Non-nil when poolPath or incentiveId cannot be resolved. func GetIncentiveRefunded(poolPath string, incentiveId string) (bool, error) { return getImplementation().GetIncentiveRefunded(poolPath, incentiveId) } // IsIncentiveActive reports whether an unrefunded incentive is active, including both start and end timestamps. // // Parameters: // - poolPath: Pool path containing the incentive record. // - incentiveId: External incentive identifier to resolve. // // Returns: // - active: True when the current Unix time is within the incentive window and it has not been refunded. // - err: Non-nil when poolPath or incentiveId cannot be resolved. func IsIncentiveActive(poolPath string, incentiveId string) (bool, error) { return getImplementation().IsIncentiveActive(poolPath, incentiveId) } // GetDepositExternalRewardLastCollectTimestamp returns the last external reward collection time for // a position and incentive. For a newly tracked incentive, the value is based on the stake timestamp. // // Parameters: // - lpTokenId: Position NFT token ID whose external reward cursor should be read. // - incentiveId: External incentive identifier whose collection cursor should be read. // // Returns: // - timestamp: Unix timestamp of the last collection cursor; newly tracked incentives use the deposit's stake time. // - err: Non-nil when lpTokenId does not resolve to a stored deposit. func GetDepositExternalRewardLastCollectTimestamp(lpTokenId uint64, incentiveId string) (int64, error) { return getImplementation().GetDepositExternalRewardLastCollectTimestamp(lpTokenId, incentiveId) } // GetDepositGnsAmount returns the GNS deposit required for each external incentive. // // Returns: // - amount: Configured GNS deposit required per external incentive, in token units. func GetDepositGnsAmount() int64 { return getImplementation().GetDepositGnsAmount() } // GetDepositInternalRewardLastCollectTimestamp returns the last internal reward collection time for a position. // // Parameters: // - lpTokenId: Position NFT token ID whose internal reward cursor should be read. // // Returns: // - timestamp: Unix timestamp of the deposit's last internal reward collection. // - err: Non-nil when lpTokenId does not resolve to a stored deposit. func GetDepositInternalRewardLastCollectTimestamp(lpTokenId uint64) (int64, error) { return getImplementation().GetDepositInternalRewardLastCollectTimestamp(lpTokenId) } // GetDepositCollectedInternalReward returns the collected internal reward amount of a position. // // Parameters: // - lpTokenId: Position NFT token ID whose collected internal reward should be read. // // Returns: // - amount: Internal GNS reward amount already recorded as collected, in token units. // - err: Non-nil when lpTokenId does not resolve to a stored deposit. func GetDepositCollectedInternalReward(lpTokenId uint64) (int64, error) { return getImplementation().GetDepositCollectedInternalReward(lpTokenId) } // GetDepositCollectedExternalReward returns the collected external reward amount of a position. // // Parameters: // - lpTokenId: Position NFT token ID whose collected reward should be read. // - incentiveId: External incentive identifier whose collected amount should be read. // // Returns: // - amount: External reward amount already recorded as collected for the incentive, in token units. // - err: Non-nil when lpTokenId does not resolve to a stored deposit. func GetDepositCollectedExternalReward(lpTokenId uint64, incentiveId string) (int64, error) { return getImplementation().GetDepositCollectedExternalReward(lpTokenId, incentiveId) } // GetDepositLiquidity returns the liquidity amount of a staked position. // // Parameters: // - lpTokenId: Position NFT token ID whose liquidity should be read. // // Returns: // - liquidity: Independent uint256 copy of the deposit's liquidity amount. // - err: Non-nil when lpTokenId does not resolve to a stored deposit. func GetDepositLiquidity(lpTokenId uint64) (*u256.Uint, error) { liquidity, err := getImplementation().GetDepositLiquidity(lpTokenId) if err != nil { return nil, err } return liquidity.Clone(), nil } // GetDepositLiquidityAsString returns the liquidity amount of a staked position as a decimal string. // // Parameters: // - lpTokenId: Position NFT token ID whose liquidity should be formatted. // // Returns: // - liquidity: Decimal representation of the deposit's uint256 liquidity amount. // - err: Non-nil when lpTokenId does not resolve to a stored deposit. func GetDepositLiquidityAsString(lpTokenId uint64) (string, error) { return getImplementation().GetDepositLiquidityAsString(lpTokenId) } // GetDepositOwner returns the owner of a staked position. // // Parameters: // - lpTokenId: Position NFT token ID whose owner should be read. // // Returns: // - owner: Address recorded as the deposit owner. // - err: Non-nil when lpTokenId does not resolve to a stored deposit. func GetDepositOwner(lpTokenId uint64) (address, error) { return getImplementation().GetDepositOwner(lpTokenId) } // GetDepositStakeTime returns the Unix timestamp at which a position was staked. // // Parameters: // - lpTokenId: Position NFT token ID whose stake time should be read. // // Returns: // - stakeTime: Unix timestamp recorded when the deposit entered staking. // - err: Non-nil when lpTokenId does not resolve to a stored deposit. func GetDepositStakeTime(lpTokenId uint64) (int64, error) { return getImplementation().GetDepositStakeTime(lpTokenId) } // GetDepositTargetPoolPath returns the pool path of a staked position. // // Parameters: // - lpTokenId: Position NFT token ID whose target pool should be read. // // Returns: // - poolPath: Pool path stored on the deposit. // - err: Non-nil when lpTokenId does not resolve to a stored deposit. func GetDepositTargetPoolPath(lpTokenId uint64) (string, error) { return getImplementation().GetDepositTargetPoolPath(lpTokenId) } // GetDepositTickLower returns the lower tick of a staked position. // // Parameters: // - lpTokenId: Position NFT token ID whose lower boundary should be read. // // Returns: // - tickLower: Lower price-range tick stored on the deposit. // - err: Non-nil when lpTokenId does not resolve to a stored deposit. func GetDepositTickLower(lpTokenId uint64) (int32, error) { return getImplementation().GetDepositTickLower(lpTokenId) } // GetDepositTickUpper returns the upper tick of a staked position. // // Parameters: // - lpTokenId: Position NFT token ID whose upper boundary should be read. // // Returns: // - tickUpper: Upper price-range tick stored on the deposit. // - err: Non-nil when lpTokenId does not resolve to a stored deposit. func GetDepositTickUpper(lpTokenId uint64) (int32, error) { return getImplementation().GetDepositTickUpper(lpTokenId) } // GetDepositWarmUp returns the warmup records of a staked position. // // Parameters: // - lpTokenId: Position NFT token ID whose warmup schedule should be inspected. // // Returns: // - warmups: Independent copy of the deposit's warmup records. // - err: Non-nil when lpTokenId does not resolve to a stored deposit. func GetDepositWarmUp(lpTokenId uint64) ([]Warmup, error) { warmups, err := getImplementation().GetDepositWarmUp(lpTokenId) if err != nil { return nil, err } return cloneWarmups(warmups), nil } // GetDepositExternalIncentiveIdList returns external incentive IDs tracked by a deposit. // // Parameters: // - lpTokenId: Position NFT token ID whose deposit should be inspected. // // Returns: // - incentiveIds: Independent copy of external incentive IDs associated with the deposit. // - err: Non-nil when lpTokenId does not resolve to a stored deposit. func GetDepositExternalIncentiveIdList(lpTokenId uint64) ([]string, error) { ids, err := getImplementation().GetDepositExternalIncentiveIdList(lpTokenId) if err != nil { return nil, err } return cloneStringSlice(ids), nil } // GetExternalIncentiveByPoolPath returns all external incentives for a pool. // // Parameters: // - poolPath: Pool path whose external incentives should be listed. // // Returns: // - incentives: Independent copies of incentives targeting poolPath. // - err: Non-nil when stored incentive data cannot be read or cast. func GetExternalIncentiveByPoolPath(poolPath string) ([]ExternalIncentive, error) { incentives, err := getImplementation().GetExternalIncentiveByPoolPath(poolPath) if err != nil { return nil, err } return cloneExternalIncentives(incentives), nil } // GetIncentiveEndTimestamp returns the end timestamp of an incentive. // // Parameters: // - poolPath: Pool path containing the incentive record. // - incentiveId: External incentive identifier to resolve. // // Returns: // - endTimestamp: Incentive end time as a Unix timestamp. // - err: Non-nil when poolPath or incentiveId cannot be resolved. func GetIncentiveEndTimestamp(poolPath string, incentiveId string) (int64, error) { return getImplementation().GetIncentiveEndTimestamp(poolPath, incentiveId) } // GetIncentiveCreator returns the creator address of an incentive. // // Parameters: // - poolPath: Pool path containing the incentive record. // - incentiveId: External incentive identifier to resolve. // // Returns: // - creator: Address that created and funded the incentive. // - err: Non-nil when poolPath or incentiveId cannot be resolved. func GetIncentiveCreator(poolPath string, incentiveId string) (address, error) { return getImplementation().GetIncentiveCreator(poolPath, incentiveId) } // GetIncentiveRewardAmount returns the remaining reward amount of an incentive, after deliveries // and refunds represented by the current incentive state. // // Parameters: // - poolPath: Pool path containing the incentive record. // - incentiveId: External incentive identifier to resolve. // // Returns: // - amount: Independent uint256 copy of the incentive's mutable remaining reward amount. // - err: Non-nil when poolPath or incentiveId cannot be resolved. func GetIncentiveRewardAmount(poolPath string, incentiveId string) (*u256.Uint, error) { amount, err := getImplementation().GetIncentiveRewardAmount(poolPath, incentiveId) if err != nil { return nil, err } return amount.Clone(), nil } // GetIncentiveRewardAmountAsString returns the remaining reward amount of an incentive as string. // // Parameters: // - poolPath: Pool path containing the incentive record. // - incentiveId: External incentive identifier to resolve. // // Returns: // - amount: Decimal string for the incentive's remaining reward amount after deliveries and refunds. // - err: Non-nil when poolPath or incentiveId cannot be resolved. func GetIncentiveRewardAmountAsString(poolPath string, incentiveId string) (string, error) { return getImplementation().GetIncentiveRewardAmountAsString(poolPath, incentiveId) } // GetIncentiveRewardPerSecondX128 returns the reward rate per second of an // incentive, expressed as a Q128 fixed-point number (i.e. actual rate = // value / 2^128). Callers needing an integer rate can right-shift the result // by 128. // // Parameters: // - poolPath: Pool path containing the incentive record. // - incentiveId: External incentive identifier to resolve. // // Returns: // - rateX128: Clone of the Q128-scaled reward rate; divide by 2^128 to recover the actual token units per second. // - err: Non-nil when poolPath or incentiveId cannot be resolved. func GetIncentiveRewardPerSecondX128(poolPath string, incentiveId string) (*u256.Uint, error) { amount, err := getImplementation().GetIncentiveRewardPerSecondX128(poolPath, incentiveId) if err != nil { return nil, err } return amount.Clone(), nil } // GetIncentiveRewardToken returns the reward token of an incentive. // // Parameters: // - poolPath: Pool path containing the incentive record. // - incentiveId: External incentive identifier to resolve. // // Returns: // - tokenPath: Reward-token path configured for the incentive. // - err: Non-nil when poolPath or incentiveId cannot be resolved. func GetIncentiveRewardToken(poolPath string, incentiveId string) (string, error) { return getImplementation().GetIncentiveRewardToken(poolPath, incentiveId) } // GetIncentiveStartTimestamp returns the start timestamp of an incentive. // // Parameters: // - poolPath: Pool path containing the incentive record. // - incentiveId: External incentive identifier to resolve. // // Returns: // - startTimestamp: Incentive start time as a Unix timestamp. // - err: Non-nil when poolPath or incentiveId cannot be resolved. func GetIncentiveStartTimestamp(poolPath string, incentiveId string) (int64, error) { return getImplementation().GetIncentiveStartTimestamp(poolPath, incentiveId) } // GetMinimumRewardAmount returns the default minimum reward amount required to create an external // incentive. A token-specific override may apply. // // Returns: // - amount: Default minimum external-incentive reward amount in token units. func GetMinimumRewardAmount() int64 { return getImplementation().GetMinimumRewardAmount() } // GetMinimumRewardAmountForToken returns the minimum reward amount for a specific token. // // Parameters: // - tokenPath: Token path whose configured minimum-reward override should be read. // // Returns: // - amount: Token-specific minimum reward amount when configured, otherwise the default minimum, in token units. func GetMinimumRewardAmountForToken(tokenPath string) int64 { return getImplementation().GetMinimumRewardAmountForToken(tokenPath) } // GetPoolStakedLiquidity returns the current total staked liquidity of a pool. // // Parameters: // - poolPath: Pool path whose current staked liquidity should be read. // // Returns: // - liquidity: Decimal string containing the pool's total staked liquidity at the current time. // - err: Non-nil when poolPath does not resolve to a pool. func GetPoolStakedLiquidity(poolPath string) (string, error) { return getImplementation().GetPoolStakedLiquidity(poolPath) } // GetPoolsByTier returns the pool list for a tier. // // Parameters: // - tier: Emission tier identifier whose current pool memberships should be listed. // // Returns: // - poolPaths: Copy of pool paths currently assigned to tier; tier zero yields an empty list. // - err: Non-nil when the stored tier membership contains an invalid value. func GetPoolsByTier(tier uint64) ([]string, error) { pools, err := getImplementation().GetPoolsByTier(tier) if err != nil { return nil, err } return cloneStringSlice(pools), nil } // GetPoolReward returns the reward amount for a tier. // // Parameters: // - tier: Emission tier identifier for which to retrieve the per-pool reward. // // Returns: // - reward: Current per-pool GNS reward rate for tier, in token units per second. // - err: Non-nil when tier is outside the valid range 1 through AllTierCount-1. func GetPoolReward(tier uint64) (int64, error) { return getImplementation().GetPoolReward(tier) } // GetPoolTier returns the tier of a pool. // // Parameters: // - poolPath: Pool path whose current emission tier should be read. // // Returns: // - tier: Current emission tier identifier; zero when the pool has no tier assignment. func GetPoolTier(poolPath string) uint64 { return getImplementation().GetPoolTier(poolPath) } // GetPoolTierCount returns the number of pools in a tier. // // Parameters: // - tier: Emission tier identifier to count; tier zero has no pools. // // Returns: // - count: Number of pools currently assigned to tier, or zero for tier zero. func GetPoolTierCount(tier uint64) uint64 { return getImplementation().GetPoolTierCount(tier) } // GetPoolTierRatio returns the reward ratio of a pool. // // Parameters: // - poolPath: Pool path whose current emission tier ratio should be read. // // Returns: // - ratio: Stored reward-share ratio for the pool's current tier. // - err: Non-nil when the pool's tier is invalid and has no configured ratio. func GetPoolTierRatio(poolPath string) (uint64, error) { return getImplementation().GetPoolTierRatio(poolPath) } // GetSpecificTokenMinimumRewardAmount returns the explicitly set minimum reward amount for a token. // // Parameters: // - tokenPath: Token path whose explicit minimum-reward override should be read. // // Returns: // - amount: Explicit minimum reward amount in token units, or 0 when no override is configured. // - found: True when tokenPath has an explicit override; false when the default would be used. func GetSpecificTokenMinimumRewardAmount(tokenPath string) (int64, bool) { return getImplementation().GetSpecificTokenMinimumRewardAmount(tokenPath) } // GetTargetPoolPathByIncentiveId returns the pool path for an incentive ID. // // Parameters: // - poolPath: Pool path containing the incentive record. // - incentiveId: External incentive identifier to resolve. // // Returns: // - targetPoolPath: Pool path stored on the resolved incentive. // - err: Non-nil when poolPath or incentiveId cannot be resolved. func GetTargetPoolPathByIncentiveId(poolPath string, incentiveId string) (string, error) { return getImplementation().GetTargetPoolPathByIncentiveId(poolPath, incentiveId) } // GetUnstakingFee returns the current unstaking fee rate in basis points (0-1,000; 100 = 1%). // // Returns: // - feeRate: Current staking-reward fee rate in basis points. func GetUnstakingFee() uint64 { return getImplementation().GetUnstakingFee() } // HasUnstakedPosition returns whether a position was unstaked with rewards left to collect. // // Parameters: // - positionId: Position NFT token ID to check in the unstaked-position tree. // // Returns: // - unstaked: True when positionId has an exit checkpoint awaiting collection; false otherwise. func HasUnstakedPosition(positionId uint64) bool { return getImplementation().HasUnstakedPosition(positionId) } // GetUnstakedPositionExitTime returns the timestamp at which an unstaked position stopped accruing rewards. // // Parameters: // - positionId: Position NFT token ID identifying the unstaked exit checkpoint. // // Returns: // - exitTime: Unix timestamp pinned as the end of the position's reward-accrual window. // - err: Non-nil when positionId has no unstaked checkpoint with uncollected rewards. func GetUnstakedPositionExitTime(positionId uint64) (int64, error) { return getImplementation().GetUnstakedPositionExitTime(positionId) } // GetUnstakedPositionPendingIncentives returns the incentives an unstaked position has yet to collect. // // Parameters: // - positionId: Position NFT token ID identifying the unstaked exit checkpoint. // // Returns: // - incentiveIds: Copy of external incentive IDs still pending for the exit checkpoint. // - err: Non-nil when positionId has no unstaked checkpoint with uncollected rewards. func GetUnstakedPositionPendingIncentives(positionId uint64) ([]string, error) { incentiveIds, err := getImplementation().GetUnstakedPositionPendingIncentives(positionId) if err != nil { return nil, err } return cloneStringSlice(incentiveIds), nil } // GetUncollectedIncentiveCount returns how many unstaked positions still owe a reward from the incentive. // // Parameters: // - incentiveId: External incentive identifier whose outstanding exit positions should be counted. // // Returns: // - count: Number of unstaked positions with an uncollected reward for incentiveId. func GetUncollectedIncentiveCount(incentiveId string) int64 { return getImplementation().GetUncollectedIncentiveCount(incentiveId) } // IsStaked returns whether a position is staked. // // Parameters: // - positionId: Position NFT token ID to check in the active deposit tree. // // Returns: // - staked: True when positionId has an active deposit; false for an unstaked or unknown position. func IsStaked(positionId uint64) bool { return getImplementation().IsStaked(positionId) } // GetTotalEmissionSent returns the total GNS emission sent. // // Returns: // - amount: Cumulative GNS emission amount sent by the staker, in token units. func GetTotalEmissionSent() int64 { return getImplementation().GetTotalEmissionSent() } // GetAllowedTokens returns the allowed external incentive tokens. // // Returns: // - tokenPaths: Copy of token paths permitted for external incentives. func GetAllowedTokens() []string { return cloneStringSlice(getImplementation().GetAllowedTokens()) } // GetDeniedRewardTokens returns the denied external incentive reward tokens. // // Returns: // - tokenPaths: Copy of token paths excluded from external incentive rewards. func GetDeniedRewardTokens() []string { return cloneStringSlice(getImplementation().GetDeniedRewardTokens()) } // GetWarmupTemplate returns the current warmup template. // // Returns: // - warmups: Copy of the configured warmup schedule used for newly staked positions. func GetWarmupTemplate() []Warmup { return cloneWarmups(getImplementation().GetWarmupTemplate()) } // GetPoolRewardCaches returns a read-only view of a pool's reward cache, keyed // by the encoded block timestamp. Callers paginate it themselves through // IterateByOffset and decode keys with DecodeInt64. // // Parameters: // - poolPath: Pool path whose reward-cache checkpoints should be read. // // Returns: // - caches: Read-only tree of timestamp keys to cached reward values, or nil when poolPath has no pool. func GetPoolRewardCaches(poolPath string) *rotree.ReadOnlyTree { return getImplementation().GetPoolRewardCaches(poolPath) } // GetPoolIncentives returns a read-only view of a pool's external incentives, // keyed by incentive ID. Reading an entry yields a clone, so the view cannot // mutate realm state. // // Parameters: // - poolPath: Pool path whose external-incentive records should be read. // // Returns: // - incentives: Read-only tree keyed by incentive ID with cloned entries, or nil when poolPath has no pool. func GetPoolIncentives(poolPath string) *rotree.ReadOnlyTree { return getImplementation().GetPoolIncentives(poolPath) } // GetPoolGlobalRewardRatioAccumulations returns a read-only view of a pool's // global reward ratio accumulation, keyed by the encoded block timestamp. // // Parameters: // - poolPath: Pool path whose global reward-ratio checkpoints should be read. // // Returns: // - accumulations: Read-only tree of timestamp keys to stored accumulation values, or nil when poolPath has no pool. func GetPoolGlobalRewardRatioAccumulations(poolPath string) *rotree.ReadOnlyTree { return getImplementation().GetPoolGlobalRewardRatioAccumulations(poolPath) } // GetPoolHistoricalTicks returns a read-only view of a pool's historical ticks, // keyed by the encoded block timestamp with the int32 tick as the value. // // Parameters: // - poolPath: Pool path whose historical tick checkpoints should be read. // // Returns: // - ticks: Read-only tree of timestamp keys to int32 ticks, or nil when poolPath has no pool. func GetPoolHistoricalTicks(poolPath string) *rotree.ReadOnlyTree { return getImplementation().GetPoolHistoricalTicks(poolPath) } // GetPendingProtocolFees returns the pending protocol fee amount per token path. // // Returns: // - fees: Copy of pending protocol-fee amounts keyed by token path, in the corresponding token units. func GetPendingProtocolFees() map[string]int64 { return cloneStringInt64Map(getImplementation().GetPendingProtocolFees()) }
  14. #14getter_utils.gno
  15. #15package staker func cloneStringSlice(src []string) []string { if src == nil { return nil } copied := make([]string, len(src)) copy(copied, src) return copied } func cloneStringInt64Map(src map[string]int64) map[string]int64 { if src == nil { return nil } copied := make(map[string]int64, len(src)) for key, value := range src { copied[key] = value } return copied } func cloneStringBoolMap(src map[string]bool) map[string]bool { if src == nil { return nil } copied := make(map[string]bool, len(src)) for key, value := range src { copied[key] = value } return copied } func cloneExternalIncentives(src []ExternalIncentive) []ExternalIncentive { if src == nil { return nil } copied := make([]ExternalIncentive, len(src)) for i := range src { copied[i] = *src[i].Clone() } return copied } func cloneWarmups(warmups []Warmup) []Warmup { if warmups == nil { return nil } copied := make([]Warmup, len(warmups)) copy(copied, warmups) return copied }
  16. #16gnomod.toml
  17. #17module = "gno.land/r/gnoswap/staker" gno = "0.9"
  18. #18pool.gno
  19. #19package staker import ( "errors" "time" "gno.land/p/gnoswap/consts/v1" i256 "gno.land/p/gnoswap/int256/v1" u256 "gno.land/p/gnoswap/uint256/v1" "gno.land/p/gnoswap/utils/v1" bptree "gno.land/p/nt/bptree/v0" ufmt "gno.land/p/nt/ufmt/v0" ) const AllTierCount = 4 // 0, 1, 2, 3 // Pool is a struct for storing an incentivized pool information // Each pool stores Incentives and Ticks associated with it. // // Fields: // - poolPath: The path of the pool. // // - stakedLiquidity: // The current total staked liquidity of the in-range positions for the pool. // Updated when tick cross happens or stake/unstake happens. // Used to calculate the global reward ratio accumulation or // decide whether to enter/exit unclaimable period. // // - lastUnclaimableTime: // The time at which the unclaimable period started. // Set to 0 when the pool is not in an unclaimable period. // // - unclaimableAcc: // The accumulated undistributed unclaimable reward. // Reset to 0 when processUnclaimableReward is called and sent to community pool. // // - rewardCache: // The cached per-second reward emitted for this pool. // Stores new entry only when the reward is changed. // PoolTier.cacheReward() updates this. // // - incentives: The external incentives associated with the pool. // // - ticks: The Ticks associated with the pool. // // - globalRewardRatioAccumulation: // Global ratio of Time / TotalStake accumulation(since the pool creation) // Stores new entry only when tick cross or stake/unstake happens. // It is used to calculate the reward for a staked position at certain time. // // - historicalTick: // The historical tick for the pool at a given time. // It does not reflect the exact tick at the timestamp, // but it provides correct ordering for the staked position's ticks. // Therefore, you should not compare it for equality, only for ordering. // Set when tick cross happens or a new position is created. type Pool struct { poolPath string stakedLiquidity *UintTree // uint64 timestamp -> *u256.Uint(Q128) lastUnclaimableTime int64 unclaimableAcc int64 rewardCache *UintTree // uint64 timestamp -> int64 gnsReward incentives *Incentives ticks Ticks // int32 tickId -> Tick tick globalRewardRatioAccumulation *UintTree // uint64 timestamp -> *u256.Uint(Q128) rewardRatioAccumulation historicalTick *UintTree // uint64 timestamp -> int32 tickId } // Pool Getter/Setter methods // PoolPath returns the pool path // // Returns: // - path: Pool identifier used to associate this state with a liquidity pool. func (p *Pool) PoolPath() string { return p.poolPath } // SetPoolPath sets the pool path // // Parameters: // - poolPath: Pool identifier to store. func (p *Pool) SetPoolPath(poolPath string) { p.poolPath = poolPath } // StakedLiquidity returns the staked liquidity tree // // Returns: // - tree: Historical staked-liquidity tree keyed by Unix timestamp, with Q128-scaled liquidity values. func (p *Pool) StakedLiquidity() *UintTree { return p.stakedLiquidity } // SetStakedLiquidity sets the staked liquidity tree // // Parameters: // - stakedLiquidity: Tree of historical total staked liquidity snapshots. func (p *Pool) SetStakedLiquidity(stakedLiquidity *UintTree) { p.stakedLiquidity = stakedLiquidity } // SetStakedLiquidityAt records the current total staked liquidity at a timestamp. // // Parameters: // - currentTime: Nonnegative Unix timestamp in seconds used as the snapshot key. // - delta: Total staked liquidity at currentTime, stored as a copied Q128-scaled uint value. func (p *Pool) SetStakedLiquidityAt(currentTime int64, delta *u256.Uint) { p.StakedLiquidity().Set(currentTime, u256.Zero().Set(delta)) } // LastUnclaimableTime returns the last unclaimable time // // Returns: // - timestamp: Unix timestamp in seconds at which the pool entered its current unclaimable period, or 0 when tracking has not started. func (p *Pool) LastUnclaimableTime() int64 { return p.lastUnclaimableTime } // SetLastUnclaimableTime sets the last unclaimable time // // Parameters: // - lastUnclaimableTime: Unix timestamp in seconds marking the start of the current unclaimable period; use 0 when no period is active. func (p *Pool) SetLastUnclaimableTime(lastUnclaimableTime int64) { p.lastUnclaimableTime = lastUnclaimableTime } // UnclaimableAcc returns the unclaimable accumulation // // Returns: // - amount: Accumulated undistributed unclaimable reward amount in the pool's int64 reward units. func (p *Pool) UnclaimableAcc() int64 { return p.unclaimableAcc } // SetUnclaimableAcc sets the unclaimable accumulation // // Parameters: // - unclaimableAcc: Accumulated undistributed unclaimable reward amount in the pool's int64 reward units. func (p *Pool) SetUnclaimableAcc(unclaimableAcc int64) { p.unclaimableAcc = unclaimableAcc } // RewardCache returns the reward cache tree // // Returns: // - tree: Historical per-second GNS reward cache keyed by Unix timestamp. func (p *Pool) RewardCache() *UintTree { return p.rewardCache } // SetRewardCache sets the reward cache tree // // Parameters: // - rewardCache: Tree containing the pool's per-second GNS reward snapshots. func (p *Pool) SetRewardCache(rewardCache *UintTree) { p.rewardCache = rewardCache } // SetRewardCacheAt records the per-second reward rate for a timestamp. // // Parameters: // - currentTime: Nonnegative Unix timestamp in seconds used as the cache key. // - reward: GNS reward emitted per second from currentTime until the next cached change. func (p *Pool) SetRewardCacheAt(currentTime int64, reward int64) { p.RewardCache().Set(currentTime, reward) } // Incentives returns the incentives // // Returns: // - incentives: External-incentive collection associated with this pool. func (p *Pool) Incentives() *Incentives { return p.incentives } // SetIncentives sets the incentives // // Parameters: // - incentives: External-incentive collection to associate with the pool. func (p *Pool) SetIncentives(incentives *Incentives) { p.incentives = incentives } // Ticks returns the ticks // // Returns: // - ticks: Addressable tick mapping for this pool's staked positions. func (p *Pool) Ticks() *Ticks { return &p.ticks } // SetTicks sets the ticks // // Parameters: // - ticks: Tick mapping value to store in the pool. func (p *Pool) SetTicks(ticks Ticks) { p.ticks = ticks } // GlobalRewardRatioAccumulation returns the global reward ratio accumulation tree // // Returns: // - tree: Historical global time-per-total-stake accumulation keyed by Unix timestamp. func (p *Pool) GlobalRewardRatioAccumulation() *UintTree { return p.globalRewardRatioAccumulation } // SetGlobalRewardRatioAccumulation sets the global reward ratio accumulation tree // // Parameters: // - globalRewardRatioAccumulation: Tree of serialized Q128-scaled reward-ratio accumulation snapshots. func (p *Pool) SetGlobalRewardRatioAccumulation(globalRewardRatioAccumulation *UintTree) { p.globalRewardRatioAccumulation = globalRewardRatioAccumulation } // SetGlobalRewardRatioAccumulationAt records a serialized global reward-ratio accumulation snapshot. // // Parameters: // - currentTime: Nonnegative Unix timestamp in seconds used as the snapshot key. // - acc: Serialized Q128-scaled global reward-ratio accumulation value. func (p *Pool) SetGlobalRewardRatioAccumulationAt(currentTime int64, acc string) { p.GlobalRewardRatioAccumulation().Set(currentTime, acc) } // HistoricalTick returns the historical tick tree // // Returns: // - tree: Historical tick-ID ordering snapshots keyed by Unix timestamp. func (p *Pool) HistoricalTick() *UintTree { return p.historicalTick } // SetHistoricalTick sets the historical tick tree // // Parameters: // - historicalTick: Tree of tick IDs representing the ordering history of staked positions. func (p *Pool) SetHistoricalTick(historicalTick *UintTree) { p.historicalTick = historicalTick } // SetHistoricalTickAt records the tick ordering snapshot for a timestamp. // // Parameters: // - currentTime: Nonnegative Unix timestamp in seconds used as the snapshot key. // - tick: Tick ID representing the pool's historical ordering at currentTime. func (p *Pool) SetHistoricalTickAt(currentTime int64, tick int32) { p.HistoricalTick().Set(currentTime, tick) } // Clone returns a pool copy of the scalar state with a fresh tick container. // // Returns: // - pool: Pool copy carrying scalar state and a fresh tick container; backing trees and incentives are nil, and nil receiver yields nil. func (p *Pool) Clone() *Pool { if p == nil { return nil } return &Pool{ poolPath: p.poolPath, stakedLiquidity: nil, lastUnclaimableTime: p.lastUnclaimableTime, unclaimableAcc: p.unclaimableAcc, rewardCache: nil, incentives: nil, ticks: NewTicks(), globalRewardRatioAccumulation: nil, historicalTick: nil, } } // NewPool creates pool reward state initialized at currentTime (Unix seconds). // // Parameters: // - poolPath: Pool identifier to store in the new reward-state object. // - currentTime: Unix timestamp in seconds used to seed the initial accumulation, reward-cache, and liquidity snapshots. // // Returns: // - pool: Initialized pool with empty backing structures and zero initial reward/liquidity snapshots at currentTime. func NewPool(poolPath string, currentTime int64) *Pool { pool := &Pool{ poolPath: poolPath, stakedLiquidity: NewUintTreeN(64), // lastUnclaimableTime is initialized to 0, which means "tracking not started yet". // When the pool receives a tier assignment (or external incentive), `cacheReward` will be called, // which will automatically call `startUnclaimablePeriod` if the pool has zero liquidity. // This ensures proper unclaimable period tracking from the moment rewards start emitting. lastUnclaimableTime: 0, unclaimableAcc: 0, rewardCache: NewUintTreeN(64), incentives: NewIncentives(poolPath), ticks: NewTicks(), globalRewardRatioAccumulation: NewUintTreeN(64), historicalTick: NewUintTreeN(64), } pool.SetGlobalRewardRatioAccumulationAt(currentTime, "0") // Initialize rewardCache to 0 to ensure `cacheReward` will trigger on first tier assignment pool.SetRewardCacheAt(currentTime, int64(0)) pool.SetStakedLiquidityAt(currentTime, u256.Zero()) return pool } // Incentives represents a collection of external incentives for a specific pool. // // Fields: // // - incentives: BPTree storing ExternalIncentive objects indexed by incentiveId // The incentiveId serves as the key to efficiently lookup incentive details // // - targetPoolPath: String identifier for the pool this incentive collection belongs to // Used to associate incentives with their corresponding liquidity pool // // - unclaimablePeriods: Tree storing periods when rewards cannot be claimed // Maps start timestamp (key) to end timestamp (value) // An end timestamp of 0 indicates an ongoing unclaimable period // Used to track intervals when staking rewards are not claimable // // - byStartTime: Per-pool start-time index mapping an incentive's start // timestamp (key) to the incentive IDs that start at that timestamp // (value). This mirrors the lazy-discovery lookup previously served by a // global creation-time index, but scoped to this pool's own incentives, so // discovery cost is bounded by this pool's incentives instead of growing // with the total number of incentives system-wide. type Incentives struct { incentives *bptree.BPTree // (incentiveId) => ExternalIncentive targetPoolPath string // The target pool path for this incentive collection unclaimablePeriods *UintTree // blockTimestamp -> any byStartTime *UintTree // startTimestamp -> []incentiveId } // Incentives Getter/Setter methods // Incentives returns the incentives tree // // Returns: // - tree: Mutable B+ tree mapping incentive IDs to ExternalIncentive records. func (i *Incentives) IncentiveTrees() *bptree.BPTree { return i.incentives } // SetIncentives sets the incentives tree // // Parameters: // - incentives: B+ tree to use for incentive ID lookups and storage. func (i *Incentives) SetIncentives(incentives *bptree.BPTree) { i.incentives = incentives } // TargetPoolPath returns the target pool path // // Returns: // - path: Pool path to which this incentive collection belongs. func (i *Incentives) TargetPoolPath() string { return i.targetPoolPath } // SetTargetPoolPath sets the target pool path // // Parameters: // - targetPoolPath: Pool path to associate with this incentive collection. func (i *Incentives) SetTargetPoolPath(targetPoolPath string) { i.targetPoolPath = targetPoolPath } // UnclaimablePeriods returns the unclaimable periods tree // // Returns: // - periods: Tree mapping unclaimable-period start timestamps to end timestamps; end 0 denotes an open period. func (i *Incentives) UnclaimablePeriods() *UintTree { return i.unclaimablePeriods } // SetUnclaimablePeriods sets the unclaimable periods tree // // Parameters: // - unclaimablePeriods: Tree of reward-unclaimable intervals keyed by their start timestamps. func (i *Incentives) SetUnclaimablePeriods(unclaimablePeriods *UintTree) { i.unclaimablePeriods = unclaimablePeriods } // Incentive returns an incentive by ID // // Parameters: // - incentiveId: Identifier used to look up the external incentive record. // // Returns: // - incentive: Matching ExternalIncentive pointer, or nil when no value is stored for incentiveId. // - found: True only when the stored value has ExternalIncentive type; false for a missing or mismatched value. func (i *Incentives) Incentive(incentiveId string) (*ExternalIncentive, bool) { value := i.incentives.Get(incentiveId) if value == nil { return nil, false } incentive, ok := value.(*ExternalIncentive) return incentive, ok } // SetIncentive sets an incentive by ID // // Parameters: // - incentiveId: Identifier under which to store the incentive. // - incentive: ExternalIncentive record to store for incentiveId. func (i *Incentives) SetIncentive(incentiveId string, incentive *ExternalIncentive) { i.incentives.Set(incentiveId, incentive) } // RemoveIncentive deletes an incentive by ID. // // Only an incentive that never started may be removed: once rewards begin // accruing, deposits and the refund accounting reference the record, so an // ended incentive is marked refunded instead of removed. // // Parameters: // - incentiveId: Identifier of the external incentive record to remove. func (i *Incentives) RemoveIncentive(incentiveId string) { i.incentives.Remove(incentiveId) } // SetUnclaimablePeriod records an interval during which staking rewards cannot be claimed. // // Parameters: // - startTimestamp: Nonnegative Unix timestamp in seconds at which the interval begins. // - endTimestamp: Unix timestamp in seconds at which the interval ends; 0 records an ongoing interval. func (i *Incentives) SetUnclaimablePeriod(startTimestamp int64, endTimestamp int64) { i.unclaimablePeriods.Set(startTimestamp, endTimestamp) } // RemoveUnclaimablePeriod removes the interval keyed by its start timestamp. // // Parameters: // - startTimestamp: Nonnegative Unix timestamp in seconds identifying the interval to remove. func (i *Incentives) RemoveUnclaimablePeriod(startTimestamp int64) { i.unclaimablePeriods.Remove(startTimestamp) } // IterateIncentives iterates over all incentives // // Parameters: // - fn: Callback receiving each incentive ID and record; returning true requests that iteration stop. func (i *Incentives) IterateIncentives(fn func(incentiveId string, incentive *ExternalIncentive) bool) { i.incentives.Iterate("", "", func(key string, value interface{}) bool { if incentive, ok := value.(*ExternalIncentive); ok { return fn(key, incentive) } return false }) } // AddIncentiveByStartTime registers an incentive ID under its start timestamp // in the per-pool start-time index. Multiple incentives starting at the same // timestamp are accumulated as a list. // // Parameters: // - startTimestamp: Nonnegative Unix timestamp in seconds used as the start-time index key. // - incentiveId: Incentive identifier to append to that timestamp's bucket. func (i *Incentives) AddIncentiveByStartTime(startTimestamp int64, incentiveId string) { var incentiveIds []string if value, ok := i.byStartTime.Get(startTimestamp); ok { if ids, ok := value.([]string); ok { incentiveIds = ids } } incentiveIds = append(incentiveIds, incentiveId) i.byStartTime.Set(startTimestamp, incentiveIds) } // RemoveIncentiveByStartTime unregisters an incentive ID from the per-pool // start-time index. The bucket itself is dropped once its last ID is removed, // so the index never keeps an empty entry that discovery would still visit. // // Parameters: // - startTimestamp: Nonnegative Unix timestamp in seconds identifying the start-time bucket. // - incentiveId: Incentive identifier to remove from that bucket; all matching entries are omitted. func (i *Incentives) RemoveIncentiveByStartTime(startTimestamp int64, incentiveId string) { value, ok := i.byStartTime.Get(startTimestamp) if !ok { return } ids, ok := value.([]string) if !ok { return } remaining := make([]string, 0, len(ids)) for _, id := range ids { if id == incentiveId { continue } remaining = append(remaining, id) } if len(remaining) == 0 { i.byStartTime.Remove(startTimestamp) return } i.byStartTime.Set(startTimestamp, remaining) } // IterateIncentiveIdsByTime iterates over the incentive IDs that start within // the inclusive [startTime, endTime] range, visiting only the buckets that // fall in the range. ReverseIterate is used because it is inclusive on both // ends, matching the discovery semantics previously implemented as // (startTimestamp >= startTime && startTimestamp <= endTime). // // Parameters: // - startTime: Inclusive lower Unix timestamp bound for incentive starts. // - endTime: Inclusive upper Unix timestamp bound for incentive starts. // - fn: Callback receiving each matching incentive ID; returning true requests that iteration stop. func (i *Incentives) IterateIncentiveIdsByTime(startTime, endTime int64, fn func(incentiveId string) bool) { i.byStartTime.ReverseIterate(startTime, endTime, func(_ int64, value any) bool { incentiveIds, ok := value.([]string) if !ok { return false } for _, incentiveId := range incentiveIds { if fn(incentiveId) { return true } } return false }) } // NewIncentives creates an incentive collection for a pool and starts an open unclaimable period at the current time. // // Parameters: // - targetPoolPath: Pool path to associate with the new incentive collection. // // Returns: // - incentives: Collection with initialized incentive, start-time, and unclaimable-period trees. func NewIncentives(targetPoolPath string) *Incentives { result := &Incentives{ targetPoolPath: targetPoolPath, unclaimablePeriods: NewUintTreeN(64), incentives: bptree.NewBPTreeN(16), byStartTime: NewUintTreeN(64), } // initial unclaimable period starts, as there cannot be any staked positions yet. currentTimestamp := time.Now().Unix() result.SetUnclaimablePeriod(currentTimestamp, int64(0)) return result } type ExternalIncentive struct { incentiveId string // incentive id startTimestamp int64 // start time for external reward endTimestamp int64 // end time for external reward createdHeight int64 // block height when the incentive was created createdTimestamp int64 // timestamp when the incentive was created depositGnsAmount int64 // deposited gns amount targetPoolPath string // external reward target pool path rewardToken string // external reward token path totalRewardAmount int64 // total reward amount rewardAmount int64 // mutable remaining reward amount rewardPerSecondX128 *u256.Uint // reward per second, scaled by 2^128 to preserve sub-second precision distributedRewardAmount int64 // reward amount delivered to positions or refunded at incentive end accumulatedPenaltyAmount int64 // accumulated warmup penalty from CollectReward creator address // creator address refunded bool // whether EndExternalIncentive finalized the incentive and returned its refundable portion and GNS deposit unclaimableSeconds int64 // accumulated seconds of unclaimable periods overlapping the incentive window } // ExternalIncentive Getter/Setter methods // IncentiveId returns the incentive ID // // Returns: // - id: Identifier assigned to this external incentive. func (e *ExternalIncentive) IncentiveId() string { return e.incentiveId } // SetIncentiveId sets the incentive ID // // Parameters: // - incentiveId: Identifier to store on the incentive record. func (e *ExternalIncentive) SetIncentiveId(incentiveId string) { e.incentiveId = incentiveId } // StartTimestamp returns the start timestamp. // // It keys the byStartTime discovery index and must stay immutable after the // incentive is registered, so no setter is exposed. // // Returns: // - timestamp: Unix timestamp in seconds at which reward distribution starts. func (e *ExternalIncentive) StartTimestamp() int64 { return e.startTimestamp } // EndTimestamp returns the end timestamp // // Returns: // - timestamp: Unix timestamp in seconds at which the incentive window ends. func (e *ExternalIncentive) EndTimestamp() int64 { return e.endTimestamp } // SetEndTimestamp sets the end timestamp // // Parameters: // - endTimestamp: Unix timestamp in seconds at which the incentive window ends. func (e *ExternalIncentive) SetEndTimestamp(endTimestamp int64) { e.endTimestamp = endTimestamp } // CreatedHeight returns the created height // // Returns: // - height: Block height at which the incentive record was created. func (e *ExternalIncentive) CreatedHeight() int64 { return e.createdHeight } // SetCreatedHeight sets the created height // // Parameters: // - createdHeight: Block height to record as the incentive's creation height. func (e *ExternalIncentive) SetCreatedHeight(createdHeight int64) { e.createdHeight = createdHeight } // CreatedTimestamp returns the created timestamp // // Returns: // - timestamp: Unix timestamp in seconds at which the incentive record was created. func (e *ExternalIncentive) CreatedTimestamp() int64 { return e.createdTimestamp } // SetCreatedTimestamp sets the created timestamp // // Parameters: // - createdTimestamp: Unix timestamp in seconds to record as the incentive creation time. func (e *ExternalIncentive) SetCreatedTimestamp(createdTimestamp int64) { e.createdTimestamp = createdTimestamp } // DepositGnsAmount returns the deposit GNS amount // // Returns: // - amount: GNS amount deposited to back this external incentive. func (e *ExternalIncentive) DepositGnsAmount() int64 { return e.depositGnsAmount } // SetDepositGnsAmount sets the deposit GNS amount // // Parameters: // - depositGnsAmount: GNS amount deposited to back this external incentive. func (e *ExternalIncentive) SetDepositGnsAmount(depositGnsAmount int64) { e.depositGnsAmount = depositGnsAmount } // TargetPoolPath returns the target pool path // // Returns: // - path: Pool path targeted by this external incentive. func (e *ExternalIncentive) TargetPoolPath() string { return e.targetPoolPath } // SetTargetPoolPath sets the target pool path // // Parameters: // - targetPoolPath: Pool path to target with this external incentive. func (e *ExternalIncentive) SetTargetPoolPath(targetPoolPath string) { e.targetPoolPath = targetPoolPath } // RewardToken returns the reward token // // Returns: // - token: Reward-token path distributed by this incentive. func (e *ExternalIncentive) RewardToken() string { return e.rewardToken } // SetRewardToken sets the reward token // // Parameters: // - rewardToken: Token path of the reward asset distributed by this incentive. func (e *ExternalIncentive) SetRewardToken(rewardToken string) { e.rewardToken = rewardToken } // TotalRewardAmount returns the total reward amount // // Returns: // - amount: Total reward amount configured when the incentive was created. func (e *ExternalIncentive) TotalRewardAmount() int64 { return e.totalRewardAmount } // SetTotalRewardAmount sets the total reward amount // // Parameters: // - totalRewardAmount: Total reward amount to record for the incentive. func (e *ExternalIncentive) SetTotalRewardAmount(totalRewardAmount int64) { e.totalRewardAmount = totalRewardAmount } // RewardAmount returns the reward amount // // Returns: // - amount: Mutable reward amount remaining after distributions and refunds. func (e *ExternalIncentive) RewardAmount() int64 { return e.rewardAmount } // SetRewardAmount sets the reward amount // // Parameters: // - rewardAmount: Remaining reward amount to store after accounting adjustments. func (e *ExternalIncentive) SetRewardAmount(rewardAmount int64) { e.rewardAmount = rewardAmount } // RewardPerSecondX128 returns the Q128-scaled reward per second. // The underlying value is (rewardAmount << 128) / duration. // // Returns: // - rate: Reward emitted per second, scaled by 2^128 for fixed-point accounting. func (e *ExternalIncentive) RewardPerSecondX128() *u256.Uint { return e.rewardPerSecondX128 } // SetRewardPerSecondX128 sets the Q128-scaled reward per second. // // Parameters: // - rewardPerSecondX128: Q128-scaled per-second reward rate; the value is copied before storage. func (e *ExternalIncentive) SetRewardPerSecondX128(rewardPerSecondX128 *u256.Uint) { e.rewardPerSecondX128 = u256.Zero().Set(rewardPerSecondX128) } // DistributedRewardAmount returns the distributed reward amount // // Returns: // - amount: Reward amount already delivered to positions or refunded at incentive end. func (e *ExternalIncentive) DistributedRewardAmount() int64 { return e.distributedRewardAmount } // SetDistributedRewardAmount sets the distributed reward amount // // Parameters: // - distributedRewardAmount: Reward amount delivered to positions or refunded at incentive end. func (e *ExternalIncentive) SetDistributedRewardAmount(distributedRewardAmount int64) { e.distributedRewardAmount = distributedRewardAmount } // AccumulatedPenaltyAmount returns the accumulated warmup penalty amount // // Returns: // - amount: Warm-up penalty accumulated from reward collections for this incentive. func (e *ExternalIncentive) AccumulatedPenaltyAmount() int64 { return e.accumulatedPenaltyAmount } // SetAccumulatedPenaltyAmount sets the accumulated warmup penalty amount // // Parameters: // - accumulatedPenaltyAmount: Warm-up penalty amount to store in the incentive's accumulated accounting. func (e *ExternalIncentive) SetAccumulatedPenaltyAmount(accumulatedPenaltyAmount int64) { e.accumulatedPenaltyAmount = accumulatedPenaltyAmount } // Creator returns the creator address // // Returns: // - creator: Address that created and funded the incentive. func (e *ExternalIncentive) Creator() address { return e.creator } // SetCreator sets the creator address // // Parameters: // - creator: Address to record as the incentive creator and refund recipient. func (e *ExternalIncentive) SetCreator(creator address) { e.creator = creator } // Refunded returns the refunded status // // Returns: // - refunded: True when incentive finalization has marked its refundable balances as returned. func (e *ExternalIncentive) Refunded() bool { return e.refunded } // SetRefunded sets the refunded status // // Parameters: // - refunded: Finalization status to store for the incentive. func (e *ExternalIncentive) SetRefunded(refunded bool) { e.refunded = refunded } // UnclaimableSeconds returns the accumulated seconds of unclaimable periods // that overlap the incentive window. It is updated whenever an unclaimable // period closes and is backfilled once from the historical unclaimable // periods tree after an upgrade. // // Returns: // - seconds: Accumulated seconds of unclaimable periods overlapping the incentive window. func (e *ExternalIncentive) UnclaimableSeconds() int64 { return e.unclaimableSeconds } // SetUnclaimableSeconds sets the accumulated unclaimable seconds. // // Parameters: // - unclaimableSeconds: Overlapping unclaimable duration in seconds to store. func (e *ExternalIncentive) SetUnclaimableSeconds(unclaimableSeconds int64) { e.unclaimableSeconds = unclaimableSeconds } // Clone returns an independent ExternalIncentive value with scalar fields copied and its fixed-point rate duplicated. // // Returns: // - incentive: Copied external incentive record; its fixed-point rate is cloned when present and otherwise initialized to zero. func (e *ExternalIncentive) Clone() *ExternalIncentive { rewardPerSecondX128 := u256.Zero() if e.rewardPerSecondX128 != nil { rewardPerSecondX128 = e.rewardPerSecondX128.Clone() } return &ExternalIncentive{ incentiveId: e.incentiveId, startTimestamp: e.startTimestamp, endTimestamp: e.endTimestamp, createdHeight: e.createdHeight, createdTimestamp: e.createdTimestamp, depositGnsAmount: e.depositGnsAmount, targetPoolPath: e.targetPoolPath, rewardToken: e.rewardToken, totalRewardAmount: e.totalRewardAmount, rewardAmount: e.rewardAmount, rewardPerSecondX128: rewardPerSecondX128, creator: e.creator, refunded: e.refunded, unclaimableSeconds: e.unclaimableSeconds, distributedRewardAmount: e.distributedRewardAmount, accumulatedPenaltyAmount: e.accumulatedPenaltyAmount, } } // NewExternalIncentive creates a new external incentive // // Parameters: // - incentiveId: Unique identifier assigned to the external incentive. // - targetPoolPath: Pool path whose staked positions may receive this incentive. // - rewardToken: Token path of the asset deposited for distribution. // - rewardAmount: Total reward amount, also used as the initial remaining reward balance. // - startTimestamp: Unix timestamp in seconds when reward distribution starts. // - endTimestamp: Unix timestamp in seconds when reward distribution ends; duration is endTimestamp-startTimestamp and must be nonzero for the rate calculation. // - creator: Address that funds the incentive and receives refunds at finalization. // - depositGnsAmount: GNS amount deposited as the incentive's required collateral. // - createdHeight: Block height to record for incentive creation. // - currentTime: Unix timestamp in seconds recorded as the incentive creation time. // // Returns: // - incentive: New incentive with a Q128-scaled per-second rate and zeroed distribution, penalty, and unclaimable counters. func NewExternalIncentive( incentiveId string, targetPoolPath string, rewardToken string, rewardAmount int64, startTimestamp int64, // timestamp is in unix time(seconds) endTimestamp int64, creator address, depositGnsAmount int64, createdHeight int64, currentTime int64, // current time in unix time(seconds) ) *ExternalIncentive { incentiveDuration := endTimestamp - startTimestamp // Compute reward per second scaled by 2^128 to preserve sub-second precision. // rewardPerSecondX128 = (rewardAmount << 128) / incentiveDuration. // Consumers must divide by 2^128 when materializing back to a plain integer. rewardPerSecondX128 := u256.MulDiv( u256.NewUintFromInt64(rewardAmount), consts.Q128(), u256.NewUintFromInt64(incentiveDuration), ) return &ExternalIncentive{ incentiveId: incentiveId, targetPoolPath: targetPoolPath, rewardToken: rewardToken, totalRewardAmount: rewardAmount, rewardAmount: rewardAmount, startTimestamp: startTimestamp, endTimestamp: endTimestamp, rewardPerSecondX128: rewardPerSecondX128, distributedRewardAmount: 0, accumulatedPenaltyAmount: 0, creator: creator, createdHeight: createdHeight, createdTimestamp: currentTime, depositGnsAmount: depositGnsAmount, refunded: false, unclaimableSeconds: 0, } } // Tick mapping for each pool type Ticks struct { tree *bptree.BPTree // int32 tickId -> tick } // Ticks Getter/Setter methods // Tree returns the ticks tree // // Returns: // - tree: Mutable B+ tree mapping encoded int32 tick IDs to Tick records. func (t *Ticks) Tree() *bptree.BPTree { return t.tree } // SetTree sets the ticks tree // // Parameters: // - tree: B+ tree to use for tick storage. func (t *Ticks) SetTree(tree *bptree.BPTree) { t.tree = tree } // Get returns the tick for the given tickId, or nil if it does not exist. // // Parameters: // - tickId: Tick index to look up. // // Returns: // - tick: Matching Tick record, or nil when the encoded ID is absent; panics if a stored value has the wrong type. func (t *Ticks) Get(tickId int32) *Tick { v := t.tree.Get(utils.EncodeInt32(tickId)) if v == nil { return nil } tick, ok := v.(*Tick) if !ok { panic("failed to cast value to *Tick") } return tick } // Has reports whether a tick ID is present in the underlying tree. // // Parameters: // - tickId: Tick index whose encoded key is tested. // // Returns: // - present: True when the encoded tick ID exists in the underlying tree. func (self *Ticks) Has(tickId int32) bool { return self.tree.Has(utils.EncodeInt32(tickId)) } // SetTick sets a tick by ID // // Parameters: // - tickId: Tick index under which to store the record. // - tick: Non-nil Tick record to store; a zero gross staked liquidity removes the tick instead, while nil input panics during the gross-liquidity check. func (t *Ticks) SetTick(tickId int32, tick *Tick) { if tick.stakedLiquidityGross.IsZero() { t.tree.Remove(utils.EncodeInt32(tickId)) return } t.tree.Set(utils.EncodeInt32(tickId), tick) } // IterateTicks iterates over all ticks // // Parameters: // - fn: Callback receiving each stored Tick and decoded tick ID; returning true requests that iteration stop. func (t *Ticks) IterateTicks(fn func(tickId int32, tick *Tick) bool) { t.tree.Iterate("", "", func(key string, value interface{}) bool { tick, ok := value.(*Tick) if !ok { return false } return fn(utils.DecodeInt32(key), tick) }) } // Clone returns a deep copy of ticks. // // Returns: // - ticks: New Ticks value with cloned Tick records in a fresh fanout-16 tree. func (t Ticks) Clone() Ticks { cloned := bptree.NewBPTreeN(16) t.tree.Iterate("", "", func(key string, value any) bool { tick, ok := value.(*Tick) if !ok { panic("failed to cast value to *Tick") } cloned.Set(key, tick.Clone()) return false }) return Ticks{tree: cloned} } // NewTicks creates an empty tick mapping with a fanout-16 B+ tree. // // Returns: // - ticks: Empty Ticks value ready to store pool tick records. func NewTicks() Ticks { return Ticks{ tree: bptree.NewBPTreeN(16), } } // Tick represents the state of a specific tick in a pool. // // Fields: // - id (int32): The ID of the tick. // - stakedLiquidityGross (*u256.Uint): Total gross staked liquidity at this tick. // - stakedLiquidityDelta (*i256.Int): Net change in staked liquidity at this tick. // - outsideAccumulation (*UintTree): RewardRatioAccumulation outside the tick. type Tick struct { id int32 // conceptually equal with Pool.liquidityGross but only for the staked positions stakedLiquidityGross *u256.Uint // conceptually equal with Pool.liquidityNet but only for the staked positions stakedLiquidityDelta *i256.Int // currentOutsideAccumulation is the accumulation of the time / TotalStake outside the tick. // It is calculated by subtracting the current tick's currentOutsideAccumulation from the global reward ratio accumulation. outsideAccumulation *UintTree // timestamp -> fixed 32-byte big-endian string } // Tick Getter/Setter methods // Id returns the tick ID // // Returns: // - id: Tick index represented by this record. func (t *Tick) Id() int32 { return t.id } // SetId sets the tick ID // // Parameters: // - id: Tick index to store in the record. func (t *Tick) SetId(id int32) { t.id = id } // StakedLiquidityGross returns the staked liquidity gross // // Returns: // - liquidity: Total gross staked liquidity currently associated with this tick. func (t *Tick) StakedLiquidityGross() *u256.Uint { return t.stakedLiquidityGross } // SetStakedLiquidityGross sets the staked liquidity gross // // Parameters: // - stakedLiquidityGross: New total gross staked liquidity; the value is copied before storage. func (t *Tick) SetStakedLiquidityGross(stakedLiquidityGross *u256.Uint) { t.stakedLiquidityGross = u256.Zero().Set(stakedLiquidityGross) } // StakedLiquidityDelta returns the staked liquidity delta // // Returns: // - delta: Net staked liquidity change associated with this tick. func (t *Tick) StakedLiquidityDelta() *i256.Int { return t.stakedLiquidityDelta } // SetStakedLiquidityDelta sets the staked liquidity delta // // Parameters: // - stakedLiquidityDelta: New net staked liquidity delta; the value is copied before storage. func (t *Tick) SetStakedLiquidityDelta(stakedLiquidityDelta *i256.Int) { t.stakedLiquidityDelta = i256.Zero().Set(stakedLiquidityDelta) } // OutsideAccumulation returns the outside accumulation tree // // Returns: // - tree: Historical reward-ratio accumulation observed outside this tick. func (t *Tick) OutsideAccumulation() *UintTree { return t.outsideAccumulation } // SetOutsideAccumulation sets the outside accumulation tree // // Parameters: // - outsideAccumulation: UintTree of outside-accumulation snapshots keyed by Unix timestamp. func (t *Tick) SetOutsideAccumulation(outsideAccumulation *UintTree) { t.outsideAccumulation = outsideAccumulation } // SetOutsideAccumulationAt sets the outside accumulation at the timestamp. // SetOutsideAccumulationAt records the Q128-scaled outside accumulation at a timestamp. // // Parameters: // - timestamp: Nonnegative Unix timestamp in seconds used as the snapshot key. // - acc: Q128-scaled accumulation value encoded into the tree. func (t *Tick) SetOutsideAccumulationAt(timestamp int64, acc *u256.Uint) { t.outsideAccumulation.Set(timestamp, utils.EncodeUint256(acc)) } // Clone returns a deep copy of the tick. // // Returns: // - tick: Deep copy of the tick and its outside-accumulation tree, or nil when the receiver is nil. func (t *Tick) Clone() *Tick { if t == nil { return nil } return &Tick{ id: t.id, stakedLiquidityGross: t.stakedLiquidityGross.Clone(), stakedLiquidityDelta: t.stakedLiquidityDelta.Clone(), outsideAccumulation: t.outsideAccumulation.Clone(), } } // NewTick creates a tick with zero staked liquidity and an empty fanout-4 outside-accumulation tree. // // Parameters: // - tickId: Tick index to assign to the new record. // // Returns: // - tick: Initialized tick record. func NewTick(tickId int32) *Tick { return &Tick{ id: tickId, stakedLiquidityGross: u256.Zero(), stakedLiquidityDelta: i256.Zero(), outsideAccumulation: NewUintTreeN(4), } } // 100%, 0%, 0% if no tier2 and tier3 // 80%, 0%, 20% if no tier2 // 70%, 30%, 0% if no tier3 // 50%, 30%, 20% if has tier2 and tier3 type TierRatio struct { Tier1 uint64 Tier2 uint64 Tier3 uint64 } // NewTierRatio constructs the reward-share ratio for tiers 1 through 3. // // Parameters: // - tier1: Tier-1 share scaled by 100 (for example, 70 means 70%). // - tier2: Tier-2 share scaled by 100. // - tier3: Tier-3 share scaled by 100. // // Returns: // - ratio: TierRatio containing the supplied scaled shares. func NewTierRatio(tier1, tier2, tier3 uint64) TierRatio { return TierRatio{ Tier1: tier1, Tier2: tier2, Tier3: tier3, } } // Get returns the ratio(scaled up by 100) for the given tier. // // Parameters: // - tier: Tier number to query; only tiers 1, 2, and 3 are supported. // // Returns: // - ratio: Requested tier share scaled by 100. // - err: Non-nil when tier is not 1, 2, or 3; nil for a supported tier. func (ratio *TierRatio) Get(tier uint64) (uint64, error) { switch tier { case 1: return ratio.Tier1, nil case 2: return ratio.Tier2, nil case 3: return ratio.Tier3, nil default: return 0, errors.New(ufmt.Sprintf("unsupported tier(%d)", tier)) } } // SwapBatchProcessor processes tick crosses in batch for a swap // This processor accumulates all tick crosses that occur during a single swap // and processes them together at the end, reducing redundant calculations // and state updates that would occur with individual tick processing type SwapBatchProcessor struct { poolPath string // The pool path identifier for this swap pool *Pool // Reference to the pool being swapped in crosses []*SwapTickCross // Accumulated tick crosses during the swap timestamp int64 // Timestamp when the swap started isActive bool // Flag to prevent accumulation after swap ends } // PoolPath returns the pool path associated with this swap batch. // // Returns: // - path: Pool identifier for the swap being processed. func (s *SwapBatchProcessor) PoolPath() string { return s.poolPath } // SetPoolPath stores the pool identifier associated with this swap batch. // // Parameters: // - poolPath: Pool identifier to associate with the swap batch. func (s *SwapBatchProcessor) SetPoolPath(poolPath string) { s.poolPath = poolPath } // Pool returns the pool referenced by this swap batch. // // Returns: // - pool: Pool state used to process the accumulated tick crosses. func (s *SwapBatchProcessor) Pool() *Pool { return s.pool } // SetPool replaces the pool reference used by this swap batch. // // Parameters: // - pool: Pool state to reference while processing tick crosses. func (s *SwapBatchProcessor) SetPool(pool *Pool) { s.pool = pool } // Crosses returns the tick crosses accumulated by this batch. // // Returns: // - crosses: Slice of tick-cross records in the order they were added. func (s *SwapBatchProcessor) Crosses() []*SwapTickCross { return s.crosses } // SetCrosses replaces the batch's accumulated tick-cross sequence. // // Parameters: // - crosses: Tick-cross records to store as the batch's accumulated sequence. func (s *SwapBatchProcessor) SetCrosses(crosses []*SwapTickCross) { s.crosses = crosses } // Timestamp returns the Unix timestamp in seconds recorded when the swap started. // // Returns: // - timestamp: Swap-start timestamp in Unix seconds. func (s *SwapBatchProcessor) Timestamp() int64 { return s.timestamp } // SetTimestamp stores the swap-start timestamp for this batch. // // Parameters: // - timestamp: Unix timestamp in seconds to record for the swap batch. func (s *SwapBatchProcessor) SetTimestamp(timestamp int64) { s.timestamp = timestamp } // IsActive reports the processor's stored active flag. // // Returns: // - active: True when the batch is marked active for the swap lifecycle. func (s *SwapBatchProcessor) IsActive() bool { return s.isActive } // SetIsActive stores the processor's active lifecycle flag. // // Parameters: // - isActive: Active flag to store for the swap lifecycle. func (s *SwapBatchProcessor) SetIsActive(isActive bool) { s.isActive = isActive } // LastCross returns the most recently appended tick cross. // // Returns: // - cross: Last tick-cross record, or nil when no crosses have been added. func (s *SwapBatchProcessor) LastCross() *SwapTickCross { if len(s.crosses) == 0 { return nil } return s.crosses[len(s.crosses)-1] } // AddCross appends a tick-cross record to the batch sequence. // // Parameters: // - tickCross: Tick-cross record to append. func (s *SwapBatchProcessor) AddCross(tickCross *SwapTickCross) { s.crosses = append(s.crosses, tickCross) } // NewSwapBatchProcessor creates an active batch for collecting tick crosses in a pool swap. // // Parameters: // - poolPath: Pool identifier associated with the swap. // - pool: Pool state whose tick crosses are being collected. // - timestamp: Unix timestamp in seconds when the swap began. // // Returns: // - processor: Active processor with an empty cross sequence. func NewSwapBatchProcessor(poolPath string, pool *Pool, timestamp int64) *SwapBatchProcessor { return &SwapBatchProcessor{ poolPath: poolPath, pool: pool, crosses: make([]*SwapTickCross, 0), timestamp: timestamp, isActive: true, } } // SwapTickCross stores information about a tick cross during a swap // This struct is used to accumulate tick cross events during a single swap transaction // for batch processing to optimize gas usage and computational efficiency type SwapTickCross struct { tickID int32 // The tick index that was crossed zeroForOne bool // Direction of the swap (true: token0->token1, false: token1->token0) delta *i256.Int // Pre-calculated liquidity delta for this tick cross } // TickID returns the index of the crossed tick. // // Returns: // - tickID: Tick index represented by this cross. func (s *SwapTickCross) TickID() int32 { return s.tickID } // ZeroForOne reports the swap direction represented by this cross. // // Returns: // - zeroForOne: True for token0-to-token1 swaps; false for token1-to-token0 swaps. func (s *SwapTickCross) ZeroForOne() bool { return s.zeroForOne } // Delta returns the precomputed net staked-liquidity change for the crossed tick. // // Returns: // - delta: Signed liquidity delta to apply at the crossed tick. func (s *SwapTickCross) Delta() *i256.Int { return s.delta } // NewSwapTickCross creates a tick-cross record for a swap batch. // // Parameters: // - tickID: Index of the tick crossed during the swap. // - zeroForOne: Swap direction; true means token0-to-token1 and false means token1-to-token0. // - delta: Precomputed signed staked-liquidity change for this tick cross. // // Returns: // - cross: Tick-cross record containing the supplied index, direction, and delta. func NewSwapTickCross(tickID int32, zeroForOne bool, delta *i256.Int) *SwapTickCross { return &SwapTickCross{ tickID: tickID, zeroForOne: zeroForOne, delta: delta, } }
  20. #20proxy.gno
  21. #21package staker // StakeToken stakes a position NFT to earn rewards. // // Parameters: // - cur: Current realm context; callers use cross(cur) when crossing into this realm. // - positionId: LP position NFT token ID to stake. // - referrer: Optional referral address string used for referral tracking. // // Returns: // - string: Pool path where the position was staked. // // Halt check: reverts while the Staker halt scope is active. func StakeToken(cur realm, positionId uint64, referrer string) string { return getImplementation().StakeToken(0, cur, positionId, referrer) } // UnStakeToken unstakes a position NFT and creates an exit checkpoint for its rewards. // // The NFT is returned to its owner without calculating or paying rewards. Use a Collect* entry // point afterward; collection of an exit checkpoint is permissionless and pays its pinned owner. // // Parameters: // - cur: Current realm context; callers use cross(cur) when crossing into this realm. // - positionId: LP position NFT token ID to unstake. // // Returns: // - string: Pool path where the position was staked. // // Halt check: reverts while the Withdraw halt scope is active. func UnStakeToken(cur realm, positionId uint64) string { return getImplementation().UnStakeToken(0, cur, positionId) } // CollectReward collects both the GNS emission and external incentive rewards for a live staked // deposit or an exit checkpoint left by UnStakeToken. // // A live-deposit collect requires the depositor/owner. An exit-checkpoint collect is permissionless // and pays the owner pinned in the checkpoint. // // Parameters: // - cur: Current realm context; callers use cross(cur) when crossing into this realm. // - positionId: Staked position NFT token ID or position with an exit checkpoint. // // Returns: // - string: GNS emission amount sent to the user. // - string: GNS emission penalty amount sent to the community pool. // - map[string]int64: Gross external reward amount per reward token, before the staking-reward fee. // - map[string]int64: External penalty amount per reward token. // // Halt check: reverts while the Withdraw halt scope is active. func CollectReward(cur realm, positionId uint64) (string, string, map[string]int64, map[string]int64) { emissionToUser, emissionPenalty, externalRewards, externalPenalties := getImplementation().CollectReward(0, cur, positionId) return emissionToUser, emissionPenalty, cloneStringInt64Map(externalRewards), cloneStringInt64Map(externalPenalties) } // CollectEmissionReward collects only the GNS emission reward for a live staked deposit or an exit // checkpoint left by UnStakeToken. // // A live-deposit collect requires the depositor/owner. An exit-checkpoint collect is permissionless // and pays the owner pinned in the checkpoint. // // External incentive rewards keep accruing; collect them with CollectExternalIncentiveReward. // // Parameters: // - cur: Current realm context; callers use cross(cur) when crossing into this realm. // - positionId: Staked position NFT token ID or position with an exit checkpoint. // // Returns: // - int64: GNS emission amount sent to the user. // - int64: GNS emission penalty amount sent to the community pool. // // Halt check: reverts while the Withdraw halt scope is active. func CollectEmissionReward(cur realm, positionId uint64) (int64, int64) { return getImplementation().CollectEmissionReward(0, cur, positionId) } // CollectExternalIncentiveReward collects one external incentive reward for a live staked deposit // or an exit checkpoint left by UnStakeToken. // // A live-deposit collect requires the depositor/owner. An exit-checkpoint collect is permissionless // and pays the owner pinned in the checkpoint. // // The GNS emission reward and every other incentive keep accruing; collect the emission reward with // CollectEmissionReward and the other incentives by calling this with their own incentive id. // // Parameters: // - cur: Current realm context; callers use cross(cur) when crossing into this realm. // - positionId: Staked position NFT token ID or position with an exit checkpoint. // - incentiveId: External incentive identifier to collect. // // Returns: // - int64: Gross reward amount before the staking-reward fee. // - int64: Penalty amount retained by the incentive. // // Halt check: reverts while the Withdraw halt scope is active. func CollectExternalIncentiveReward(cur realm, positionId uint64, incentiveId string) (int64, int64) { return getImplementation().CollectExternalIncentiveReward(0, cur, positionId, incentiveId) } // SetPoolTier assigns a pool to an internal GNS emission reward tier. // // Parameters: // - cur: Current realm context; callers use cross(cur) when crossing into this realm. // - poolPath: Pool path whose emission tier is assigned. // - tier: Target tier number from 0 through 3; zero removes the pool from emission targeting. // // Halt check: reverts while the Staker halt scope is active. func SetPoolTier(cur realm, poolPath string, tier uint64) { getImplementation().SetPoolTier(0, cur, poolPath, tier) } // ChangePoolTier changes the internal GNS emission tier assigned to a pool. // // Parameters: // - cur: Current realm context; callers use cross(cur) when crossing into this realm. // - poolPath: Pool path whose emission tier is changed. // - tier: New tier number from 0 through 3; zero means no internal-emission target. // // Halt check: reverts while the Staker halt scope is active. func ChangePoolTier(cur realm, poolPath string, tier uint64) { getImplementation().ChangePoolTier(0, cur, poolPath, tier) } // RemovePoolTier removes a pool from the internal GNS emission tier system. // // Parameters: // - cur: Current realm context; callers use cross(cur) when crossing into this realm. // - poolPath: Pool path to remove from emission-tier membership. // // Halt check: reverts while the Staker halt scope is active. func RemovePoolTier(cur realm, poolPath string) { getImplementation().RemovePoolTier(0, cur, poolPath) } // CreateExternalIncentive creates an external reward incentive for a pool. // // Parameters: // - cur: Current realm context; callers use cross(cur) when crossing into this realm. // - targetPoolPath: Pool path whose liquidity providers will receive the incentive. // - rewardToken: Registered token path used to pay the incentive. // - rewardAmount: Total reward amount deposited, in reward-token units. // - startTimestamp: Incentive start time as an inclusive Unix timestamp. // - endTimestamp: Incentive end time as an inclusive Unix timestamp. // // Any caller may create an incentive after satisfying the token, duration, start-time, // reward-minimum, and GNS-deposit checks. // // Halt check: reverts while the Staker halt scope is active. func CreateExternalIncentive( cur realm, targetPoolPath string, rewardToken string, rewardAmount int64, startTimestamp int64, endTimestamp int64, ) { getImplementation().CreateExternalIncentive( 0, cur, targetPoolPath, rewardToken, rewardAmount, startTimestamp, endTimestamp, ) } // EndExternalIncentive finalizes an external incentive once its end timestamp has passed, // sending the unclaimable/remainder reward portion and GNS deposit to the explicit refundAddress. // Only the incentive creator or admin may call it; an outstanding exit checkpoint for this // incentive must be collected or forfeited first. // // Parameters: // - cur: Current realm context; callers use cross(cur) when crossing into this realm. // - targetPoolPath: Pool path containing the incentive. // - incentiveId: Unique incentive identifier to finalize. // - refundAddress: Address receiving the refundable reward tokens and GNS deposit. // // Halt check: reverts while the Withdraw halt scope is active. func EndExternalIncentive(cur realm, targetPoolPath, incentiveId string, refundAddress address) { getImplementation().EndExternalIncentive(0, cur, targetPoolPath, incentiveId, refundAddress) } // CancelExternalIncentive cancels an external incentive that has not started yet, // removing it and refunding the reward tokens and the GNS deposit to the creator. // Callable by admin, governance, or the incentive creator. // // Parameters: // - cur: Current realm context; callers use cross(cur) when crossing into this realm. // - targetPoolPath: Pool path containing the incentive. // - incentiveId: Unique incentive identifier to cancel. // // Halt check: reverts while the Withdraw halt scope is active. func CancelExternalIncentive(cur realm, targetPoolPath, incentiveId string) { getImplementation().CancelExternalIncentive(0, cur, targetPoolPath, incentiveId) } // CollectExternalIncentivePenalty collects accumulated warm-up penalties after // EndExternalIncentive has finalized the incentive, sending them to refundAddress. // Only the incentive creator or admin may call it. // // Parameters: // - cur: Current realm context; callers use cross(cur) when crossing into this realm. // - targetPoolPath: Pool path containing the incentive. // - incentiveId: Unique incentive identifier whose penalty is collected. // - refundAddress: Address receiving the collected penalty amount. // // Returns: // - int64: Penalty amount transferred, capped by the staker's available reward-token balance. // // Halt check: reverts while the Withdraw halt scope is active. func CollectExternalIncentivePenalty(cur realm, targetPoolPath, incentiveId string, refundAddress address) int64 { return getImplementation().CollectExternalIncentivePenalty(0, cur, targetPoolPath, incentiveId, refundAddress) } // AddToken adds a token to the reward token whitelist. // // Parameters: // - cur: Current realm context; callers use cross(cur) when crossing into this realm. // - tokenPath: Registered token path to add to the allowed reward-token list. // // Halt check: reverts while the Staker halt scope is active. func AddToken(cur realm, tokenPath string) { getImplementation().AddToken(0, cur, tokenPath) } // RemoveToken removes a token from the reward token whitelist. // // Parameters: // - cur: Current realm context; callers use cross(cur) when crossing into this realm. // - tokenPath: Token path to remove from the allowed reward-token list. // // Halt check: reverts while the Staker halt scope is active. func RemoveToken(cur realm, tokenPath string) { getImplementation().RemoveToken(0, cur, tokenPath) } // SetDeniedRewardToken sets or clears the operational deny flag for an external // incentive reward token. Pool-pair tokens qualify as reward tokens without the // governance allowlist (by design), so this flag is the only lever to stop NEW // incentives in a pair token whose issuer turned hostile. Existing incentives // and their collection are deliberately unaffected; the ledger-level delivery // guard in the implementation bounds their blast radius instead. // // Parameters: // - cur: Current realm context; callers use cross(cur) when crossing into this realm. // - tokenPath: Reward-token path whose deny status is changed. // - denied: True to block new incentives for tokenPath; false to clear that block. // // Halt check: reverts while the Staker halt scope is active. func SetDeniedRewardToken(cur realm, tokenPath string, denied bool) { getImplementation().SetDeniedRewardToken(0, cur, tokenPath, denied) } // SetWarmUp configures the duration for the warm-up tier selected by its fixed ratio. // Finite tiers are capped at 365 days; the final 100% tier must retain math.MaxInt64. // // Parameters: // - cur: Current realm context; callers use cross(cur) when crossing into this realm. // - pct: Warm-up payout percentage selecting one of the 30%, 50%, 70%, or 100% tiers. // - timeDuration: Warm-up duration in Unix seconds for the selected percentage tier; finite tiers are capped at 365 days and the 100% tier uses math.MaxInt64. // // Halt check: reverts while the Staker halt scope is active. func SetWarmUp(cur realm, pct, timeDuration int64) { getImplementation().SetWarmUp(0, cur, pct, timeDuration) } // SetDepositGnsAmount sets the GNS deposit required for each external incentive. // // Parameters: // - cur: Current realm context; callers use cross(cur) when crossing into this realm. // - amount: GNS amount required as the per-incentive deposit. // // Halt check: reverts while the Staker halt scope is active. func SetDepositGnsAmount(cur realm, amount int64) { getImplementation().SetDepositGnsAmount(0, cur, amount) } // SetMinimumRewardAmount sets the default minimum reward amount required to create an external // incentive. A token-specific override may apply. // // Parameters: // - cur: Current realm context; callers use cross(cur) when crossing into this realm. // - amount: Default minimum reward amount, measured in the reward token's units. // // Halt check: reverts while the Staker halt scope is active. func SetMinimumRewardAmount(cur realm, amount int64) { getImplementation().SetMinimumRewardAmount(0, cur, amount) } // SetTokenMinimumRewardAmount sets minimum reward amounts per token. // // Parameters: // - cur: Current realm context; callers use cross(cur) when crossing into this realm. // - paramsStr: Colon-delimited token path and minimum amount (`tokenPath:amount`); amount zero removes the override. // // Halt check: reverts while the Staker halt scope is active. func SetTokenMinimumRewardAmount(cur realm, paramsStr string) { getImplementation().SetTokenMinimumRewardAmount(0, cur, paramsStr) } // SetUnStakingFee sets the unstaking fee rate in basis points (0-1,000; 100 = 1%). // // Parameters: // - cur: Current realm context; callers use cross(cur) when crossing into this realm. // - fee: Unstaking fee rate in basis points, from 0 through 1,000 inclusive. // // Halt check: reverts while the Staker halt scope is active. func SetUnStakingFee(cur realm, fee uint64) { getImplementation().SetUnStakingFee(0, cur, fee) }
  22. #22render.gno
  23. #23package staker // Render delegates web rendering to the active implementation. func Render(path string) string { return getImplementation().Render(path) }
  24. #24state.gno

Result log

msg:0,success:true,log:,events:[]

← Back to block 77,258