Kind Realm (renderable)
Name v1
Namespace gnoswap / gov / staker
Exported functions 12
Module gno.land/r/gnoswap/gov/staker/v1
gno 0.9 staker_reward.gno gno
⧉
1 package staker 2 3 import ( 4 "chain" 5 "time" 6 7 prbac "gno.land/p/gnoswap/rbac/v1" 8 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.
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.
38 func (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.
93 func (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
128 func (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.
169 func (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
236 func (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
283 func (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
347 func (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.
385 func (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.
401 func (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.
413 func 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