PathrockNetwork Gno Explorer
HomeBlocksTransactionsTokensRealmsPackagesValidatorsAnalytics

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

gnowebarchive RPC

gno.land/r/gnoswap/gov/staker/v1

Realm
Open in gnoweb ↗

Overview

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

Files (25)

  • README.mdmarkdown
  • gnomod.tomltoml
  • assert.gnogno
  • consts.gnogno
  • delegation_manager.gnogno
  • delegation_withdraw.gnogno
  • delegation.gnogno
  • doc.gnogno
  • emission_reward_manager.gnogno
  • emission_reward_state.gnogno
  • emits.gnogno
  • errors.gnogno
  • getter_utils.gnogno
  • getter.gnogno
  • init.gnogno
  • instance.gnogno
  • launchpad_project_deposits.gnogno
  • protocol_fee_reward_manager.gnogno
  • protocol_fee_reward_state.gnogno
  • render.gnogno
  • staker_delegate.gnogno
  • staker_delegation_snapshot.gnogno
  • staker_reward.gnogno
  • state.gnogno
  • util.gnogno
  • staker_reward.gnogno
    1package staker23import (4	"chain"5	"time"67	prbac "gno.land/p/gnoswap/rbac/v1"8

    Functions

    • NewDelegation(id int64, delegateFrom string, delegateTo string, delegateAmount int64, createdHeight int64, createdAt int64) *gno.land/r/gnoswap/gov/staker.Delegation

    • NewDelegationManagerResolver(delegationManager *gno.land/r/gnoswap/gov/staker.DelegationManager) *gno.land/r/gnoswap/gov/staker/v1.DelegationManagerResolver

    • NewDelegationResolver(delegation *gno.land/r/gnoswap/gov/staker.Delegation) *gno.land/r/gnoswap/gov/staker/v1.DelegationResolver

    • NewDelegationWithdraw(delegationID int64, unDelegateAmount int64, createdHeight int64, createdAt int64, unDelegationLockupPeriod int64) struct{delegationID int64; unDelegateAmount int64; unDelegatedHeight int64; unDelegatedAt int64; collectedAmount int64; collectableTime int64; collectedAt int64; collected bool}

    • NewDelegationWithdrawResolver(withdraw *gno.land/r/gnoswap/gov/staker.DelegationWithdraw) *gno.land/r/gnoswap/gov/staker/v1.DelegationWithdrawResolver

    • NewDelegationWithdrawWithoutLockup(delegationID int64, unDelegateAmount int64, createdHeight int64, createdAt int64) struct{delegationID int64; unDelegateAmount int64; unDelegatedHeight int64; unDelegatedAt int64; collectedAmount int64; collectableTime int64; collectedAt int64; collected bool}

    • NewEmissionRewardManagerResolver(emissionRewardManager *gno.land/r/gnoswap/gov/staker.EmissionRewardManager) *gno.land/r/gnoswap/gov/staker/v1.EmissionRewardManagerResolver

    • NewEmissionRewardStateResolver(emissionRewardState *gno.land/r/gnoswap/gov/staker.EmissionRewardState) *gno.land/r/gnoswap/gov/staker/v1.EmissionRewardStateResolver

    • NewGovStakerV1(store interface {GetAllDelegations func() *gno.land/p/nt/bptree/v0.BPTree; GetDelegation func(int64) (*gno.land/r/gnoswap/gov/staker.Delegation, bool); GetDelegationCounter func() *gno.land/r/gnoswap/gov/staker.Counter; GetDelegationManager func() *gno.land/r/gnoswap/gov/staker.DelegationManager; GetEmissionRewardManager func() *gno.land/r/gnoswap/gov/staker.EmissionRewardManager; GetLaunchpadProjectDeposits func() *gno.land/r/gnoswap/gov/staker.LaunchpadProjectDeposits; GetProtocolFeeRewardManager func() *gno.land/r/gnoswap/gov/staker.ProtocolFeeRewardManager; GetTotalDelegatedAmount func() int64; GetTotalDelegationHistory func() *gno.land/r/gnoswap/gov/staker.UintTree; GetTotalLockedAmount func() int64; GetUnDelegationLockupPeriod func() int64; GetUserDelegationHistory func() *gno.land/p/nt/bptree/v0.BPTree; HasDelegation func(int64) bool; HasDelegationCounterStoreKey func() bool; HasDelegationManagerStoreKey func() bool; HasDelegationsStoreKey func() bool; HasEmissionRewardManagerStoreKey func() bool; HasLaunchpadProjectDepositsStoreKey func() bool; HasProtocolFeeRewardManagerStoreKey func() bool; HasTotalDelegatedAmountStoreKey func() bool; HasTotalDelegationHistoryStoreKey func() bool; HasTotalLockedAmountStoreKey func() bool; HasUnDelegationLockupPeriodStoreKey func() bool; HasUserDelegationHistoryStoreKey func() bool; RemoveDelegation func(int, .uverse.realm, int64) .uverse.error; SetDelegation func(int, .uverse.realm, int64, *gno.land/r/gnoswap/gov/staker.Delegation) .uverse.error; SetDelegationCounter func(int, .uverse.realm, *gno.land/r/gnoswap/gov/staker.Counter) .uverse.error; SetDelegationManager func(int, .uverse.realm, *gno.land/r/gnoswap/gov/staker.DelegationManager) .uverse.error; SetDelegations func(int, .uverse.realm, *gno.land/p/nt/bptree/v0.BPTree) .uverse.error; SetEmissionRewardManager func(int, .uverse.realm, *gno.land/r/gnoswap/gov/staker.EmissionRewardManager) .uverse.error; SetLaunchpadProjectDeposits func(int, .uverse.realm, *gno.land/r/gnoswap/gov/staker.LaunchpadProjectDeposits) .uverse.error; SetProtocolFeeRewardManager func(int, .uverse.realm, *gno.land/r/gnoswap/gov/staker.ProtocolFeeRewardManager) .uverse.error; SetTotalDelegatedAmount func(int, .uverse.realm, int64) .uverse.error; SetTotalDelegationHistory func(int, .uverse.realm, *gno.land/r/gnoswap/gov/staker.UintTree) .uverse.error; SetTotalLockedAmount func(int, .uverse.realm, int64) .uverse.error; SetUnDelegationLockupPeriod func(int, .uverse.realm, int64) .uverse.error; SetUserDelegationHistory func(int, .uverse.realm, *gno.land/p/nt/bptree/v0.BPTree) .uverse.error}) interface {CleanStakerDelegationSnapshotByAdmin func(int, .uverse.realm, int64, .uverse.address); CollectEmissionReward func(int, .uverse.realm); CollectEmissionRewardFromLaunchPad func(int, .uverse.realm, .uverse.address); CollectProtocolFeeReward func(int, .uverse.realm, string); CollectProtocolFeeRewardFromLaunchPad func(int, .uverse.realm, .uverse.address, string); CollectReward func(int, .uverse.realm); CollectRewardFromLaunchPad func(int, .uverse.realm, .uverse.address); CollectUndelegatedGns func(int, .uverse.realm) int64; Delegate func(int, .uverse.realm, .uverse.address, int64, string) int64; ExistsDelegation func(int64) bool; GetClaimableRewardByAddress func(.uverse.address) (int64, map[string]int64, .uverse.error); GetClaimableRewardByLaunchpad func(.uverse.address) (int64, map[string]int64, .uverse.error); GetClaimableRewardByRewardID func(string) (int64, map[string]int64, .uverse.error); GetCollectableWithdrawAmount func(int64) int64; GetDelegationWithdrawCount func(int64) int; GetDelegationWithdraws func(int64, int, int) ([]gno.land/r/gnoswap/gov/staker.DelegationWithdraw, .uverse.error); GetDelegations func() *gno.land/p/nt/bptree/rotree/v0.ReadOnlyTree; GetDelegatorDelegations func(.uverse.address) *gno.land/p/nt/bptree/rotree/v0.ReadOnlyTree; GetEmissionAccumulatedTimestamp func() int64; GetEmissionAccumulatedX128PerStake func() *gno.land/p/gnoswap/uint256/v1.Uint; GetEmissionDistributedAmount func() int64; GetLaunchpadProjectDeposit func(string) (int64, bool); GetProtocolFeeAccumulatedTimestamp func() int64; GetProtocolFeeAccumulatedX128PerStake func(string) *gno.land/p/gnoswap/uint256/v1.Uint; GetProtocolFeeAmount func(string) int64; GetTotalDelegated func() int64; GetTotalDelegationAmountAtSnapshot func(int64) (int64, bool); GetTotalLockedAmount func() int64; GetTotalxGnsSupply func() int64; GetUnDelegationLockupPeriod func() int64; GetUserDelegationAmountAtSnapshot func(.uverse.address, int64) (int64, bool); GetUserDelegationIDs func(.uverse.address, .uverse.address) []int64; HasDelegationSnapshotsKey func() bool; Redelegate func(int, .uverse.realm, .uverse.address, .uverse.address, int64) int64; Render func(string) string; SetAmountByProjectWallet func(int, .uverse.realm, .uverse.address, int64, bool); SetUnDelegationLockupPeriodByAdmin func(int, .uverse.realm, int64); Undelegate func(int, .uverse.realm, .uverse.address, int64) int64}

    • NewLaunchpadProjectDepositsResolver(launchpadProjectDeposits *gno.land/r/gnoswap/gov/staker.LaunchpadProjectDeposits) *gno.land/r/gnoswap/gov/staker/v1.LaunchpadProjectDepositsResolver

    • NewProtocolFeeRewardManagerResolver(manager *gno.land/r/gnoswap/gov/staker.ProtocolFeeRewardManager) *gno.land/r/gnoswap/gov/staker/v1.ProtocolFeeRewardManagerResolver

    • NewProtocolFeeRewardStateResolver(protocolFeeRewardState *gno.land/r/gnoswap/gov/staker.ProtocolFeeRewardState) *gno.land/r/gnoswap/gov/staker/v1.ProtocolFeeRewardStateResolver

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

    Rendered

    RenderedRawgnoweb ↗
    This realm does not provide renderable output (vm/qrender → NoRenderDeclError). View on gnoweb ↗

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

    "gno.land/p/gnoswap/utils/v1"
    9 ufmt "gno.land/p/nt/ufmt/v0"
    10
    11 "gno.land/r/gnoswap/access/v1"
    12 "gno.land/r/gnoswap/common"
    13 "gno.land/r/gnoswap/gns"
    14 "gno.land/r/gnoswap/gov/xgns"
    15 "gno.land/r/gnoswap/halt/v1"
    16)
    17
    18// CollectReward claims all rewards for the caller.
    19//
    20// It settles both reward streams:
    21// 1. GNS emission rewards from the emission accumulator.
    22// 2. Protocol-fee rewards for every known token path.
    23//
    24// Protocol-fee rewards are divided by the total stake in force for each
    25// accrual epoch and settled across the caller's stake-event segments. They
    26// are not calculated from one current xGNS/total-xGNS ratio. Q128 fractional
    27// remainders remain in state for later collection.
    28//
    29// The all-token path intentionally grows with the number of known fee tokens.
    30// Use the token-specific entry point when bounded work is required.
    31//
    32// No business parameters are required; the caller's reward ID is used.
    33// Rewards are transferred directly to the caller.
    34//
    35// Parameters:
    36// - _: Noncrossing implementation-call discriminator; pass 0.
    37// - rlm: Current realm context forwarded by the governance-staker proxy; validated before settlement and transfers.
    38func (gs *govStakerV1) CollectReward(_ int, rlm realm) {
    39 access.AssertIsRlmCurrent(0, rlm)
    40
    41 halt.AssertIsNotHaltedWithdraw()
    42
    43 prev := rlm.Previous()
    44 caller := prev.Address()
    45 from := rlm.Address()
    46 currentTimestamp := time.Now().Unix()
    47
    48 emissionReward, protocolFeeRewards, err := gs.claimRewards(0, rlm, caller.String(), currentTimestamp)
    49 if err != nil {
    50 panic(err)
    51 }
    52
    53 // Transfer emission rewards (GNS tokens) if any
    54 if emissionReward > 0 {
    55 gns.Transfer(cross(rlm), caller, emissionReward)
    56
    57 chain.Emit(
    58 "CollectEmissionReward",
    59 "prevAddr", prev.Address().String(),
    60 "prevRealm", prev.PkgPath(),
    61 "from", from.String(),
    62 "to", caller.String(),
    63 "emissionRewardAmount", utils.FormatInt(emissionReward),
    64 )
    65 }
    66
    67 // Transfer protocol fee rewards for each token type
    68 for tokenPath, amount := range protocolFeeRewards {
    69 if amount > 0 {
    70 err := transferToken(0, rlm, tokenPath, from, caller, amount)
    71 if err != nil {
    72 panic(err)
    73 }
    74
    75 chain.Emit(
    76 "CollectProtocolFeeReward",
    77 "prevAddr", prev.Address().String(),
    78 "prevRealm", prev.PkgPath(),
    79 "tokenPath", tokenPath,
    80 "from", from.String(),
    81 "to", caller.String(),
    82 "collectedAmount", utils.FormatInt(amount),
    83 )
    84 }
    85 }
    86}
    87
    88// CollectEmissionReward collects accumulated GNS emission rewards only.
    89//
    90// Parameters:
    91// - _: Noncrossing implementation-call discriminator; pass 0.
    92// - rlm: Current realm context forwarded by the governance-staker proxy; validated before settlement and transfer.
    93func (gs *govStakerV1) CollectEmissionReward(_ int, rlm realm) {
    94 access.AssertIsRlmCurrent(0, rlm)
    95
    96 halt.AssertIsNotHaltedWithdraw()
    97
    98 prev := rlm.Previous()
    99 caller := prev.Address()
    100 from := rlm.Address()
    101 currentTimestamp := time.Now().Unix()
    102
    103 emissionReward, err := gs.claimRewardsEmissionReward(0, rlm, caller.String(), currentTimestamp)
    104 if err != nil {
    105 panic(err)
    106 }
    107
    108 if emissionReward > 0 {
    109 gns.Transfer(cross(rlm), caller, emissionReward)
    110
    111 chain.Emit(
    112 "CollectEmissionReward",
    113 "prevAddr", prev.Address().String(),
    114 "prevRealm", prev.PkgPath(),
    115 "from", from.String(),
    116 "to", caller.String(),
    117 "emissionRewardAmount", utils.FormatInt(emissionReward),
    118 )
    119 }
    120}
    121
    122// CollectProtocolFeeReward collects accumulated protocol fee rewards for the provided token path.
    123//
    124// Parameters:
    125// - _: Noncrossing implementation-call discriminator; pass 0.
    126// - rlm: Current realm context forwarded by the governance-staker proxy; validated before settlement and transfer.
    127// - tokenPath: registered fee-token path whose reward should be collected
    128func (gs *govStakerV1) CollectProtocolFeeReward(_ int, rlm realm, tokenPath string) {
    129 access.AssertIsRlmCurrent(0, rlm)
    130
    131 halt.AssertIsNotHaltedWithdraw()
    132
    133 prev := rlm.Previous()
    134 caller := prev.Address()
    135 from := rlm.Address()
    136 currentTimestamp := time.Now().Unix()
    137
    138 amount, err := gs.claimRewardProtocolFeeRewardByTokenPath(0, rlm, caller.String(), tokenPath, currentTimestamp)
    139 if err != nil {
    140 panic(err)
    141 }
    142
    143 if amount > 0 {
    144 err := transferToken(0, rlm, tokenPath, from, caller, amount)
    145 if err != nil {
    146 panic(err)
    147 }
    148
    149 chain.Emit(
    150 "CollectProtocolFeeReward",
    151 "prevAddr", prev.Address().String(),
    152 "prevRealm", prev.PkgPath(),
    153 "tokenPath", tokenPath,
    154 "from", from.String(),
    155 "to", caller.String(),
    156 "collectedAmount", utils.FormatInt(amount),
    157 )
    158 }
    159}
    160
    161// CollectRewardFromLaunchPad collects rewards for launchpad project wallets.
    162//
    163// Parameters:
    164// - _: Noncrossing implementation-call discriminator; pass 0.
    165// - rlm: Current realm context forwarded by the governance-staker proxy; validated before launchpad reward settlement.
    166// - to: project wallet address receiving its emission and protocol-fee rewards
    167//
    168// Only callable by launchpad contract.
    169func (gs *govStakerV1) CollectRewardFromLaunchPad(_ int, rlm realm, to address) {
    170 access.AssertIsRlmCurrent(0, rlm)
    171
    172 halt.AssertIsNotHaltedWithdraw()
    173
    174 prev := rlm.Previous()
    175 caller := prev.Address()
    176 access.AssertIsLaunchpad(caller)
    177
    178 from := rlm.Address()
    179 currentTimestamp := time.Now().Unix()
    180
    181 launchpadRewardID := gs.makeLaunchpadRewardID(to.String())
    182 _, exists := gs.getLaunchpadProjectDeposit(launchpadRewardID)
    183 if !exists {
    184 panic(makeErrorWithDetails(
    185 errNoDelegatedAmount,
    186 ufmt.Sprintf("%s is not project wallet from launchpad", to.String()),
    187 ))
    188 }
    189
    190 emissionReward, protocolFeeRewards, err := gs.claimRewardsFromLaunchpad(0, rlm, to.String(), currentTimestamp)
    191 if err != nil {
    192 panic(err)
    193 }
    194
    195 // Transfer emission rewards (GNS tokens) to project wallet if any
    196 if emissionReward > 0 {
    197 gns.Transfer(cross(rlm), to, emissionReward)
    198
    199 chain.Emit(
    200 "CollectEmissionFromLaunchPad",
    201 "prevAddr", prev.Address().String(),
    202 "prevRealm", prev.PkgPath(),
    203 "from", from.String(),
    204 "to", to.String(),
    205 "emissionRewardAmount", utils.FormatInt(emissionReward),
    206 )
    207 }
    208
    209 // Transfer protocol fee rewards to project wallet for each token type
    210 for tokenPath, amount := range protocolFeeRewards {
    211 if amount > 0 {
    212 err := transferToken(0, rlm, tokenPath, from, to, amount)
    213 if err != nil {
    214 panic(err)
    215 }
    216
    217 chain.Emit(
    218 "CollectProtocolFeeFromLaunchPad",
    219 "prevAddr", prev.Address().String(),
    220 "prevRealm", prev.PkgPath(),
    221 "tokenPath", tokenPath,
    222 "from", from.String(),
    223 "to", to.String(),
    224 "collectedAmount", utils.FormatInt(amount),
    225 )
    226 }
    227 }
    228}
    229
    230// CollectEmissionRewardFromLaunchPad collects emission rewards only for launchpad project wallets.
    231//
    232// Parameters:
    233// - _: Noncrossing implementation-call discriminator; pass 0.
    234// - rlm: Current realm context forwarded by the governance-staker proxy; validated before launchpad reward settlement.
    235// - to: project wallet address receiving its emission reward
    236func (gs *govStakerV1) CollectEmissionRewardFromLaunchPad(_ int, rlm realm, to address) {
    237 access.AssertIsRlmCurrent(0, rlm)
    238
    239 halt.AssertIsNotHaltedWithdraw()
    240
    241 prev := rlm.Previous()
    242 caller := prev.Address()
    243 access.AssertIsLaunchpad(caller)
    244
    245 from := rlm.Address()
    246 currentTimestamp := time.Now().Unix()
    247
    248 launchpadRewardID := gs.makeLaunchpadRewardID(to.String())
    249 _, exists := gs.getLaunchpadProjectDeposit(launchpadRewardID)
    250 if !exists {
    251 panic(makeErrorWithDetails(
    252 errNoDelegatedAmount,
    253 ufmt.Sprintf("%s is not project wallet from launchpad", to.String()),
    254 ))
    255 }
    256
    257 emissionReward, err := gs.claimRewardsEmissionReward(0, rlm, launchpadRewardID, currentTimestamp)
    258 if err != nil {
    259 panic(err)
    260 }
    261
    262 if emissionReward > 0 {
    263 gns.Transfer(cross(rlm), to, emissionReward)
    264
    265 chain.Emit(
    266 "CollectEmissionFromLaunchPad",
    267 "prevAddr", prev.Address().String(),
    268 "prevRealm", prev.PkgPath(),
    269 "from", from.String(),
    270 "to", to.String(),
    271 "emissionRewardAmount", utils.FormatInt(emissionReward),
    272 )
    273 }
    274}
    275
    276// CollectProtocolFeeRewardFromLaunchPad collects one token path of protocol fee rewards for launchpad project wallets.
    277//
    278// Parameters:
    279// - _: Noncrossing implementation-call discriminator; pass 0.
    280// - rlm: Current realm context forwarded by the governance-staker proxy; validated before launchpad reward settlement.
    281// - to: project wallet address receiving the protocol-fee reward
    282// - tokenPath: registered fee-token path whose reward should be collected
    283func (gs *govStakerV1) CollectProtocolFeeRewardFromLaunchPad(_ int, rlm realm, to address, tokenPath string) {
    284 access.AssertIsRlmCurrent(0, rlm)
    285
    286 halt.AssertIsNotHaltedWithdraw()
    287
    288 prev := rlm.Previous()
    289 caller := prev.Address()
    290 access.AssertIsLaunchpad(caller)
    291
    292 from := rlm.Address()
    293 currentTimestamp := time.Now().Unix()
    294
    295 launchpadRewardID := gs.makeLaunchpadRewardID(to.String())
    296 _, exists := gs.getLaunchpadProjectDeposit(launchpadRewardID)
    297 if !exists {
    298 panic(makeErrorWithDetails(
    299 errNoDelegatedAmount,
    300 ufmt.Sprintf("%s is not project wallet from launchpad", to.String()),
    301 ))
    302 }
    303
    304 amount, err := gs.claimRewardProtocolFeeRewardByTokenPath(0, rlm, launchpadRewardID, tokenPath, currentTimestamp)
    305 if err != nil {
    306 panic(err)
    307 }
    308
    309 if amount > 0 {
    310 err := transferToken(0, rlm, tokenPath, from, to, amount)
    311 if err != nil {
    312 panic(err)
    313 }
    314
    315 chain.Emit(
    316 "CollectProtocolFeeFromLaunchPad",
    317 "prevAddr", prev.Address().String(),
    318 "prevRealm", prev.PkgPath(),
    319 "tokenPath", tokenPath,
    320 "from", from.String(),
    321 "to", to.String(),
    322 "collectedAmount", utils.FormatInt(amount),
    323 )
    324 }
    325}
    326
    327// SetAmountByProjectWallet sets the amount of reward stake for the project wallet.
    328// This function is exclusively callable by the launchpad contract to manage
    329// xGNS balances for project wallets that participate in launchpad offerings.
    330//
    331// The function handles both adding and removing stakes:
    332// - When adding: mints xGNS to launchpad address and starts reward accumulation
    333// - When removing: burns xGNS from launchpad address and stops reward accumulation
    334// Adjusts stake amount for project wallet address.
    335//
    336// Parameters:
    337// - _: Noncrossing implementation-call discriminator; pass 0.
    338// - rlm: Current realm context forwarded by the governance-staker proxy; validated before launchpad authorization and staking changes.
    339// - addr: project wallet address whose launchpad-backed stake should be adjusted
    340// - amount: amount of stake to add or remove
    341// - add: true to add stake and mint xGNS to launchpad, false to remove stake and burn xGNS from launchpad
    342//
    343// Panics:
    344// - if caller is not the launchpad contract
    345// - if system is halted for withdrawals
    346// - if access control operations fail
    347func (gs *govStakerV1) SetAmountByProjectWallet(_ int, rlm realm, addr address, amount int64, add bool) {
    348 access.AssertIsRlmCurrent(0, rlm)
    349
    350 if add {
    351 halt.AssertIsNotHaltedGovStaker()
    352 } else {
    353 halt.AssertIsNotHaltedWithdraw()
    354 }
    355
    356 prev := rlm.Previous()
    357 caller := prev.Address()
    358 currentTimestamp := time.Now().Unix()
    359
    360 access.AssertIsLaunchpad(caller)
    361
    362 launchpadAddr := access.MustGetAddress(prbac.ROLE_LAUNCHPAD.String())
    363
    364 if add {
    365 // Add stake for the project wallet and mint xGNS to launchpad
    366 err := gs.addStakeFromLaunchpad(0, rlm, addr.String(), amount, currentTimestamp)
    367 if err != nil {
    368 panic(err)
    369 }
    370
    371 xgns.Mint(cross(rlm), launchpadAddr, amount)
    372 } else {
    373 // Remove stake for the project wallet and burn xGNS from launchpad
    374 err := gs.removeStakeFromLaunchpad(0, rlm, addr.String(), amount, currentTimestamp)
    375 if err != nil {
    376 panic(err)
    377 }
    378
    379 xgns.Burn(cross(rlm), launchpadAddr, amount)
    380 }
    381}
    382
    383// claimRewards claims both emission and protocol fee rewards.
    384// Coordinates claiming process for both reward types.
    385func (gs *govStakerV1) claimRewards(_ int, rlm realm, rewardID string, currentTimestamp int64) (int64, map[string]int64, error) {
    386 emissionReward, err := gs.claimRewardsEmissionReward(0, rlm, rewardID, currentTimestamp)
    387 if err != nil {
    388 return 0, nil, err
    389 }
    390
    391 protocolFeeRewards, err := gs.claimRewardsProtocolFeeReward(0, rlm, rewardID, currentTimestamp)
    392 if err != nil {
    393 return 0, nil, err
    394 }
    395
    396 return emissionReward, protocolFeeRewards, nil
    397}
    398
    399// claimRewardsFromLaunchpad claims rewards for launchpad project wallets.
    400// Uses special reward ID format for launchpad integration.
    401func (gs *govStakerV1) claimRewardsFromLaunchpad(_ int, rlm realm, address string, currentTimestamp int64) (int64, map[string]int64, error) {
    402 launchpadRewardID := gs.makeLaunchpadRewardID(address)
    403
    404 return gs.claimRewards(0, rlm, launchpadRewardID, currentTimestamp)
    405}
    406
    407// transferToken transfers tokens from the staker contract to a recipient address.
    408// transferToken handles token transfers for reward distribution.
    409//
    410// Non-crossing helper: takes `_ int, rlm realm` so the realm token threaded
    411// in by the public reward-collection entry points reaches the underlying
    412// GRC-20 transfer without forcing each caller to recompute it.
    413func transferToken(
    414 _ int,
    415 rlm realm,
    416 tokenPath string,
    417 from, to address,
    418 amount int64,
    419) error {
    420 common.MustRegistered(tokenPath)
    421
    422 // Validate recipient address
    423 if !to.IsValid() {
    424 return makeErrorWithDetails(
    425 errInvalidAddress,
    426 ufmt.Sprintf("invalid address %s to transfer protocol fee", to.String()),
    427 )
    428 }
    429
    430 // Validate transfer amount
    431 if amount < 0 {
    432 return makeErrorWithDetails(
    433 errInvalidAmount,
    434 ufmt.Sprintf("invalid amount %d to transfer protocol fee", amount),
    435 )
    436 }
    437
    438 // Check sufficient balance
    439 balance := common.BalanceOf(tokenPath, from)
    440 if balance < amount {
    441 return makeErrorWithDetails(
    442 errNotEnoughBalance,
    443 ufmt.Sprintf("not enough %s balance(%d) to collect(%d)", tokenPath, balance, amount),
    444 )
    445 }
    446
    447 common.SafeGRC20Transfer(0, rlm, tokenPath, to, amount)
    448
    449 return nil
    450}
    451