# 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.
## Configuration
- **Deposit GNS Amount**: 1,000 GNS for external incentives (default)
- **Minimum Reward Amount**: 1,000 tokens (default)
- **Unstaking Fee**: 1% (default)
- **Pool Tiers**: 1, 2, or 3 (assigned per pool)
- **Warmup Schedule**: 30/50/70/100% over 30/60/90 days
- **External Token Whitelist**: Approved reward tokens
## 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 block
- Proportional to staked liquidity
- Unclaimed rewards returned to creator
### Warmup Periods
Every staked position progresses through warmup periods:
- 0-30 days: 30% rewards (70% to community/creator)
- 30-60 days: 50% rewards (50% to community/creator)
- 60-90 days: 70% rewards (30% to community/creator)
- 90+ days: 100% rewards
## Key Functions
### `StakeToken`
Stakes LP position NFT to earn rewards.
### `UnStakeToken`
Unstakes position and collects all rewards.
### `CollectReward`
Collects accumulated rewards without unstaking.
### `CreateExternalIncentive`
Creates external reward program for specific pool.
### `EndExternalIncentive`
Ends incentive program and returns unused rewards.
## 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) =
[1, 0, 0] if Count(2) = 0 ∧ Count(3) = 0
[0.8, 0, 0.2] if Count(2) = 0
[0.7, 0.3, 0] if Count(3) = 0
[0.5, 0.3, 0.2] otherwise
```
### Pool Reward Formula
```math
poolReward(pool) = (emission × TierRatio[tier(pool)]) / Count(tier(pool))
```
Where emission is calculated as:
```math
emission = GNSEmissionPerSecond × (avgMsPerBlock/1000) × StakerEmissionRatio
```
### Position Reward Calculation
The reward for each position is calculated through:
1. **Cache pool rewards** up to current block
2. **Retrieve position state** from deposit records
3. **Calculate internal rewards** if pool is tiered
4. **Calculate external rewards** for active incentives
5. **Apply warmup penalties** based on stake duration
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
## Usage
```go
// Stake existing position
StakeToken(123, "g1referrer...")
// Create external incentive
CreateExternalIncentive(
"gno.land/r/demo/bar:gno.land/r/demo/baz:3000",
"gno.land/r/demo/reward",
"1000000000", // 1000 tokens
startTime,
endTime,
)
// Collect rewards without unstaking
CollectReward(123)
// Unstake and collect all rewards
UnStakeToken(123)
```
## Security
- Positions locked during staking
- External incentives require GNS deposit
- Warmup periods prevent gaming
- Unclaimed rewards properly redirected
- Hook integration ensures accurate tracking