/
feetokens.go
158 lines (127 loc) · 4.1 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
package keeper
import (
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/gogo/protobuf/proto"
"github.com/osmosis-labs/osmosis/v6/x/txfees/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.spotPriceCalculator.CalculateSpotPrice(ctx, feeToken.PoolID, feeToken.Denom, baseDenom)
if err != nil {
return sdk.Coin{}, err
}
return sdk.NewCoin(baseDenom, spotPrice.MulInt(inputFee.Amount).Ceil().RoundInt()), nil
}
// GetFeeToken returns the fee token record for a specific denom
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 sdkerrors.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.spotPriceCalculator.CalculateSpotPrice(ctx, feeToken.PoolID, feeToken.Denom, baseDenom)
return err
}
// GetFeeToken returns the 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{}, sdkerrors.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.
// 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
}