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}