-
Notifications
You must be signed in to change notification settings - Fork 557
/
feetokens.go
188 lines (152 loc) · 5.15 KB
/
feetokens.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
package keeper
import (
"github.com/cosmos/gogoproto/proto"
errorsmod "cosmossdk.io/errors"
"github.com/osmosis-labs/osmosis/osmomath"
"github.com/osmosis-labs/osmosis/v22/x/txfees/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// ConvertToBaseToken converts a fee amount in a whitelisted fee token to the base fee token amount.
func (k Keeper) ConvertToBaseToken(ctx sdk.Context, inputFee sdk.Coin) (sdk.Coin, error) {
baseDenom, err := k.GetBaseDenom(ctx)
if err != nil {
return sdk.Coin{}, err
}
if inputFee.Denom == baseDenom {
return inputFee, nil
}
feeToken, err := k.GetFeeToken(ctx, inputFee.Denom)
if err != nil {
return sdk.Coin{}, err
}
spotPrice, err := k.CalcFeeSpotPrice(ctx, feeToken.Denom)
if err != nil {
return sdk.Coin{}, err
}
// Note: spotPrice truncation is done here for maintaining state-compatibility with v19.x
// It should be changed to support full spot price precision before
// https://github.com/osmosis-labs/osmosis/issues/6064 is complete
return sdk.NewCoin(baseDenom, spotPrice.Dec().MulInt(inputFee.Amount).RoundInt()), nil
}
// CalcFeeSpotPrice converts the provided tx fees into their equivalent value in the base denomination.
// Spot Price Calculation: spotPrice / (1 - spreadFactor),
// where spotPrice is defined as:
// (tokenBalanceIn / tokenWeightIn) / (tokenBalanceOut / tokenWeightOut)
func (k Keeper) CalcFeeSpotPrice(ctx sdk.Context, inputDenom string) (osmomath.BigDec, error) {
baseDenom, err := k.GetBaseDenom(ctx)
if err != nil {
return osmomath.BigDec{}, err
}
feeToken, err := k.GetFeeToken(ctx, inputDenom)
if err != nil {
return osmomath.BigDec{}, err
}
spotPrice, err := k.poolManager.RouteCalculateSpotPrice(ctx, feeToken.PoolID, baseDenom, feeToken.Denom)
if err != nil {
return osmomath.BigDec{}, err
}
return spotPrice, nil
}
// GetFeeToken returns the fee token record for a specific denom,
// In our case the baseDenom is uosmo.
func (k Keeper) GetBaseDenom(ctx sdk.Context) (denom string, err error) {
store := ctx.KVStore(k.storeKey)
if !store.Has(types.BaseDenomKey) {
return "", types.ErrNoBaseDenom
}
bz := store.Get(types.BaseDenomKey)
return string(bz), nil
}
// SetBaseDenom sets the base fee denom for the chain. Should only be used once.
func (k Keeper) SetBaseDenom(ctx sdk.Context, denom string) error {
store := ctx.KVStore(k.storeKey)
err := sdk.ValidateDenom(denom)
if err != nil {
return err
}
store.Set(types.BaseDenomKey, []byte(denom))
return nil
}
// ValidateFeeToken validates that a fee token record is valid
// It checks:
// - The denom exists
// - The denom is not the base denom
// - The gamm pool exists
// - The gamm pool includes the base token and fee token.
func (k Keeper) ValidateFeeToken(ctx sdk.Context, feeToken types.FeeToken) error {
baseDenom, err := k.GetBaseDenom(ctx)
if err != nil {
return err
}
if baseDenom == feeToken.Denom {
return errorsmod.Wrap(types.ErrInvalidFeeToken, "cannot add basedenom as a whitelisted fee token")
}
// This not returning an error implies that:
// - feeToken.Denom exists
// - feeToken.PoolID exists
// - feeToken.PoolID has both feeToken.Denom and baseDenom
_, err = k.poolManager.RouteCalculateSpotPrice(ctx, feeToken.PoolID, feeToken.Denom, baseDenom)
return err
}
// GetFeeToken returns a unique fee token record for a specific denom.
// If the denom doesn't exist, returns an error.
func (k Keeper) GetFeeToken(ctx sdk.Context, denom string) (types.FeeToken, error) {
prefixStore := k.GetFeeTokensStore(ctx)
if !prefixStore.Has([]byte(denom)) {
return types.FeeToken{}, errorsmod.Wrapf(types.ErrInvalidFeeToken, "%s", denom)
}
bz := prefixStore.Get([]byte(denom))
feeToken := types.FeeToken{}
err := proto.Unmarshal(bz, &feeToken)
if err != nil {
return types.FeeToken{}, err
}
return feeToken, nil
}
// setFeeToken sets a new fee token record for a specific denom.
// PoolID is just the pool to swap rate between alt fee token and native fee token.
// If the feeToken pool ID is 0, deletes the fee Token entry.
func (k Keeper) setFeeToken(ctx sdk.Context, feeToken types.FeeToken) error {
prefixStore := k.GetFeeTokensStore(ctx)
if feeToken.PoolID == 0 {
if prefixStore.Has([]byte(feeToken.Denom)) {
prefixStore.Delete([]byte(feeToken.Denom))
}
return nil
}
err := k.ValidateFeeToken(ctx, feeToken)
if err != nil {
return err
}
bz, err := proto.Marshal(&feeToken)
if err != nil {
return err
}
prefixStore.Set([]byte(feeToken.Denom), bz)
return nil
}
func (k Keeper) GetFeeTokens(ctx sdk.Context) (feetokens []types.FeeToken) {
prefixStore := k.GetFeeTokensStore(ctx)
// this entire store just contains FeeTokens, so iterate over all entries.
iterator := prefixStore.Iterator(nil, nil)
defer iterator.Close()
feeTokens := []types.FeeToken{}
for ; iterator.Valid(); iterator.Next() {
feeToken := types.FeeToken{}
err := proto.Unmarshal(iterator.Value(), &feeToken)
if err != nil {
panic(err)
}
feeTokens = append(feeTokens, feeToken)
}
return feeTokens
}
func (k Keeper) SetFeeTokens(ctx sdk.Context, feetokens []types.FeeToken) error {
for _, feeToken := range feetokens {
err := k.setFeeToken(ctx, feeToken)
if err != nil {
return err
}
}
return nil
}