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