205 lines
7.2 KiB
Go
205 lines
7.2 KiB
Go
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")
|
|
}
|