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

launchpad_deposit.gno

5.99 Kb · 211 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 !isTierDepositable(projectTier, currentTime) {
144		return launchpad.DefaultDeposit(), nil, false, "", makeErrorWithDetails(errInactiveProject, project.ID())
145	}
146
147	assertHasTierReward(projectTier)
148
149	depositID := lp.nextDepositID()
150	deposit := launchpad.MakeDeposit(
151		depositID,
152		project.ID(),
153		tierDuration,
154		callerAddress,
155		depositAmount,
156		currentHeight,
157		currentTime,
158		projectTier.EndTime(),
159	)
160
161	// Store a value in the deposits tree and persist later updates explicitly.
162	deposits := lp.store.GetDeposits()
163	deposits.Set(depositID, deposit)
164
165	rewardManager, err := lp.getProjectTierRewardManager(projectTier.ID())
166	if err != nil {
167		return launchpad.DefaultDeposit(), nil, false, "", err
168	}
169
170	isFirstDeposit := !isRewardManagerInitialized(rewardManager)
171
172	// update rewards before adding deposit to reward manager
173	err = updateRewardPerDepositX128(rewardManager, getTierCurrentDepositAmount(projectTier), currentTime)
174	if err != nil {
175		return launchpad.DefaultDeposit(), nil, false, "", err
176	}
177
178	// add reward state to reward manager
179	rewardState := addRewardStateByDeposit(rewardManager, deposit)
180
181	// update tier data after adding reward state to reward manager
182	depositToTier(projectTier, deposit)
183	project.SetTier(tierDuration, projectTier)
184
185	// Save the modified state back
186	if err := lp.store.SetDeposits(0, rlm, deposits); err != nil {
187		return launchpad.DefaultDeposit(), nil, false, "", err
188	}
189
190	emitUpdateLaunchpadRewardAccumulation(projectTier.ID(), rewardManager, getTierCurrentDepositAmount(projectTier))
191
192	return deposit,
193		rewardState,
194		isFirstDeposit,
195		rewardManager.DistributeAmountPerSecondX128().ToString(),
196		nil
197}
198
199// stakeGovernance stakes governance token to the project.
200func (lp *launchpadV1) stakeGovernance(_ int, rlm realm, recipient address, depositAmount int64, launchpadAddress address, callerAddress address) error {
201	gov_staker.SetAmountByProjectWallet(cross(rlm), recipient, depositAmount, true)
202
203	gns.TransferFrom(
204		cross(rlm),
205		callerAddress,
206		launchpadAddress,
207		depositAmount,
208	)
209
210	return nil
211}