launchpad_reward.gno
3.38 Kb · 118 lines
1package launchpad
2
3import (
4 "chain"
5 "chain/runtime"
6 "time"
7
8 "gno.land/r/gnoswap/access/v1"
9
10 gnsmath "gno.land/p/gnoswap/gnsmath/v1"
11 "gno.land/p/gnoswap/utils/v1"
12
13 "gno.land/r/gnoswap/common"
14 "gno.land/r/gnoswap/halt/v1"
15 "gno.land/r/gnoswap/launchpad"
16)
17
18// CollectRewardByDepositId collects the claimable project-token reward from a
19// specific deposit. The reward becomes claimable one day after deposit creation,
20// capped at the selected tier's end time.
21//
22// Parameters:
23// - _: Noncrossing implementation-call discriminator; pass 0.
24// - rlm: Current realm context forwarded unchanged by the launchpad proxy.
25// - depositID: ID of the deposit to collect from.
26//
27// Returns:
28// - amount: project-token reward amount collected for the deposit, in the token's base units; failures panic before returning.
29//
30// Only callable by deposit owner after the claimable time.
31func (lp *launchpadV1) CollectRewardByDepositId(_ int, rlm realm, depositID string) int64 {
32 access.AssertIsRlmCurrent(0, rlm)
33
34 halt.AssertIsNotHaltedWithdraw()
35
36 previousRealm := rlm.Previous()
37
38 caller := previousRealm.Address()
39 lp.assertIsDepositOwner(depositID, caller)
40
41 deposit := lp.mustGetDeposit(depositID)
42 targetProjectTierID := deposit.ProjectTierID()
43 currentHeight := runtime.ChainHeight()
44 currentTime := time.Now().Unix()
45
46 rewardTokenPath, rewardAmount, err := lp.collectDepositReward(0, rlm, deposit, currentHeight, currentTime)
47 if err != nil {
48 panic(err)
49 }
50
51 // Transfer reward token to depositor
52 if rewardAmount > 0 {
53 common.SafeGRC20Transfer(0, rlm, rewardTokenPath, deposit.Depositor(), rewardAmount)
54 }
55
56 chain.Emit(
57 "CollectRewardByDepositId",
58 "prevAddr", caller.String(),
59 "prevRealm", previousRealm.PkgPath(),
60 "depositId", depositID,
61 "targetProjectTierId", targetProjectTierID,
62 "rewardTokenPath", rewardTokenPath,
63 "amount", utils.FormatInt(rewardAmount),
64 )
65
66 return rewardAmount
67}
68
69// collectDepositReward calculates and collects the reward for a deposit.
70func (lp *launchpadV1) collectDepositReward(_ int, rlm realm, deposit launchpad.Deposit, currentHeight, currentTime int64) (string, int64, error) {
71 if currentTime <= 0 {
72 return "", 0, makeErrorWithDetails(errInvalidTime, "currentTime must be positive")
73 }
74
75 // Get project and tier data
76 project, err := lp.getProject(deposit.ProjectID())
77 if err != nil {
78 return "", 0, err
79 }
80
81 projectTier, err := getProjectTier(project, deposit.Tier())
82 if err != nil {
83 return "", 0, err
84 }
85
86 // Get reward manager
87 rewardManager, err := lp.getProjectTierRewardManager(projectTier.ID())
88 if err != nil {
89 return "", 0, err
90 }
91
92 // Update reward state before collection
93 err = updateRewardPerDepositX128(rewardManager, getTierCurrentDepositAmount(projectTier), currentTime)
94 if err != nil {
95 return "", 0, err
96 }
97
98 // Collect reward
99 rewardAmount, err := collectReward(rewardManager, deposit.ID(), currentTime)
100 if err != nil {
101 return "", 0, err
102 }
103
104 // Update total collected amount for the tier
105 if rewardAmount > 0 {
106 projectTier.SetTotalCollectedAmount(gnsmath.SafeAddInt64(projectTier.TotalCollectedAmount(), rewardAmount))
107 project.SetTier(deposit.Tier(), projectTier)
108
109 projects := lp.store.GetProjects()
110 if err := lp.store.SetProjects(0, rlm, projects); err != nil {
111 return "", 0, err
112 }
113 }
114
115 emitUpdateLaunchpadRewardAccumulation(projectTier.ID(), rewardManager, getTierCurrentDepositAmount(projectTier))
116
117 return project.TokenPath(), rewardAmount, nil
118}