Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

launchpad_deposit.gno

5.95 Kb · 209 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/emission"
 15	"gno.land/r/gnoswap/gns"
 16	gov_staker "gno.land/r/gnoswap/gov/staker"
 17	"gno.land/r/gnoswap/gov/xgns"
 18	"gno.land/r/gnoswap/halt/v1"
 19	"gno.land/r/gnoswap/launchpad"
 20	"gno.land/r/gnoswap/referral/v1"
 21)
 22
 23// DepositGns deposits GNS tokens to a launchpad project tier.
 24//
 25// Parameters:
 26//   - _: leading integer discriminator for the forwarded realm call; callers pass 0.
 27//   - rlm: propagated realm context; the implementation validates it is the current realm.
 28//   - targetProjectTierID: project-tier identifier in `{projectID}:{tierDuration}` form.
 29//   - depositAmount: amount of GNS to deposit into the tier.
 30//   - referrer: optional referral address associated with the deposit.
 31//
 32// Returns:
 33//   - depositID: identifier assigned to the newly created deposit.
 34func (lp *launchpadV1) DepositGns(_ int, rlm realm, targetProjectTierID string, depositAmount int64, referrer string) string {
 35	access.AssertIsRlmCurrent(0, rlm)
 36
 37	halt.AssertIsNotHaltedLaunchpad()
 38
 39	previousRealm := rlm.Previous()
 40
 41	assertIsValidAmount(depositAmount)
 42
 43	emission.MintAndDistributeGns(cross(rlm))
 44
 45	projectID, tierDuration := parseProjectTierID(targetProjectTierID)
 46	caller := previousRealm.Address()
 47
 48	project, err := lp.getProject(projectID)
 49	if err != nil {
 50		panic(err.Error())
 51	}
 52
 53	beforeTotalGNSStakedAmount := lp.store.GetTotalGNSStakedAmount()
 54
 55	deposit, rewardState, isFirstDeposit, distributeAmountPerSecondX128, err := lp.depositGns(
 56		0,
 57		rlm,
 58		project,
 59		tierDuration,
 60		depositAmount,
 61		caller,
 62	)
 63	if err != nil {
 64		panic(err.Error())
 65	}
 66
 67	afterTotalGNSStakedAmount := gnsmath.SafeAddInt64(beforeTotalGNSStakedAmount, depositAmount)
 68	if err := lp.store.SetTotalGNSStakedAmount(0, rlm, afterTotalGNSStakedAmount); err != nil {
 69		panic(err.Error())
 70	}
 71
 72	actualReferrer := referral.TryRegister(cross(rlm), caller, referrer)
 73
 74	if isFirstDeposit {
 75		chain.Emit(
 76			"FirstDepositForProjectTier",
 77			"prevAddr", previousRealm.Address().String(),
 78			"prevRealm", previousRealm.PkgPath(),
 79			"targetProjectTierId", targetProjectTierID,
 80			"amount", utils.FormatInt(depositAmount),
 81			"depositId", deposit.ID(),
 82			"claimableTime", utils.FormatInt(rewardState.ClaimableTime()),
 83			"tierAmountPerSecondX128", distributeAmountPerSecondX128,
 84			"totalGNSStakedAmount", utils.FormatInt(afterTotalGNSStakedAmount),
 85			"recipient", project.Recipient().String(),
 86		)
 87	}
 88
 89	chain.Emit(
 90		"DepositGns",
 91		"prevAddr", previousRealm.Address().String(),
 92		"prevRealm", previousRealm.PkgPath(),
 93		"targetProjectTierId", targetProjectTierID,
 94		"amount", utils.FormatInt(depositAmount),
 95		"depositId", deposit.ID(),
 96		"claimableTime", utils.FormatInt(rewardState.ClaimableTime()),
 97		"referrer", actualReferrer,
 98		"totalGNSStakedAmount", utils.FormatInt(afterTotalGNSStakedAmount),
 99		"recipient", project.Recipient().String(),
100	)
101
102	launchpadAddress := rlm.Address()
103
104	// stake governance token to the project
105	err = lp.stakeGovernance(0, rlm, project.Recipient(), depositAmount, launchpadAddress, caller)
106	if err != nil {
107		panic(err.Error())
108	}
109
110	return deposit.ID()
111}
112
113// depositGns deposits GNS to a project tier.
114func (lp *launchpadV1) depositGns(
115	_ int,
116	rlm realm,
117	project *launchpad.Project,
118	tierDuration int64,
119	depositAmount int64,
120	callerAddress address,
121) (launchpad.Deposit, *launchpad.RewardState, bool, string, error) {
122	balanceOfFn := func(tokenPath string, caller address) int64 {
123		if tokenPath == GOV_XGNS_PATH {
124			return xgns.BalanceOf(caller)
125		}
126
127		return common.BalanceOf(tokenPath, caller)
128	}
129
130	err := checkProjectConditions(project, callerAddress, balanceOfFn)
131	if err != nil {
132		return launchpad.DefaultDeposit(), nil, false, "", err
133	}
134
135	projectTier, err := getProjectTier(project, tierDuration)
136	if err != nil {
137		return launchpad.DefaultDeposit(), nil, false, "", err
138	}
139
140	currentTime := time.Now().Unix()
141	currentHeight := runtime.ChainHeight()
142
143	if !projectTier.IsActivated(currentTime) {
144		return launchpad.DefaultDeposit(), nil, false, "", makeErrorWithDetails(errInactiveProject, project.ID())
145	}
146
147	depositID := lp.nextDepositID()
148	deposit := launchpad.MakeDeposit(
149		depositID,
150		project.ID(),
151		tierDuration,
152		callerAddress,
153		depositAmount,
154		currentHeight,
155		currentTime,
156		projectTier.EndTime(),
157	)
158
159	// Store a value in the deposits tree and persist later updates explicitly.
160	deposits := lp.store.GetDeposits()
161	deposits.Set(depositID, deposit)
162
163	rewardManager, err := lp.getProjectTierRewardManager(projectTier.ID())
164	if err != nil {
165		return launchpad.DefaultDeposit(), nil, false, "", err
166	}
167
168	isFirstDeposit := !isRewardManagerInitialized(rewardManager)
169
170	// update rewards before adding deposit to reward manager
171	err = updateRewardPerDepositX128(rewardManager, getTierCurrentDepositAmount(projectTier), currentTime)
172	if err != nil {
173		return launchpad.DefaultDeposit(), nil, false, "", err
174	}
175
176	// add reward state to reward manager
177	rewardState := addRewardStateByDeposit(rewardManager, deposit)
178
179	// update tier data after adding reward state to reward manager
180	depositToTier(projectTier, deposit)
181	project.SetTier(tierDuration, projectTier)
182
183	// Save the modified state back
184	if err := lp.store.SetDeposits(0, rlm, deposits); err != nil {
185		return launchpad.DefaultDeposit(), nil, false, "", err
186	}
187
188	emitUpdateLaunchpadRewardAccumulation(projectTier.ID(), rewardManager, getTierCurrentDepositAmount(projectTier))
189
190	return deposit,
191		rewardState,
192		isFirstDeposit,
193		rewardManager.DistributeAmountPerSecondX128().ToString(),
194		nil
195}
196
197// stakeGovernance stakes governance token to the project.
198func (lp *launchpadV1) stakeGovernance(_ int, rlm realm, recipient address, depositAmount int64, launchpadAddress address, callerAddress address) error {
199	gov_staker.SetAmountByProjectWallet(cross(rlm), recipient, depositAmount, true)
200
201	gns.TransferFrom(
202		cross(rlm),
203		callerAddress,
204		launchpadAddress,
205		depositAmount,
206	)
207
208	return nil
209}