native_token.gno
5.31 Kb ยท 170 lines
1package v1
2
3import (
4 "chain"
5 "chain/banker"
6 "chain/runtime"
7
8 "gno.land/p/nt/ufmt"
9
10 "gno.land/r/gnoland/wugnot"
11)
12
13const (
14 UGNOT_MIN_DEPOSIT_TO_WRAP = int64(1000)
15 WUGNOT_PATH = "gno.land/r/gnoland/wugnot"
16 GNOT_DENOM = "ugnot"
17)
18
19// wrap wraps the specified amount of the native token ugnot into the wrapped token wugnot.
20// Returns an error if ugnotAmount is zero or less than the minimum deposit threshold.
21func (p *positionV1) wrap(ugnotAmount int64, to address) error {
22 if ugnotAmount == 0 || ugnotAmount < UGNOT_MIN_DEPOSIT_TO_WRAP {
23 return ufmt.Errorf("amount(%d) < minimum(%d)", ugnotAmount, UGNOT_MIN_DEPOSIT_TO_WRAP)
24 }
25
26 positionAddr := mustGetPositionAddress()
27 wugnotAddr := chain.PackageAddress(WUGNOT_PATH)
28 p.transferUGNOT(positionAddr, wugnotAddr, ugnotAmount)
29
30 wugnot.Deposit(cross) // position has wugnot
31 wugnot.Transfer(cross, to, ugnotAmount) // send wugnot: position -> user
32
33 return nil
34}
35
36// unwrap converts a specified amount of WUGNOT tokens into UGNOT tokens
37// and transfers the resulting UGNOT back to the specified recipient address.
38func (p *positionV1) unwrap(wugnotAmount int64, to address) error {
39 if wugnotAmount <= 0 {
40 return ufmt.Errorf("amount(%d) is zero or negative", wugnotAmount)
41 }
42
43 positionAddr := mustGetPositionAddress()
44
45 wugnot.TransferFrom(cross, to, positionAddr, wugnotAmount) // send wugnot: user -> position
46 wugnot.Withdraw(cross, wugnotAmount) // position has ugnot
47 p.transferUGNOT(positionAddr, to, wugnotAmount) // send ugnot: position -> user
48 return nil
49}
50
51// transferUGNOT transfers a specified amount of UGNOT tokens from one address to another.
52// The function ensures that no transaction occurs if the transfer amount is zero.
53// Panics if amount is negative or if sender has insufficient balance.
54func (p *positionV1) transferUGNOT(from, to address, amount int64) {
55 if amount < 0 {
56 panic(ufmt.Sprintf("amount(%d) is negative", amount))
57 }
58 if amount == 0 {
59 return
60 }
61
62 banker_ := banker.NewBanker(banker.BankerTypeRealmSend)
63 fromBalance := banker_.GetCoins(from).AmountOf(GNOT_DENOM)
64 if fromBalance < amount {
65 panic(newErrorWithDetail(
66 errInsufficientUGNOT,
67 ufmt.Sprintf("from(%s) balance(%d) is less than amount(%d)", from, fromBalance, amount)))
68 }
69 banker_.SendCoins(from, to, chain.Coins{
70 {Denom: GNOT_DENOM, Amount: amount},
71 })
72}
73
74// isNative checks whether the given token is a native token.
75func isNative(token string) bool {
76 return token == GNOT_DENOM
77}
78
79// isWrappedToken checks whether the tokenPath is wrapped token.
80func isWrappedToken(tokenPath string) bool {
81 return tokenPath == WUGNOT_PATH
82}
83
84// safeWrapNativeToken safely wraps the native token ugnot into the wrapped token wugnot for a user.
85// Returns the amount of ugnot that was successfully wrapped into wugnot.
86// Returns an error if the sent ugnot amount is zero, less than requested, or if wrapping fails.
87func (p *positionV1) safeWrapNativeToken(amount int64, toAddress address) (int64, error) {
88 // if amount is zero, return 0
89 if amount == 0 {
90 return 0, nil
91 }
92
93 beforeWrappedBalance := wugnot.BalanceOf(toAddress)
94 nativeSentAmount := banker.OriginSend().AmountOf(GNOT_DENOM)
95
96 if nativeSentAmount <= 0 {
97 return 0, makeErrorWithDetails(errZeroUGNOT, "amount of ugnot is zero")
98 }
99
100 if nativeSentAmount < amount {
101 return 0, makeErrorWithDetails(errInsufficientUGNOT, "amount of ugnot is less than desired amount")
102 }
103
104 // If nativeSentAmount is greater than amount, refund the excess amount.
105 if nativeSentAmount > amount {
106 excessAmount := nativeSentAmount - amount
107 p.transferUGNOT(mustGetPositionAddress(), toAddress, excessAmount)
108
109 nativeSentAmount = amount
110 }
111
112 if err := p.wrapWithTransfer(nativeSentAmount, toAddress); err != nil {
113 return 0, err
114 }
115
116 balanceDiff := wugnot.BalanceOf(toAddress) - beforeWrappedBalance
117
118 if balanceDiff != nativeSentAmount {
119 return 0, makeErrorWithDetails(
120 errWrapUnwrap,
121 ufmt.Sprintf("amount of ugnot (%d) is not equal to amount of wugnot. (diff: %d)", nativeSentAmount, balanceDiff),
122 )
123 }
124
125 return nativeSentAmount, nil
126}
127
128func (p *positionV1) wrapWithTransfer(ugnotAmount int64, toAddress address) error {
129 if ugnotAmount <= 0 {
130 return makeErrorWithDetails(errWrapUnwrap, "cannot wrap 0 ugnot")
131 }
132
133 if ugnotAmount < UGNOT_MIN_DEPOSIT_TO_WRAP {
134 return makeErrorWithDetails(
135 errWugnotMinimum,
136 ufmt.Sprintf("amount(%d) < minimum(%d)", ugnotAmount, UGNOT_MIN_DEPOSIT_TO_WRAP),
137 )
138 }
139
140 // wrap it
141 wugnotAddr := chain.PackageAddress(WUGNOT_PATH)
142 currentRealmAddr := runtime.CurrentRealm().Address()
143
144 banker_ := banker.NewBanker(banker.BankerTypeRealmSend)
145 banker_.SendCoins(currentRealmAddr, wugnotAddr, chain.Coins{{GNOT_DENOM, ugnotAmount}})
146 wugnot.Deposit(cross) // Position has wugnot
147
148 // send wugnot: position -> user
149 wugnot.Transfer(cross, toAddress, ugnotAmount)
150
151 return nil
152}
153
154func (p *positionV1) unwrapWithTransferFrom(fromAddress, toAddress address, wugnotAmount int64) error {
155 if wugnotAmount == 0 {
156 return nil
157 }
158
159 currentRealmAddr := runtime.CurrentRealm().Address()
160 if fromAddress != currentRealmAddr {
161 wugnot.TransferFrom(cross, fromAddress, currentRealmAddr, wugnotAmount)
162 }
163
164 wugnot.Withdraw(cross, wugnotAmount)
165
166 banker_ := banker.NewBanker(banker.BankerTypeRealmSend)
167 banker_.SendCoins(currentRealmAddr, toAddress, chain.Coins{{GNOT_DENOM, wugnotAmount}})
168
169 return nil
170}