Search Apps Documentation Source Content File Folder Download Copy Actions Download

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}