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