Search Apps Documentation Source Content File Folder Download Copy Actions Download

protocol_fee.gno

5.08 Kb ยท 191 lines
  1package v1
  2
  3import (
  4	"chain"
  5	"chain/runtime"
  6
  7	prabc "gno.land/p/gnoswap/rbac"
  8	u256 "gno.land/p/gnoswap/uint256"
  9	"gno.land/p/nt/ufmt"
 10
 11	"gno.land/r/gnoswap/access"
 12	"gno.land/r/gnoswap/common"
 13	"gno.land/r/gnoswap/halt"
 14	pf "gno.land/r/gnoswap/protocol_fee"
 15)
 16
 17const (
 18	MaxBpsValue = uint64(1000) // 10%
 19	ZeroBps     = uint64(0)
 20)
 21
 22// HandleWithdrawalFee withdraws the fee from the user and returns the amount after the fee
 23// Only position contract can call this function
 24// Input:
 25// - positionId: the id of the LP token
 26// - token0Path: the path of the token0
 27// - amount0: the amount of token0
 28// - token1Path: the path of the token1
 29// - amount1: the amount of token1
 30// - poolPath: the path of the pool
 31// - positionCaller: the original caller of the position contract
 32// Output:
 33// - the amount of token0 after the fee
 34// - the amount of token1 after the fee
 35func (i *poolV1) HandleWithdrawalFee(
 36	positionId uint64,
 37	token0Path string,
 38	amount0 string, // uint256
 39	token1Path string,
 40	amount1 string, // uint256
 41	poolPath string,
 42	positionCaller address,
 43) (string, string) { // uint256 x2
 44	halt.AssertIsNotHaltedPool()
 45	halt.AssertIsNotHaltedWithdraw()
 46
 47	// only position contract can call this function
 48	previousRealm := runtime.PreviousRealm()
 49	caller := previousRealm.Address()
 50	access.AssertIsPosition(caller)
 51
 52	common.MustRegistered(token0Path, token1Path)
 53
 54	fee := i.store.GetWithdrawalFeeBPS()
 55	if fee == ZeroBps {
 56		return amount0, amount1
 57	}
 58
 59	feeU256 := u256.NewUint(fee)
 60	feeAmount0, afterAmount0 := calculateAmountWithFee(u256.MustFromDecimal(amount0), feeU256)
 61	feeAmount1, afterAmount1 := calculateAmountWithFee(u256.MustFromDecimal(amount1), feeU256)
 62
 63	protocolFeeAddr := access.MustGetAddress(prabc.ROLE_PROTOCOL_FEE.String())
 64
 65	pf.AddToProtocolFee(cross, token0Path, safeConvertToInt64(feeAmount0))
 66	common.SafeGRC20TransferFrom(cross, token0Path, positionCaller, protocolFeeAddr, safeConvertToInt64(feeAmount0))
 67	pf.AddToProtocolFee(cross, token1Path, safeConvertToInt64(feeAmount1))
 68	common.SafeGRC20TransferFrom(cross, token1Path, positionCaller, protocolFeeAddr, safeConvertToInt64(feeAmount1))
 69
 70	afterAmount0Str := afterAmount0.ToString()
 71	afterAmount1Str := afterAmount1.ToString()
 72
 73	chain.Emit(
 74		"WithdrawalFee",
 75		"prevAddr", caller.String(),
 76		"prevRealm", previousRealm.PkgPath(),
 77		"lpTokenId", formatUint(positionId),
 78		"poolPath", poolPath,
 79		"feeAmount0", feeAmount0.ToString(),
 80		"feeAmount1", feeAmount1.ToString(),
 81		"amount0WithoutFee", afterAmount0Str,
 82		"amount1WithoutFee", afterAmount1Str,
 83	)
 84
 85	return afterAmount0Str, afterAmount1Str
 86}
 87
 88// SetPoolCreationFee sets the poolCreationFee.
 89// Only admin or governance can call this function.
 90func (i *poolV1) SetPoolCreationFee(fee int64) {
 91	halt.AssertIsNotHaltedPool()
 92
 93	previousRealm := runtime.PreviousRealm()
 94	caller := previousRealm.Address()
 95	access.AssertIsAdminOrGovernance(caller)
 96
 97	prevPoolCreationFee := i.store.GetPoolCreationFee()
 98	err := i.setPoolCreationFee(fee)
 99	if err != nil {
100		panic(err)
101	}
102
103	chain.Emit(
104		"SetPoolCreationFee",
105		"prevAddr", caller.String(),
106		"prevRealm", previousRealm.PkgPath(),
107		"prevFee", formatInt(prevPoolCreationFee),
108		"newFee", formatInt(fee),
109	)
110}
111
112// SetWithdrawalFee sets the withdrawal fee.
113// Only admin or governance can call this function.
114func (i *poolV1) SetWithdrawalFee(fee uint64) {
115	halt.AssertIsNotHaltedPool()
116
117	previousRealm := runtime.PreviousRealm()
118	caller := previousRealm.Address()
119	access.AssertIsAdminOrGovernance(caller)
120
121	prevWithdrawalFee := i.store.GetWithdrawalFeeBPS()
122
123	err := i.setWithdrawalFee(fee)
124	if err != nil {
125		panic(err)
126	}
127
128	chain.Emit(
129		"SetWithdrawalFee",
130		"prevAddr", caller.String(),
131		"prevRealm", previousRealm.PkgPath(),
132		"prevFee", formatUint(prevWithdrawalFee),
133		"newFee", formatUint(fee),
134	)
135}
136
137// calculateAmountWithFee calculates the fee amount and the amount after the fee
138//
139// Inputs:
140// - amount: the amount before the fee
141// - fee: the fee in BPS
142//
143// Outputs:
144// - the fee amount
145// - the amount after the fee applied
146func calculateAmountWithFee(amount, fee *u256.Uint) (feeAmount, afterAmount *u256.Uint) {
147	feeAmount, overflow := u256.Zero().MulOverflow(amount, fee)
148	if overflow {
149		panic(errOverflow)
150	}
151	feeAmount = u256.Zero().Div(feeAmount, u256.NewUint(MaxBpsValue))
152	afterAmount = u256.Zero().Sub(amount, feeAmount)
153	return feeAmount, afterAmount
154}
155
156// setPoolCreationFee this function is internal function called by SetPoolCreationFee
157// And SetPoolCreationFee
158func (i *poolV1) setPoolCreationFee(fee int64) error {
159	if fee < 0 {
160		return makeErrorWithDetails(
161			errInvalidInput,
162			"pool creation fee cannot be negative",
163		)
164	}
165
166	// update pool creation fee
167	err := i.store.SetPoolCreationFee(fee)
168	if err != nil {
169		return err
170	}
171
172	return nil
173}
174
175// setWithdrawalFee this function is internal function called by SetWithdrawalFee
176// function and SetWithdrawalFee function
177func (i *poolV1) setWithdrawalFee(fee uint64) error {
178	if fee > MaxBpsValue {
179		return makeErrorWithDetails(
180			errInvalidWithdrawalFeePct,
181			ufmt.Sprintf("fee(%d) must be in range 0 ~ %d", fee, MaxBpsValue),
182		)
183	}
184
185	err := i.store.SetWithdrawalFeeBPS(fee)
186	if err != nil {
187		return err
188	}
189
190	return nil
191}