Search Apps Documentation Source Content File Folder Download Copy Actions Download

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}