feat: custom x/mint minting function (#24436)
Co-authored-by: Tyler <48813565+technicallyty@users.noreply.github.com>
This commit is contained in:
parent
2bca0bf2fa
commit
c5cbda08f2
@ -60,6 +60,8 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
||||
* x/distribution can now utilize an externally managed community pool. NOTE: this will make the message handlers for FundCommunityPool and CommunityPoolSpend error, as well as the query handler for CommunityPool.
|
||||
* (client) [#18101](https://github.com/cosmos/cosmos-sdk/pull/18101) Add a `keyring-default-keyname` in `client.toml` for specifying a default key name, and skip the need to use the `--from` flag when signing transactions.
|
||||
* (x/gov) [#24355](https://github.com/cosmos/cosmos-sdk/pull/24355) Allow users to set a custom CalculateVoteResultsAndVotingPower function to be used in govkeeper.Tally.
|
||||
* (x/mint) [#24436](https://github.com/cosmos/cosmos-sdk/pull/24436) Allow users to set a custom minting function used in the `x/mint` begin blocker.
|
||||
* The `InflationCalculationFn` argument to `mint.NewAppModule()` is now ignored and must be nil. To set a custom `InflationCalculationFn` on the default minter, use `mintkeeper.WithMintFn(mintkeeper.DefaultMintFn(customInflationFn))`.
|
||||
* (api) [#24428](https://github.com/cosmos/cosmos-sdk/pull/24428) Add block height to response headers
|
||||
|
||||
### Improvements
|
||||
|
||||
56
UPGRADING.md
56
UPGRADING.md
@ -139,6 +139,62 @@ Required wiring:
|
||||
- entry in SetGenesisModuleOrder
|
||||
- entry in SetExportModuleOrder **before `x/bank`**
|
||||
|
||||
## Custom Minting Function in `x/mint`
|
||||
|
||||
This release introduces the ability to configure a custom mint function in `x/mint`. The minting logic is now abstracted as a `MintFn` with a default implementation that can be overridden.
|
||||
|
||||
### What’s New
|
||||
|
||||
- **Configurable Mint Function:**
|
||||
A new `MintFn` abstraction is introduced. By default, the module uses `DefaultMintFn`, but you can supply your own implementation.
|
||||
|
||||
- **Deprecated InflationCalculationFn Parameter:**
|
||||
The `InflationCalculationFn` argument previously provided to `mint.NewAppModule()` is now ignored and must be `nil`. To customize the default minter’s inflation behavior, wrap your custom function with `mintkeeper.DefaultMintFn` and pass it via the `WithMintFn` option:
|
||||
|
||||
```go
|
||||
mintkeeper.WithMintFn(mintkeeper.DefaultMintFn(customInflationFn))
|
||||
```
|
||||
|
||||
### How to Upgrade
|
||||
|
||||
1. **Using the Default Minting Function**
|
||||
|
||||
No action is needed if you’re happy with the default behavior. Make sure your application wiring initializes the MintKeeper like this:
|
||||
|
||||
```go
|
||||
mintKeeper := mintkeeper.NewKeeper(
|
||||
appCodec,
|
||||
storeService,
|
||||
stakingKeeper,
|
||||
accountKeeper,
|
||||
bankKeeper,
|
||||
authtypes.FeeCollectorName,
|
||||
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
|
||||
)
|
||||
```
|
||||
|
||||
2. **Using a Custom Minting Function**
|
||||
|
||||
To use a custom minting function, define it as follows and pass it you your mintKeeper when constructing it:
|
||||
|
||||
```go
|
||||
func myCustomMintFunc(ctx sdk.Context, k *mintkeeper.Keeper) {
|
||||
// do minting...
|
||||
}
|
||||
|
||||
// ...
|
||||
mintKeeper := mintkeeper.NewKeeper(
|
||||
appCodec,
|
||||
storeService,
|
||||
stakingKeeper,
|
||||
accountKeeper,
|
||||
bankKeeper,
|
||||
authtypes.FeeCollectorName,
|
||||
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
|
||||
mintkeeper.WithMintFn(myCustomMintFunc), // Use custom minting function
|
||||
)
|
||||
```
|
||||
|
||||
### Misc Changes
|
||||
|
||||
#### Testnet's init-files Command
|
||||
|
||||
@ -349,6 +349,7 @@ func NewSimApp(
|
||||
app.BankKeeper,
|
||||
authtypes.FeeCollectorName,
|
||||
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
|
||||
// mintkeeper.WithMintFn(mintkeeper.DefaultMintFn(minttypes.DefaultInflationCalculationFn)), custom mintFn can be added here
|
||||
)
|
||||
|
||||
app.ProtocolPoolKeeper = protocolpoolkeeper.NewKeeper(
|
||||
|
||||
@ -156,7 +156,7 @@ func NewSimApp(
|
||||
//
|
||||
|
||||
// For providing a custom inflation function for x/mint add here your
|
||||
// custom function that implements the minttypes.InflationCalculationFn
|
||||
// custom minting function that implements the mintkeeper.MintFn
|
||||
// interface.
|
||||
),
|
||||
)
|
||||
|
||||
@ -4,6 +4,8 @@ sidebar_position: 1
|
||||
|
||||
# `x/mint`
|
||||
|
||||
The `x/mint` module handles the regular minting of new tokens in a configurable manner.
|
||||
|
||||
## Contents
|
||||
|
||||
* [State](#state)
|
||||
@ -25,7 +27,7 @@ sidebar_position: 1
|
||||
|
||||
### The Minting Mechanism
|
||||
|
||||
The minting mechanism was designed to:
|
||||
The default minting mechanism was designed to:
|
||||
|
||||
* allow for a flexible inflation rate determined by market demand targeting a particular bonded-stake ratio
|
||||
* effect a balance between market liquidity and staked supply
|
||||
@ -46,6 +48,31 @@ It can be broken down in the following way:
|
||||
* If the actual percentage of bonded tokens is above the goal %-bonded the inflation rate will
|
||||
decrease until a minimum value is reached
|
||||
|
||||
### Custom Minters
|
||||
|
||||
As of Cosmos SDK v0.53.0, developers can set a custom `MintFn` for the module for specialized token minting logic.
|
||||
|
||||
The function signature that a `MintFn` must implement is as follows:
|
||||
|
||||
```go
|
||||
// MintFn defines the function that needs to be implemented in order to customize the minting process.
|
||||
type MintFn func(ctx sdk.Context, k *Keeper) error
|
||||
```
|
||||
|
||||
This can be passed to the `Keeper` upon creation with an additional `Option`:
|
||||
|
||||
```go
|
||||
app.MintKeeper = mintkeeper.NewKeeper(
|
||||
appCodec,
|
||||
runtime.NewKVStoreService(keys[minttypes.StoreKey]),
|
||||
app.StakingKeeper,
|
||||
app.AccountKeeper,
|
||||
app.BankKeeper,
|
||||
authtypes.FeeCollectorName,
|
||||
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
|
||||
// mintkeeper.WithMintFn(CUSTOM_MINT_FN), // custom mintFn can be added here
|
||||
)
|
||||
```
|
||||
|
||||
## State
|
||||
|
||||
|
||||
@ -10,66 +10,9 @@ import (
|
||||
)
|
||||
|
||||
// BeginBlocker mints new tokens for the previous block.
|
||||
func BeginBlocker(ctx context.Context, k keeper.Keeper, ic types.InflationCalculationFn) error {
|
||||
func BeginBlocker(ctx context.Context, k keeper.Keeper) error {
|
||||
defer telemetry.ModuleMeasureSince(types.ModuleName, telemetry.Now(), telemetry.MetricKeyBeginBlocker)
|
||||
|
||||
// fetch stored minter & params
|
||||
minter, err := k.Minter.Get(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
params, err := k.Params.Get(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// recalculate inflation rate
|
||||
totalStakingSupply, err := k.StakingTokenSupply(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bondedRatio, err := k.BondedRatio(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
minter.Inflation = ic(ctx, minter, params, bondedRatio)
|
||||
minter.AnnualProvisions = minter.NextAnnualProvisions(params, totalStakingSupply)
|
||||
if err = k.Minter.Set(ctx, minter); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// mint coins, update supply
|
||||
mintedCoin := minter.BlockProvision(params)
|
||||
mintedCoins := sdk.NewCoins(mintedCoin)
|
||||
|
||||
err = k.MintCoins(ctx, mintedCoins)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// send the minted coins to the fee collector account
|
||||
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")
|
||||
}
|
||||
|
||||
sdkCtx := sdk.UnwrapSDKContext(ctx)
|
||||
sdkCtx.EventManager().EmitEvent(
|
||||
sdk.NewEvent(
|
||||
types.EventTypeMint,
|
||||
sdk.NewAttribute(types.AttributeKeyBondedRatio, bondedRatio.String()),
|
||||
sdk.NewAttribute(types.AttributeKeyInflation, minter.Inflation.String()),
|
||||
sdk.NewAttribute(types.AttributeKeyAnnualProvisions, minter.AnnualProvisions.String()),
|
||||
sdk.NewAttribute(sdk.AttributeKeyAmount, mintedCoin.Amount.String()),
|
||||
),
|
||||
)
|
||||
|
||||
return nil
|
||||
return k.MintFn(sdkCtx)
|
||||
}
|
||||
|
||||
@ -29,9 +29,24 @@ type Keeper struct {
|
||||
Schema collections.Schema
|
||||
Params collections.Item[types.Params]
|
||||
Minter collections.Item[types.Minter]
|
||||
|
||||
// mintFn is a function that encompasses all minting logic run in the x/mint begin blocker.
|
||||
mintFn MintFn
|
||||
}
|
||||
|
||||
// NewKeeper creates a new mint Keeper instance
|
||||
type InitOption func(*Keeper)
|
||||
|
||||
// WithMintFn sets a custom minting function for the x/mint keeper.
|
||||
func WithMintFn(mintFn MintFn) InitOption {
|
||||
return func(k *Keeper) {
|
||||
k.mintFn = mintFn
|
||||
}
|
||||
}
|
||||
|
||||
// NewKeeper creates a new mint Keeper instance.
|
||||
//
|
||||
// The mint keeper is always initialized with the DefaultMintFn but this can be overridden with the
|
||||
// WithMintFn option.
|
||||
func NewKeeper(
|
||||
cdc codec.BinaryCodec,
|
||||
storeService storetypes.KVStoreService,
|
||||
@ -40,6 +55,7 @@ func NewKeeper(
|
||||
bk types.BankKeeper,
|
||||
feeCollectorName string,
|
||||
authority string,
|
||||
opts ...InitOption,
|
||||
) Keeper {
|
||||
// ensure mint module account is set
|
||||
if addr := ak.GetModuleAddress(types.ModuleName); addr == nil {
|
||||
@ -56,6 +72,7 @@ func NewKeeper(
|
||||
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)),
|
||||
mintFn: DefaultMintFn(types.DefaultInflationCalculationFn),
|
||||
}
|
||||
|
||||
schema, err := sb.Build()
|
||||
@ -63,6 +80,11 @@ func NewKeeper(
|
||||
panic(err)
|
||||
}
|
||||
k.Schema = schema
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(&k)
|
||||
}
|
||||
|
||||
return k
|
||||
}
|
||||
|
||||
|
||||
80
x/mint/keeper/mint.go
Normal file
80
x/mint/keeper/mint.go
Normal file
@ -0,0 +1,80 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
"github.com/cosmos/cosmos-sdk/telemetry"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/mint/types"
|
||||
)
|
||||
|
||||
// MintFn defines the function that needs to be implemented in order to customize the minting process.
|
||||
type MintFn func(ctx sdk.Context, k *Keeper) error
|
||||
|
||||
// MintFn runs the mintFn of the keeper.
|
||||
func (k *Keeper) MintFn(ctx sdk.Context) error {
|
||||
return k.mintFn(ctx, k)
|
||||
}
|
||||
|
||||
// DefaultMintFn returns a default mint function.
|
||||
// The default MintFn has a requirement on staking as it uses bond to calculate inflation.
|
||||
func DefaultMintFn(ic types.InflationCalculationFn) MintFn {
|
||||
return func(ctx sdk.Context, k *Keeper) error {
|
||||
// fetch stored minter & params
|
||||
minter, err := k.Minter.Get(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
params, err := k.Params.Get(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// recalculate inflation rate
|
||||
totalStakingSupply, err := k.StakingTokenSupply(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bondedRatio, err := k.BondedRatio(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
minter.Inflation = ic(ctx, minter, params, bondedRatio)
|
||||
minter.AnnualProvisions = minter.NextAnnualProvisions(params, totalStakingSupply)
|
||||
if err = k.Minter.Set(ctx, minter); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// mint coins, update supply
|
||||
mintedCoin := minter.BlockProvision(params)
|
||||
mintedCoins := sdk.NewCoins(mintedCoin)
|
||||
|
||||
err = k.MintCoins(ctx, mintedCoins)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// send the minted coins to the fee collector account
|
||||
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")
|
||||
}
|
||||
|
||||
ctx.EventManager().EmitEvent(
|
||||
sdk.NewEvent(
|
||||
types.EventTypeMint,
|
||||
sdk.NewAttribute(types.AttributeKeyBondedRatio, bondedRatio.String()),
|
||||
sdk.NewAttribute(types.AttributeKeyInflation, minter.Inflation.String()),
|
||||
sdk.NewAttribute(types.AttributeKeyAnnualProvisions, minter.AnnualProvisions.String()),
|
||||
sdk.NewAttribute(sdk.AttributeKeyAmount, mintedCoin.Amount.String()),
|
||||
),
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
204
x/mint/keeper/mint_test.go
Normal file
204
x/mint/keeper/mint_test.go
Normal file
@ -0,0 +1,204 @@
|
||||
package keeper_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"slices"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
"go.uber.org/mock/gomock"
|
||||
|
||||
"cosmossdk.io/math"
|
||||
storetypes "cosmossdk.io/store/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/runtime"
|
||||
"github.com/cosmos/cosmos-sdk/testutil"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/mint"
|
||||
"github.com/cosmos/cosmos-sdk/x/mint/keeper"
|
||||
minttestutil "github.com/cosmos/cosmos-sdk/x/mint/testutil"
|
||||
"github.com/cosmos/cosmos-sdk/x/mint/types"
|
||||
)
|
||||
|
||||
// MintFnTestSuite defines the integration test suite for minting.
|
||||
type MintFnTestSuite struct {
|
||||
suite.Suite
|
||||
|
||||
mintKeeper keeper.Keeper
|
||||
ctx sdk.Context
|
||||
stakingKeeper *minttestutil.MockStakingKeeper
|
||||
bankKeeper *minttestutil.MockBankKeeper
|
||||
}
|
||||
|
||||
// TestMintFnTestSuite runs the mint test suite.
|
||||
func TestMintFnTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(MintFnTestSuite))
|
||||
}
|
||||
|
||||
// SetupTest sets up the context, KV store, and mocks.
|
||||
func (s *MintFnTestSuite) SetupTest() {
|
||||
encCfg := moduletestutil.MakeTestEncodingConfig(mint.AppModuleBasic{})
|
||||
key := storetypes.NewKVStoreKey(types.StoreKey)
|
||||
storeService := runtime.NewKVStoreService(key)
|
||||
testCtx := testutil.DefaultContextWithDB(s.T(), key, storetypes.NewTransientStoreKey("transient_test"))
|
||||
s.ctx = testCtx.Ctx
|
||||
|
||||
ctrl := gomock.NewController(s.T())
|
||||
accountKeeper := minttestutil.NewMockAccountKeeper(ctrl)
|
||||
s.bankKeeper = minttestutil.NewMockBankKeeper(ctrl)
|
||||
s.stakingKeeper = minttestutil.NewMockStakingKeeper(ctrl)
|
||||
|
||||
// Return a dummy module address for the mint module.
|
||||
accountKeeper.EXPECT().GetModuleAddress(types.ModuleName).Return(sdk.AccAddress{}).AnyTimes()
|
||||
|
||||
// Override the default mint function with our dummy inflation calculator.
|
||||
s.mintKeeper = keeper.NewKeeper(
|
||||
encCfg.Codec,
|
||||
storeService,
|
||||
s.stakingKeeper,
|
||||
accountKeeper,
|
||||
s.bankKeeper,
|
||||
authtypes.FeeCollectorName,
|
||||
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
|
||||
)
|
||||
|
||||
// Set default parameters.
|
||||
err := s.mintKeeper.Params.Set(s.ctx, types.DefaultParams())
|
||||
s.Require().NoError(err)
|
||||
|
||||
// Set a known dummy minter in the store for deterministic behavior.
|
||||
s.Require().NoError(s.mintKeeper.Minter.Set(s.ctx, types.DefaultInitialMinter()))
|
||||
}
|
||||
|
||||
// TestDefaultMintFn_Success tests the successful execution of the default mint function.
|
||||
func (s *MintFnTestSuite) TestDefaultMintFn_Success() {
|
||||
// Set the staking keeper expectations.
|
||||
stakingSupply := math.NewInt(1_000_000_000)
|
||||
bondedRatio := math.LegacyNewDecWithPrec(50, 2) // 0.50
|
||||
s.stakingKeeper.EXPECT().StakingTokenSupply(s.ctx).Return(stakingSupply, nil).Times(1)
|
||||
s.stakingKeeper.EXPECT().BondedRatio(s.ctx).Return(bondedRatio, nil).Times(1)
|
||||
|
||||
expectedCoins := sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(20)))
|
||||
|
||||
minter, err := s.mintKeeper.Minter.Get(s.ctx)
|
||||
s.Require().NoError(err)
|
||||
expectedInflation := types.DefaultInflationCalculationFn(context.TODO(), minter, types.DefaultParams(), bondedRatio)
|
||||
|
||||
// Set bank keeper expectations for minting and fee collection.
|
||||
s.bankKeeper.EXPECT().MintCoins(s.ctx, types.ModuleName, expectedCoins).Return(nil).Times(1)
|
||||
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(s.ctx, types.ModuleName, authtypes.FeeCollectorName, expectedCoins).Return(nil).Times(1)
|
||||
|
||||
// Call the mint function.
|
||||
err = s.mintKeeper.MintFn(s.ctx)
|
||||
s.Require().NoError(err)
|
||||
|
||||
// Retrieve the updated minter from storage.
|
||||
updatedMinter, err := s.mintKeeper.Minter.Get(s.ctx)
|
||||
s.Require().NoError(err)
|
||||
|
||||
// check that minter values are updated as expected
|
||||
s.Require().Equal(expectedInflation, updatedMinter.Inflation)
|
||||
s.Require().Equal(expectedInflation.MulInt(stakingSupply), updatedMinter.AnnualProvisions)
|
||||
|
||||
// Optionally, verify that a mint event has been emitted.
|
||||
events := s.ctx.EventManager().Events()
|
||||
s.Require().True(slices.ContainsFunc(events, func(event sdk.Event) bool {
|
||||
return event.Type == types.EventTypeMint
|
||||
}), "expected a mint event to be emitted")
|
||||
}
|
||||
|
||||
// customMintFn defines a custom minting function that overrides minter behavior.
|
||||
func customMintFn(ctx sdk.Context, k *keeper.Keeper) error {
|
||||
// Retrieve the current minter and parameters.
|
||||
minter, err := k.Minter.Get(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = k.Params.Get(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Custom logic: override minter values.
|
||||
minter.Inflation = math.LegacyMustNewDecFromStr("0.1")
|
||||
minter.AnnualProvisions = math.LegacyMustNewDecFromStr("200")
|
||||
if err := k.Minter.Set(ctx, minter); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Instead of the default block provision, mint a custom coin.
|
||||
mintedCoin := sdk.NewCoin("custom", math.NewInt(50))
|
||||
mintedCoins := sdk.NewCoins(mintedCoin)
|
||||
|
||||
// Execute bank keeper methods.
|
||||
if err := k.MintCoins(ctx, mintedCoins); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := k.AddCollectedFees(ctx, mintedCoins); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Emit a custom event.
|
||||
sdkCtx := sdk.UnwrapSDKContext(ctx)
|
||||
sdkCtx.EventManager().EmitEvent(sdk.NewEvent(
|
||||
"custom_mint",
|
||||
sdk.NewAttribute("custom_attribute", "true"),
|
||||
))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// TestCustomMintFn tests the custom mint function.
|
||||
func (s *MintFnTestSuite) TestCustomMintFn() {
|
||||
// Reinitialize the keeper with the custom mint function.
|
||||
encCfg := moduletestutil.MakeTestEncodingConfig(mint.AppModuleBasic{})
|
||||
key := storetypes.NewKVStoreKey(types.StoreKey)
|
||||
storeService := runtime.NewKVStoreService(key)
|
||||
s.ctx = testutil.DefaultContextWithDB(s.T(), key, storetypes.NewTransientStoreKey("transient_test")).Ctx
|
||||
|
||||
ctrl := gomock.NewController(s.T())
|
||||
accountKeeper := minttestutil.NewMockAccountKeeper(ctrl)
|
||||
// Use fresh mocks for account keeper if needed.
|
||||
accountKeeper.EXPECT().GetModuleAddress(types.ModuleName).Return(sdk.AccAddress{}).AnyTimes()
|
||||
|
||||
// Reuse the existing stakingKeeper and bankKeeper from the suite.
|
||||
s.mintKeeper = keeper.NewKeeper(
|
||||
encCfg.Codec,
|
||||
storeService,
|
||||
s.stakingKeeper,
|
||||
accountKeeper,
|
||||
s.bankKeeper,
|
||||
authtypes.FeeCollectorName,
|
||||
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
|
||||
keeper.WithMintFn(customMintFn),
|
||||
)
|
||||
|
||||
// Set default parameters and initial minter.
|
||||
err := s.mintKeeper.Params.Set(s.ctx, types.DefaultParams())
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(s.mintKeeper.Minter.Set(s.ctx, types.DefaultInitialMinter()))
|
||||
|
||||
// Expect bank keeper calls to be made for the custom minted coin.
|
||||
expectedCoins := sdk.NewCoins(sdk.NewCoin("custom", math.NewInt(50)))
|
||||
s.bankKeeper.EXPECT().MintCoins(s.ctx, types.ModuleName, expectedCoins).Return(nil).Times(1)
|
||||
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(s.ctx, types.ModuleName, authtypes.FeeCollectorName, expectedCoins).Return(nil).Times(1)
|
||||
|
||||
// Call the custom mint function.
|
||||
err = s.mintKeeper.MintFn(s.ctx)
|
||||
s.Require().NoError(err)
|
||||
|
||||
// Retrieve and verify the updated minter values.
|
||||
storedMinter, err := s.mintKeeper.Minter.Get(s.ctx)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(math.LegacyMustNewDecFromStr("0.1"), storedMinter.Inflation)
|
||||
s.Require().Equal(math.LegacyMustNewDecFromStr("200"), storedMinter.AnnualProvisions)
|
||||
|
||||
// Check that the custom mint event was emitted.
|
||||
events := s.ctx.EventManager().Events()
|
||||
s.Require().True(slices.ContainsFunc(events, func(event sdk.Event) bool {
|
||||
return event.Type == "custom_mint"
|
||||
}), "expected custom_mint event to be emitted")
|
||||
}
|
||||
@ -92,10 +92,6 @@ type AppModule struct {
|
||||
|
||||
// legacySubspace is used solely for migration of x/params managed parameters
|
||||
legacySubspace exported.Subspace
|
||||
|
||||
// inflationCalculator is used to calculate the inflation rate during BeginBlock.
|
||||
// If inflationCalculator is nil, the default inflation calculation logic is used.
|
||||
inflationCalculator types.InflationCalculationFn
|
||||
}
|
||||
|
||||
// NewAppModule creates a new AppModule object. If the InflationCalculationFn
|
||||
@ -104,19 +100,19 @@ func NewAppModule(
|
||||
cdc codec.Codec,
|
||||
keeper keeper.Keeper,
|
||||
ak types.AccountKeeper,
|
||||
// This input is unused as of Cosmos SDK v0.53 and will be removed in a future release of the Cosmos SDK.
|
||||
ic types.InflationCalculationFn,
|
||||
ss exported.Subspace,
|
||||
) AppModule {
|
||||
if ic == nil {
|
||||
ic = types.DefaultInflationCalculationFn
|
||||
if ic != nil {
|
||||
panic("inflation calculation function argument must be nil as it is no longer used. This argument will be removed in a future release of the Cosmos SDK. To set a custom inflation calculation function, use the WithMintFn option when constructing the x/mint keeper as follows: mintkeeper.WithMintFn(mintkeeper.DefaultMintFn(minttypes.DefaultInflationCalculationFn))")
|
||||
}
|
||||
|
||||
return AppModule{
|
||||
AppModuleBasic: AppModuleBasic{cdc: cdc},
|
||||
keeper: keeper,
|
||||
authKeeper: ak,
|
||||
inflationCalculator: ic,
|
||||
legacySubspace: ss,
|
||||
AppModuleBasic: AppModuleBasic{cdc: cdc},
|
||||
keeper: keeper,
|
||||
authKeeper: ak,
|
||||
legacySubspace: ss,
|
||||
}
|
||||
}
|
||||
|
||||
@ -160,7 +156,7 @@ func (AppModule) ConsensusVersion() uint64 { return ConsensusVersion }
|
||||
|
||||
// BeginBlock returns the begin blocker for the mint module.
|
||||
func (am AppModule) BeginBlock(ctx context.Context) error {
|
||||
return BeginBlocker(ctx, am.keeper, am.inflationCalculator)
|
||||
return BeginBlocker(ctx, am.keeper)
|
||||
}
|
||||
|
||||
// AppModuleSimulation functions
|
||||
@ -172,7 +168,7 @@ func (AppModule) GenerateGenesisState(simState *module.SimulationState) {
|
||||
|
||||
// ProposalMsgs returns msgs used for governance proposals for simulations.
|
||||
// migrate to ProposalMsgsX. This method is ignored when ProposalMsgsX exists and will be removed in the future.
|
||||
func (AppModule) ProposalMsgs(simState module.SimulationState) []simtypes.WeightedProposalMsg {
|
||||
func (AppModule) ProposalMsgs(_ module.SimulationState) []simtypes.WeightedProposalMsg {
|
||||
return simulation.ProposalMsgs()
|
||||
}
|
||||
|
||||
@ -204,11 +200,13 @@ func init() {
|
||||
type ModuleInputs struct {
|
||||
depinject.In
|
||||
|
||||
ModuleKey depinject.OwnModuleKey
|
||||
Config *modulev1.Module
|
||||
StoreService store.KVStoreService
|
||||
Cdc codec.Codec
|
||||
ModuleKey depinject.OwnModuleKey
|
||||
Config *modulev1.Module
|
||||
StoreService store.KVStoreService
|
||||
Cdc codec.Codec
|
||||
// Deprecated: This input is unused as of Cosmos SDK v0.53 and will be removed in a future release of the Cosmos SDK.
|
||||
InflationCalculationFn types.InflationCalculationFn `optional:"true"`
|
||||
MintFn keeper.MintFn `optional:"true"`
|
||||
|
||||
// LegacySubspace is used solely for migration of x/params managed parameters
|
||||
LegacySubspace exported.Subspace `optional:"true"`
|
||||
@ -237,6 +235,15 @@ func ProvideModule(in ModuleInputs) ModuleOutputs {
|
||||
authority = authtypes.NewModuleAddressOrBech32Address(in.Config.Authority)
|
||||
}
|
||||
|
||||
if in.InflationCalculationFn != nil {
|
||||
panic("inflation calculation function argument must be nil as it is no longer used. This argument will be removed in a future release of the Cosmos SDK. To set a custom inflation calculation function, while using depinject ")
|
||||
}
|
||||
|
||||
var opts []keeper.InitOption
|
||||
if in.MintFn != nil {
|
||||
opts = append(opts, keeper.WithMintFn(in.MintFn))
|
||||
}
|
||||
|
||||
k := keeper.NewKeeper(
|
||||
in.Cdc,
|
||||
in.StoreService,
|
||||
@ -245,10 +252,11 @@ func ProvideModule(in ModuleInputs) ModuleOutputs {
|
||||
in.BankKeeper,
|
||||
feeCollectorName,
|
||||
authority.String(),
|
||||
opts...,
|
||||
)
|
||||
|
||||
// when no inflation calculation function is provided it will use the default types.DefaultInflationCalculationFn
|
||||
m := NewAppModule(in.Cdc, k, in.AccountKeeper, in.InflationCalculationFn, in.LegacySubspace)
|
||||
m := NewAppModule(in.Cdc, k, in.AccountKeeper, nil, in.LegacySubspace)
|
||||
|
||||
return ModuleOutputs{MintKeeper: k, Module: m}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user