PathrockNetwork Gno Explorer
HomeBlocksTransactionsRealmsPackagesValidatorsAnalytics

PathrockNetwork Gno Explorer — an independent explorer for Gno.land Mainnet (gnoland-1), operated by PathrockNetwork. Not an official Gno.land service.

gnowebarchive RPC

gno.land/r/gnoswap/emission

Realm
Open in gnoweb ↗

Overview

Kind
Realm (renderable)
Name
emission
Namespace
gnoswap
Files
10 (README)(gnomod.toml)
Exported functions
n/a — Gnoland RPC unavailable (functions): rpc abci_query: HTTP 500
Module
gno.land/r/gnoswap/emission
gno
0.9

Files (10)

  • README.mdmarkdown
  • gnomod.tomltoml
  • assert.gnogno
  • distribution.gnogno
  • doc.gnogno
  • emission.gnogno
  • errors.gnogno
  • getter.gnogno
  • render.gnogno
  • utils.gnogno
  • distribution.gnogno
    1package emission23import (4	"chain"5	"time"67	ufmt "gno.land/p/nt/ufmt/v0"8

    Functions

    Gnoland RPC unavailable (functions): rpc abci_query: HTTP 500

    Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.

    Rendered

    RenderedRawgnoweb ↗

    vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.

    9 gnsmath "gno.land/p/gnoswap/gnsmath/v1"
    10 prbac "gno.land/p/gnoswap/rbac/v1"
    11 "gno.land/p/gnoswap/utils/v1"
    12
    13 "gno.land/r/gnoswap/access/v1"
    14 "gno.land/r/gnoswap/gns"
    15 "gno.land/r/gnoswap/halt/v1"
    16)
    17
    18const (
    19 _ int = iota
    20 LIQUIDITY_STAKER
    21 DEVOPS
    22 COMMUNITY_POOL
    23 GOV_STAKER
    24)
    25
    26var (
    27 // Stores the percentage (in basis points) for each distribution target
    28 // 1 basis point = 0.01%
    29 // These percentages can be modified by admin or governance.
    30 distributionBpsPct map[int]int64
    31
    32 distributedToStaker int64 // can be cleared by staker contract
    33 distributedToDevOps int64
    34 distributedToCommunityPool int64
    35 distributedToGovStaker int64 // can be cleared by governance staker
    36
    37 // Historical total distributions (never reset)
    38 accuDistributedToStaker int64
    39 accuDistributedToDevOps int64
    40 accuDistributedToCommunityPool int64
    41 accuDistributedToGovStaker int64
    42)
    43
    44// Initialize default distribution percentages:
    45// - Liquidity Stakers: 75%
    46// - DevOps: 20%
    47// - Community Pool: 5%
    48// - Governance Stakers: 0%
    49//
    50// ref: https://docs.gnoswap.io/gnoswap-token/emission
    51func init() {
    52 distributionBpsPct = map[int]int64{
    53 LIQUIDITY_STAKER: 7500,
    54 DEVOPS: 2000,
    55 COMMUNITY_POOL: 500,
    56 GOV_STAKER: 0,
    57 }
    58}
    59
    60// ChangeDistributionPct changes distribution percentages for emission targets.
    61//
    62// This function redistributes how newly minted GNS tokens are allocated across
    63// protocol components. Before applying new ratios, it distributes any accumulated
    64// emissions using the current ratios, ensuring emissions are distributed according
    65// to the ratios in effect when they were generated. This prevents retroactive
    66// application of new ratios to past emissions.
    67//
    68// Parameters:
    69// - cur: Current realm context; callers use cross(cur) when crossing into this realm.
    70// - liquidityStakerPct: percentage for liquidity stakers in basis points (100 = 1%, 10000 = 100%).
    71// - devOpsPct: percentage for DevOps in basis points (100 = 1%, 10000 = 100%).
    72// - communityPoolPct: percentage for the community pool in basis points (100 = 1%, 10000 = 100%).
    73// - govStakerPct: percentage for governance stakers in basis points (100 = 1%, 10000 = 100%).
    74//
    75// Requirements:
    76// - Percentages must sum to exactly 10000 (100%).
    77// - Each percentage must be between 0 and 10000 inclusive.
    78//
    79// Example:
    80//
    81// ChangeDistributionPct(
    82// 7000, // 70% to liquidity stakers
    83// 2000, // 20% to devops
    84// 1000, // 10% to community pool
    85// 0, // 0% to governance stakers
    86// )
    87//
    88// Only callable by admin or governance.
    89func ChangeDistributionPct(
    90 cur realm,
    91 liquidityStakerPct int64,
    92 devOpsPct int64,
    93 communityPoolPct int64,
    94 govStakerPct int64,
    95) {
    96 halt.AssertIsNotHaltedEmission()
    97
    98 caller := cur.Previous().Address()
    99 access.AssertIsAdminOrGovernance(caller)
    100
    101 assertValidDistributionPct(liquidityStakerPct, devOpsPct, communityPoolPct, govStakerPct)
    102
    103 // Distribute accumulated emissions with current ratios before changing ratios.
    104 // This prevents retroactive application of new ratios to emissions that occurred
    105 // under previous ratio configurations.
    106 MintAndDistributeGns(cur)
    107
    108 currentTimestamp := time.Now().Unix()
    109 stakerRewardPerSecond := GetEmissionAmountPerSecondBy(currentTimestamp, liquidityStakerPct)
    110 govStakerRewardPerSecond := GetEmissionAmountPerSecondBy(currentTimestamp, govStakerPct)
    111
    112 if onDistributionPctChangeCallback != nil {
    113 onDistributionPctChangeCallback(cross(cur), stakerRewardPerSecond)
    114 }
    115
    116 changeDistributionPcts(liquidityStakerPct, devOpsPct, communityPoolPct, govStakerPct)
    117
    118 previousRealm := cur.Previous()
    119 chain.Emit(
    120 "ChangeDistributionPct",
    121 "prevAddr", previousRealm.Address().String(),
    122 "prevRealm", previousRealm.PkgPath(),
    123 "liquidityStakerPct", utils.FormatInt(liquidityStakerPct),
    124 "devOpsPct", utils.FormatInt(devOpsPct),
    125 "communityPoolPct", utils.FormatInt(communityPoolPct),
    126 "govStakerPct", utils.FormatInt(govStakerPct),
    127 "stakerRewardPerSecond", utils.FormatInt(stakerRewardPerSecond),
    128 "govStakerRewardPerSecond", utils.FormatInt(govStakerRewardPerSecond),
    129 )
    130}
    131
    132// changeDistributionPcts updates the distribution percentages for all targets.
    133func changeDistributionPcts(liquidityStakerPct, devOpsPct, communityPoolPct, govStakerPct int64) {
    134 setDistributionBpsPct(LIQUIDITY_STAKER, liquidityStakerPct)
    135 setDistributionBpsPct(DEVOPS, devOpsPct)
    136 setDistributionBpsPct(COMMUNITY_POOL, communityPoolPct)
    137 setDistributionBpsPct(GOV_STAKER, govStakerPct)
    138}
    139
    140func calculateDistributableAmounts(amount int64) (map[int]int64, int64) {
    141 distributable := make(map[int]int64, 0)
    142 totalSent := int64(0)
    143
    144 for target, pct := range distributionBpsPct {
    145 distAmount := calculateAmount(amount, pct)
    146 if distAmount == 0 {
    147 continue
    148 }
    149
    150 distributable[target] = distAmount
    151 totalSent = gnsmath.SafeAddInt64(totalSent, distAmount)
    152 }
    153
    154 leftAmount := gnsmath.SafeSubInt64(amount, totalSent)
    155 return distributable, leftAmount
    156}
    157
    158// calculateAmount converts basis points to actual token amount.
    159func calculateAmount(amount, bptPct int64) int64 {
    160 if amount < 0 || bptPct < 0 || bptPct > 10000 {
    161 panic("invalid amount or bptPct")
    162 }
    163
    164 // More precise overflow prevention
    165 const maxInt64 = 9223372036854775807
    166 if amount > maxInt64/10000 {
    167 panic("amount too large, would cause overflow")
    168 }
    169
    170 // Additional safety check for zero division
    171 if bptPct == 0 {
    172 return 0
    173 }
    174
    175 return amount * bptPct / 10000
    176}
    177
    178func applyDistribution(targets map[int]int64) (map[address]int64, error) {
    179 amountByAddress := make(map[address]int64, 0)
    180
    181 for target, amount := range targets {
    182 var addr address
    183
    184 switch target {
    185 case LIQUIDITY_STAKER:
    186 distributedToStaker = gnsmath.SafeAddInt64(distributedToStaker, amount)
    187 accuDistributedToStaker = gnsmath.SafeAddInt64(accuDistributedToStaker, amount)
    188 addr = access.MustGetAddress(prbac.ROLE_STAKER.String())
    189
    190 case DEVOPS:
    191 distributedToDevOps = gnsmath.SafeAddInt64(distributedToDevOps, amount)
    192 accuDistributedToDevOps = gnsmath.SafeAddInt64(accuDistributedToDevOps, amount)
    193 addr = access.MustGetAddress(prbac.ROLE_DEVOPS.String())
    194
    195 case COMMUNITY_POOL:
    196 distributedToCommunityPool = gnsmath.SafeAddInt64(distributedToCommunityPool, amount)
    197 accuDistributedToCommunityPool = gnsmath.SafeAddInt64(accuDistributedToCommunityPool, amount)
    198 addr = access.MustGetAddress(prbac.ROLE_COMMUNITY_POOL.String())
    199
    200 case GOV_STAKER:
    201 distributedToGovStaker = gnsmath.SafeAddInt64(distributedToGovStaker, amount)
    202 accuDistributedToGovStaker = gnsmath.SafeAddInt64(accuDistributedToGovStaker, amount)
    203 addr = access.MustGetAddress(prbac.ROLE_GOV_STAKER.String())
    204
    205 default:
    206 return nil, makeErrorWithDetails(
    207 errInvalidEmissionTarget,
    208 ufmt.Sprintf("invalid target(%d)", target),
    209 )
    210 }
    211
    212 amountByAddress[addr] = gnsmath.SafeAddInt64(amountByAddress[addr], amount)
    213 }
    214
    215 return amountByAddress, nil
    216}
    217
    218func transferToTarget(_ int, rlm realm, targets map[address]int64) error {
    219 for address, amount := range targets {
    220 gns.Transfer(cross(rlm), address, amount)
    221 }
    222
    223 return nil
    224}
    225
    226// GetDistributionBpsPct returns the configured distribution percentage in basis points for a target.
    227//
    228// Parameters:
    229// - target: distribution target constant whose configured share is queried.
    230//
    231// Returns:
    232// - pct: configured target share in basis points (100 = 1%, 10000 = 100%).
    233// - error: nil when the target exists in the initialized map; otherwise an invalid-target error.
    234func GetDistributionBpsPct(target int) (int64, error) {
    235 if err := validateDistributionTarget(target); err != nil {
    236 return 0, err
    237 }
    238
    239 if distributionBpsPct == nil {
    240 return 0, makeErrorWithDetails(
    241 errInvalidEmissionTarget,
    242 ufmt.Sprintf("distributionBpsPct is nil"),
    243 )
    244 }
    245
    246 pct, exist := distributionBpsPct[target]
    247 if !exist {
    248 return 0, makeErrorWithDetails(
    249 errInvalidEmissionTarget,
    250 ufmt.Sprintf("invalid target(%d)", target),
    251 )
    252 }
    253
    254 return pct, nil
    255}
    256
    257// GetDistributedToStaker returns the pending GNS amount allocated to liquidity stakers.
    258//
    259// Returns:
    260// - amount: pending liquidity-staker allocation in GNS base units since the last clear.
    261func GetDistributedToStaker() int64 {
    262 return distributedToStaker
    263}
    264
    265// GetDistributedToDevOps returns the GNS amount currently accumulated for DevOps.
    266//
    267// Returns:
    268// - amount: accumulated DevOps allocation in GNS base units.
    269func GetDistributedToDevOps() int64 {
    270 return distributedToDevOps
    271}
    272
    273// GetDistributedToCommunityPool returns the GNS amount currently accumulated for the community pool.
    274//
    275// Returns:
    276// - amount: accumulated community-pool allocation in GNS base units.
    277func GetDistributedToCommunityPool() int64 {
    278 return distributedToCommunityPool
    279}
    280
    281// GetDistributedToGovStaker returns the pending GNS amount allocated to governance stakers.
    282//
    283// Returns:
    284// - amount: pending governance-staker allocation in GNS base units since the last clear.
    285func GetDistributedToGovStaker() int64 {
    286 return distributedToGovStaker
    287}
    288
    289// AccumulateDistributedInfo returns the current pending allocation for every distribution target.
    290//
    291// Returns:
    292// - toStaker: pending GNS allocation for liquidity stakers, in token base units.
    293// - toDevOps: accumulated GNS allocation for DevOps, in token base units.
    294// - toCommunityPool: accumulated GNS allocation for the community pool, in token base units.
    295// - toGovStaker: pending GNS allocation for governance stakers, in token base units.
    296func AccumulateDistributedInfo() (toStaker, toDevOps, toCommunityPool, toGovStaker int64) {
    297 toStaker = GetDistributedToStaker()
    298 toDevOps = GetDistributedToDevOps()
    299 toCommunityPool = GetDistributedToCommunityPool()
    300 toGovStaker = GetDistributedToGovStaker()
    301 return
    302}
    303
    304// GetAccuDistributedToStaker returns the total historical GNS amount allocated to liquidity stakers.
    305//
    306// Returns:
    307// - amount: cumulative liquidity-staker allocation in GNS base units; this value is not cleared.
    308func GetAccuDistributedToStaker() int64 {
    309 return accuDistributedToStaker
    310}
    311
    312// GetAccuDistributedToDevOps returns the total historical GNS amount allocated to DevOps.
    313//
    314// Returns:
    315// - amount: cumulative DevOps allocation in GNS base units; this value is not cleared.
    316func GetAccuDistributedToDevOps() int64 {
    317 return accuDistributedToDevOps
    318}
    319
    320// GetAccuDistributedToCommunityPool returns the total historical GNS amount allocated to the community pool.
    321//
    322// Returns:
    323// - amount: cumulative community-pool allocation in GNS base units; this value is not cleared.
    324func GetAccuDistributedToCommunityPool() int64 {
    325 return accuDistributedToCommunityPool
    326}
    327
    328// GetAccuDistributedToGovStaker returns the total historical GNS amount allocated to governance stakers.
    329//
    330// Returns:
    331// - amount: cumulative governance-staker allocation in GNS base units; this value is not cleared.
    332func GetAccuDistributedToGovStaker() int64 {
    333 return accuDistributedToGovStaker
    334}
    335
    336// GetEmissionAmountPerSecondBy returns the GNS emission rate per second for a timestamp and target share.
    337//
    338// Parameters:
    339// - timestamp: Unix timestamp at which the base emission rate is queried.
    340// - distributionPct: target share in basis points, from 0 through 10000 inclusive.
    341//
    342// Returns:
    343// - amountPerSecond: target's GNS emission rate in token base units per second, or zero outside the schedule.
    344func GetEmissionAmountPerSecondBy(timestamp, distributionPct int64) int64 {
    345 return calculateAmount(gns.GetEmissionAmountPerSecondByTimestamp(timestamp), distributionPct)
    346}
    347
    348// GetStakerEmissionAmountPerSecond returns the current GNS emission rate allocated to liquidity stakers.
    349//
    350// Returns:
    351// - amountPerSecond: current liquidity-staker emission rate in GNS base units per second.
    352// - error: nil when the liquidity-staker distribution share is available; otherwise the target lookup error.
    353func GetStakerEmissionAmountPerSecond() (int64, error) {
    354 currentTimestamp := time.Now().Unix()
    355 pct, err := GetDistributionBpsPct(LIQUIDITY_STAKER)
    356 if err != nil {
    357 return 0, err
    358 }
    359 return GetEmissionAmountPerSecondBy(currentTimestamp, pct), nil
    360}
    361
    362// GetStakerEmissionAmountPerSecondInRange returns liquidity-staker emission-rate change points in a time range.
    363//
    364// Parameters:
    365// - start: inclusive start Unix timestamp for the range.
    366// - end: inclusive end Unix timestamp for the range.
    367//
    368// Returns:
    369// - timestamps: ordered timestamps in the range where the base emission rate changes.
    370// - amountsPerSecond: liquidity-staker GNS rates corresponding to timestamps, in token base units per second.
    371// - error: nil when the liquidity-staker distribution share is available; otherwise the target lookup error.
    372func GetStakerEmissionAmountPerSecondInRange(start, end int64) ([]int64, []int64, error) {
    373 gnsHalvingBlocks, gnsHalvingEmissions := gns.GetEmissionAmountPerSecondInRange(start, end)
    374 halvingBlocks := make([]int64, len(gnsHalvingBlocks))
    375 halvingEmissions := make([]int64, len(gnsHalvingEmissions))
    376
    377 pct, err := GetDistributionBpsPct(LIQUIDITY_STAKER)
    378 if err != nil {
    379 return nil, nil, err
    380 }
    381
    382 for i := range halvingBlocks {
    383 halvingBlocks[i] = gnsHalvingBlocks[i]
    384 // Applying staker ratio for past halving blocks
    385 halvingEmissions[i] = calculateAmount(gnsHalvingEmissions[i], pct)
    386 }
    387
    388 return halvingBlocks, halvingEmissions, nil
    389}
    390
    391// ClearDistributedToStaker resets the pending distribution amount for liquidity stakers.
    392//
    393// Parameters:
    394// - cur: Current realm context; callers use cross(cur) when crossing into this realm.
    395//
    396// Only callable by staker contract.
    397func ClearDistributedToStaker(cur realm) {
    398 caller := cur.Previous().Address()
    399 access.AssertIsStaker(caller)
    400
    401 distributedToStaker = 0
    402}
    403
    404// ClearDistributedToGovStaker resets the pending distribution amount for governance stakers.
    405//
    406// Parameters:
    407// - cur: Current realm context; callers use cross(cur) when crossing into this realm.
    408//
    409// Only callable by governance staker contract.
    410func ClearDistributedToGovStaker(cur realm) {
    411 caller := cur.Previous().Address()
    412 access.AssertIsGovStaker(caller)
    413 distributedToGovStaker = 0
    414}
    415
    416// setDistributionBpsPct changes percentage of each target for how much GNS it will get by emission.
    417// Creates new map if nil.
    418func setDistributionBpsPct(target int, pct int64) {
    419 if distributionBpsPct == nil {
    420 distributionBpsPct = make(map[int]int64)
    421 }
    422
    423 distributionBpsPct[target] = pct
    424}
    425
    426// targetToStr converts target constant to string representation.
    427func targetToStr(target int) string {
    428 switch target {
    429 case LIQUIDITY_STAKER:
    430 return "LIQUIDITY_STAKER"
    431 case DEVOPS:
    432 return "DEVOPS"
    433 case COMMUNITY_POOL:
    434 return "COMMUNITY_POOL"
    435 case GOV_STAKER:
    436 return "GOV_STAKER"
    437 default:
    438 return "UNKNOWN"
    439 }
    440}
    441