Search Apps Documentation Source Content File Folder Download Copy Actions Download

launchpad_withdraw.gno

4.26 Kb ยท 152 lines
  1package v1
  2
  3import (
  4	"chain"
  5	"chain/runtime"
  6	"time"
  7
  8	"gno.land/p/nt/ufmt"
  9
 10	"gno.land/r/gnoswap/access"
 11	"gno.land/r/gnoswap/common"
 12	"gno.land/r/gnoswap/emission"
 13	"gno.land/r/gnoswap/halt"
 14	"gno.land/r/gnoswap/launchpad"
 15
 16	gov_staker "gno.land/r/gnoswap/gov/staker"
 17)
 18
 19// CollectDepositGns withdraws the original GNS deposit after the lock period ends.
 20//
 21// Parameters:
 22//   - depositID: ID of the deposit to withdraw
 23//
 24// Returns amount withdrawn and any error.
 25// Only callable by deposit owner after tier lock period ends.
 26func (lp *launchpadV1) CollectDepositGns(depositID string) (int64, error) {
 27	halt.AssertIsNotHaltedLaunchpad()
 28	halt.AssertIsNotHaltedWithdraw()
 29
 30	previousRealm := runtime.PreviousRealm()
 31	access.AssertIsUser(previousRealm)
 32
 33	caller := previousRealm.Address()
 34	lp.assertIsDepositOwner(depositID, caller)
 35
 36	emission.MintAndDistributeGns(cross)
 37
 38	deposit := lp.mustGetDeposit(depositID)
 39	currentHeight := runtime.ChainHeight()
 40	currentTime := time.Now().Unix()
 41
 42	// Collect reward before withdrawal
 43	rewardTokenPath, rewardAmount, err := lp.collectDepositReward(deposit, currentHeight, currentTime)
 44	if err != nil {
 45		panic(err)
 46	}
 47
 48	// Transfer reward token to depositor
 49	if rewardAmount > 0 {
 50		common.SafeGRC20Transfer(cross, rewardTokenPath, deposit.Depositor(), rewardAmount)
 51
 52		chain.Emit(
 53			"CollectRewardByDepositId",
 54			"prevAddr", caller.String(),
 55			"prevRealm", previousRealm.PkgPath(),
 56			"depositId", depositID,
 57			"amount", formatInt(rewardAmount),
 58		)
 59	}
 60
 61	recipient, withdrawalAmount, err := lp.withdrawDeposit(deposit, runtime.ChainHeight(), currentTime)
 62	if err != nil {
 63		panic(err.Error())
 64	}
 65
 66	unStakeGovernance(recipient, withdrawalAmount)
 67
 68	// Transfer the original GNS deposit back to the depositor
 69	common.SafeGRC20Transfer(cross, GNS_PATH, deposit.Depositor(), withdrawalAmount)
 70
 71	chain.Emit(
 72		"CollectDepositGns",
 73		"prevAddr", caller.String(),
 74		"prevRealm", previousRealm.PkgPath(),
 75		"depositId", depositID,
 76		"amount", formatInt(withdrawalAmount),
 77	)
 78
 79	return withdrawalAmount, nil
 80}
 81
 82// withdrawDeposit withdraws a deposit and updates the reward manager.
 83func (lp *launchpadV1) withdrawDeposit(deposit *launchpad.Deposit, currentHeight, currentTime int64) (address, int64, error) {
 84	// Input validation
 85	if deposit == nil {
 86		return "", 0, makeErrorWithDetails(errNotExistDeposit, "deposit is nil")
 87	}
 88
 89	if currentTime <= 0 {
 90		return "", 0, makeErrorWithDetails(errInvalidTime, "currentTime must be positive")
 91	}
 92
 93	// State validation
 94	if deposit.IsWithdrawn() {
 95		return "", 0, makeErrorWithDetails(errAlreadyCollected, ufmt.Sprintf("(%s)", deposit.ID()))
 96	}
 97
 98	if !deposit.IsEnded(currentTime) {
 99		return "", 0, makeErrorWithDetails(errNotYetEndedProject, ufmt.Sprintf("(%s)", deposit.ID()))
100	}
101
102	// Get project and tier information
103	project, err := lp.getProject(deposit.ProjectID())
104	if err != nil {
105		return "", 0, err
106	}
107
108	projectTier, err := getProjectTier(project, deposit.Tier())
109	if err != nil {
110		return "", 0, err
111	}
112
113	// Get reward manager and update rewards before withdrawal
114	rewardManager, err := lp.getProjectTierRewardManager(projectTier.ID())
115	if err != nil {
116		return "", 0, err
117	}
118
119	// Update rewards with current deposit amount
120	err = updateRewardPerDepositX128(rewardManager, getTierCurrentDepositAmount(projectTier), currentHeight, currentTime)
121	if err != nil {
122		return "", 0, err
123	}
124
125	// Process withdrawal from project tier
126	withdrawToTier(projectTier, deposit)
127	project.SetTier(deposit.Tier(), projectTier)
128
129	// Finalize withdrawal
130	withdrawalAmount := withdrawDeposit(deposit, currentHeight, currentTime)
131
132	// Remove reward state from AVL tree after withdrawal
133	// This improves iteration performance for calculateClaimableRewardsForActiveDeposits
134	// and prevents accessing reward state for already withdrawn deposits
135	removeRewardState(rewardManager, deposit.ID())
136
137	// Store updated deposit in state
138	deposits := lp.store.GetDeposits()
139	deposits.Set(deposit.ID(), deposit)
140
141	// Save the modified state back
142	if err := lp.store.SetDeposits(deposits); err != nil {
143		return "", 0, err
144	}
145
146	return project.Recipient(), withdrawalAmount, nil
147}
148
149// unStakeGovernance removes the staked amount from governance system
150func unStakeGovernance(recipient address, withdrawalAmount int64) {
151	gov_staker.SetAmountByProjectWallet(cross, recipient, withdrawalAmount, false)
152}