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}