launchpad_deposit.gno
5.05 Kb ยท 195 lines
1package v1
2
3import (
4 "chain"
5 "chain/runtime"
6 "time"
7
8 "gno.land/r/gnoswap/access"
9 "gno.land/r/gnoswap/common"
10 "gno.land/r/gnoswap/gns"
11 gov_staker "gno.land/r/gnoswap/gov/staker"
12 "gno.land/r/gnoswap/gov/xgns"
13 "gno.land/r/gnoswap/halt"
14 "gno.land/r/gnoswap/launchpad"
15 "gno.land/r/gnoswap/referral"
16)
17
18// DepositGns deposits GNS tokens to a launchpad project tier.
19//
20// Parameters:
21// - targetProjectTierID: format "{projectId}:{tierType}"
22// - depositAmount: amount of GNS to deposit
23// - referrer: referral address (optional)
24//
25// Returns deposit ID.
26func (lp *launchpadV1) DepositGns(targetProjectTierID string, depositAmount int64, referrer string) string {
27 halt.AssertIsNotHaltedLaunchpad()
28
29 previousRealm := runtime.PreviousRealm()
30 access.AssertIsUser(previousRealm)
31
32 assertIsValidAmount(depositAmount)
33
34 projectID, tierDuration := parseProjectTierID(targetProjectTierID)
35 caller := previousRealm.Address()
36
37 project, err := lp.getProject(projectID)
38 if err != nil {
39 panic(err.Error())
40 }
41
42 deposit, rewardState, isFirstDeposit, distributeAmountPerSecondX128, err := lp.depositGns(
43 project,
44 tierDuration,
45 depositAmount,
46 caller,
47 )
48 if err != nil {
49 panic(err.Error())
50 }
51
52 actualReferrer, success := registerReferral(referrer, caller)
53 if !success {
54 actualReferrer = referral.GetReferral(runtime.PreviousRealm().Address().String())
55 }
56
57 if isFirstDeposit {
58 chain.Emit(
59 "FirstDepositForProjectTier",
60 "prevAddr", previousRealm.Address().String(),
61 "prevRealm", previousRealm.PkgPath(),
62 "targetProjectTierId", targetProjectTierID,
63 "amount", formatInt(depositAmount),
64 "depositId", deposit.ID(),
65 "claimableTime", formatInt(rewardState.ClaimableTime()),
66 "tierAmountPerSecondX128", distributeAmountPerSecondX128,
67 )
68 }
69
70 chain.Emit(
71 "DepositGns",
72 "prevAddr", previousRealm.Address().String(),
73 "prevRealm", previousRealm.PkgPath(),
74 "targetProjectTierId", targetProjectTierID,
75 "amount", formatInt(depositAmount),
76 "depositId", deposit.ID(),
77 "claimableTime", formatInt(rewardState.ClaimableTime()),
78 "referrer", actualReferrer,
79 )
80
81 launchpadAddress := runtime.CurrentRealm().Address()
82
83 // stake governance token to the project
84 err = lp.stakeGovernance(project.Recipient(), depositAmount, launchpadAddress, caller)
85 if err != nil {
86 panic(err.Error())
87 }
88
89 return deposit.ID()
90}
91
92// depositGns deposits GNS to a project tier.
93func (lp *launchpadV1) depositGns(
94 project *launchpad.Project,
95 tierDuration int64,
96 depositAmount int64,
97 callerAddress address,
98) (*launchpad.Deposit, *launchpad.RewardState, bool, string, error) {
99 balanceOfFn := func(tokenPath string, caller address) int64 {
100 if tokenPath == GOV_XGNS_PATH {
101 return xgns.BalanceOf(caller)
102 }
103
104 return common.BalanceOf(tokenPath, caller)
105 }
106
107 err := checkProjectConditions(project, callerAddress, balanceOfFn)
108 if err != nil {
109 return nil, nil, false, "", err
110 }
111
112 projectTier, err := getProjectTier(project, tierDuration)
113 if err != nil {
114 return nil, nil, false, "", err
115 }
116
117 currentTime := time.Now().Unix()
118 currentHeight := runtime.ChainHeight()
119
120 if !projectTier.IsActivated(currentTime) {
121 return nil, nil, false, "", makeErrorWithDetails(errInactiveProject, project.ID())
122 }
123
124 depositID := lp.nextDepositID()
125 deposit := launchpad.NewDeposit(
126 depositID,
127 project.ID(),
128 tierDuration,
129 callerAddress,
130 depositAmount,
131 currentHeight,
132 currentTime,
133 projectTier.EndTime(),
134 )
135
136 // Get state and store deposit
137 deposits := lp.store.GetDeposits()
138 deposits.Set(depositID, deposit)
139
140 rewardManager, err := lp.getProjectTierRewardManager(projectTier.ID())
141 if err != nil {
142 return nil, nil, false, "", err
143 }
144
145 isFirstDeposit := !isRewardManagerInitialized(rewardManager)
146
147 // update rewards before adding deposit to reward manager
148 err = updateRewardPerDepositX128(rewardManager, getTierCurrentDepositAmount(projectTier), currentHeight, currentTime)
149 if err != nil {
150 return nil, nil, false, "", err
151 }
152
153 // add reward state to reward manager
154 rewardState := addRewardStateByDeposit(rewardManager, deposit)
155
156 // update tier data after adding reward state to reward manager
157 depositToTier(projectTier, deposit)
158 project.SetTier(tierDuration, projectTier)
159
160 // Save the modified state back
161 if err := lp.store.SetDeposits(deposits); err != nil {
162 return nil, nil, false, "", err
163 }
164
165 return deposit,
166 rewardState,
167 isFirstDeposit,
168 rewardManager.DistributeAmountPerSecondX128().ToString(),
169 nil
170}
171
172// registerReferral registers a referral for a caller.
173func registerReferral(referrer string, callerAddress address) (string, bool) {
174 success := referral.TryRegister(cross, callerAddress, referrer)
175 actualReferrer := referrer
176 if !success {
177 actualReferrer = referral.GetReferral(callerAddress.String())
178 }
179
180 return actualReferrer, success
181}
182
183// stakeGovernance stakes governance token to the project.
184func (lp *launchpadV1) stakeGovernance(recipient address, depositAmount int64, launchpadAddress address, callerAddress address) error {
185 gov_staker.SetAmountByProjectWallet(cross, recipient, depositAmount, true)
186
187 gns.TransferFrom(
188 cross,
189 callerAddress,
190 launchpadAddress,
191 depositAmount,
192 )
193
194 return nil
195}