-
Notifications
You must be signed in to change notification settings - Fork 3.6k
/
keeper.go
187 lines (157 loc) · 5.87 KB
/
keeper.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
package keeper
import (
"context"
"fmt"
"cosmossdk.io/collections"
"cosmossdk.io/core/appmodule"
"cosmossdk.io/core/event"
"cosmossdk.io/math"
"cosmossdk.io/x/mint/types"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// Keeper of the mint store
type Keeper struct {
appmodule.Environment
cdc codec.BinaryCodec
bankKeeper types.BankKeeper
feeCollectorName string
// the address capable of executing a MsgUpdateParams message. Typically, this
// should be the x/gov module account.
authority string
Schema collections.Schema
Params collections.Item[types.Params]
Minter collections.Item[types.Minter]
// mintFn is used to mint new coins during BeginBlock. This function is in charge of
// minting new coins based on arbitrary logic, previously done through InflationCalculationFn.
mintFn types.MintFn
}
// NewKeeper creates a new mint Keeper instance
func NewKeeper(
cdc codec.BinaryCodec,
env appmodule.Environment,
ak types.AccountKeeper,
bk types.BankKeeper,
feeCollectorName string,
authority string,
) *Keeper {
// ensure mint module account is set
if addr := ak.GetModuleAddress(types.ModuleName); addr == nil {
panic(fmt.Sprintf("the x/%s module account has not been set", types.ModuleName))
}
sb := collections.NewSchemaBuilder(env.KVStoreService)
k := Keeper{
Environment: env,
cdc: cdc,
bankKeeper: bk,
feeCollectorName: feeCollectorName,
authority: authority,
Params: collections.NewItem(sb, types.ParamsKey, "params", codec.CollValue[types.Params](cdc)),
Minter: collections.NewItem(sb, types.MinterKey, "minter", codec.CollValue[types.Minter](cdc)),
}
schema, err := sb.Build()
if err != nil {
panic(err)
}
k.Schema = schema
return &k
}
// SetMintFn is used to mint new coins during BeginBlock. The mintFn function is in charge of
// minting new coins based on arbitrary logic, previously done through InflationCalculationFn.
func (k *Keeper) SetMintFn(mintFn types.MintFn) error {
k.mintFn = mintFn
return nil
}
// GetAuthority returns the x/mint module's authority.
func (k *Keeper) GetAuthority() string {
return k.authority
}
// MintCoins implements an alias call to the underlying supply keeper's
// MintCoins to be used in BeginBlocker.
func (k *Keeper) MintCoins(ctx context.Context, newCoins sdk.Coins) error {
if newCoins.Empty() {
// skip as no coins need to be minted
return nil
}
return k.bankKeeper.MintCoins(ctx, types.ModuleName, newCoins)
}
// AddCollectedFees implements an alias call to the underlying supply keeper's
// AddCollectedFees to be used in BeginBlocker.
func (k *Keeper) AddCollectedFees(ctx context.Context, fees sdk.Coins) error {
return k.bankKeeper.SendCoinsFromModuleToModule(ctx, types.ModuleName, k.feeCollectorName, fees)
}
func (k *Keeper) MintFn(ctx context.Context, minter *types.Minter, epochId string, epochNumber int64) error {
return k.mintFn(ctx, k.Environment, minter, epochId, epochNumber)
}
// DefaultMintFn returns a default mint function. It requires the Staking module and the mint keeper.
// The default Mintfn has a requirement on staking as it uses bond to calculate inflation.
func DefaultMintFn(ic types.InflationCalculationFn, staking types.StakingKeeper, k *Keeper) types.MintFn {
return func(ctx context.Context, env appmodule.Environment, minter *types.Minter, epochId string, epochNumber int64) error {
// the default mint function is called every block, so we only check if epochId is "block" which is
// a special value to indicate that this is not an epoch minting, but a regular block minting.
if epochId != "block" {
return nil
}
stakingTokenSupply, err := staking.StakingTokenSupply(ctx)
if err != nil {
return err
}
bondedRatio, err := staking.BondedRatio(ctx)
if err != nil {
return err
}
params, err := k.Params.Get(ctx)
if err != nil {
return err
}
minter.Inflation = ic(ctx, *minter, params, bondedRatio)
minter.AnnualProvisions = minter.NextAnnualProvisions(params, stakingTokenSupply)
mintedCoin := minter.BlockProvision(params)
mintedCoins := sdk.NewCoins(mintedCoin)
maxSupply := params.MaxSupply
totalSupply := stakingTokenSupply
// if maxSupply is not infinite, check against max_supply parameter
if !maxSupply.IsZero() {
if totalSupply.Add(mintedCoins.AmountOf(params.MintDenom)).GT(maxSupply) {
// calculate the difference between maxSupply and totalSupply
diff := maxSupply.Sub(totalSupply)
if diff.LTE(math.ZeroInt()) {
k.Environment.Logger.Info("max supply reached, no new tokens will be minted")
return nil
}
// mint the difference
diffCoin := sdk.NewCoin(params.MintDenom, diff)
diffCoins := sdk.NewCoins(diffCoin)
// mint coins
if err := k.MintCoins(ctx, diffCoins); err != nil {
return err
}
mintedCoins = diffCoins
}
}
// mint coins if maxSupply is infinite or total staking supply is less than maxSupply
if maxSupply.IsZero() || totalSupply.Add(mintedCoins.AmountOf(params.MintDenom)).LT(maxSupply) {
// mint coins
if err := k.MintCoins(ctx, mintedCoins); err != nil {
return err
}
}
// send the minted coins to the fee collector account
// TODO: figure out a better way to do this
err = k.AddCollectedFees(ctx, mintedCoins)
if err != nil {
return err
}
if mintedCoin.Amount.IsInt64() {
defer telemetry.ModuleSetGauge(types.ModuleName, float32(mintedCoin.Amount.Int64()), "minted_tokens")
}
return env.EventService.EventManager(ctx).EmitKV(
types.EventTypeMint,
event.NewAttribute(types.AttributeKeyBondedRatio, bondedRatio.String()),
event.NewAttribute(types.AttributeKeyInflation, minter.Inflation.String()),
event.NewAttribute(types.AttributeKeyAnnualProvisions, minter.AnnualProvisions.String()),
event.NewAttribute(sdk.AttributeKeyAmount, mintedCoin.Amount.String()),
)
}
}