From b596a5010a094793afddcfd9cf9d9e71f9cd67d7 Mon Sep 17 00:00:00 2001 From: Haiyi Zhong Date: Tue, 28 Jan 2025 10:43:28 -0500 Subject: [PATCH 1/4] feat(distribution)!: custom fee allocation --- app/app.go | 9 +- app/keepers.go | 13 + docs/proto/proto-docs.md | 34 + .../axelar/distribution/v1beta1/events.proto | 12 + x/distribution/keeper/keeper.go | 102 ++ x/distribution/keeper/keeper_test.go | 103 ++ x/distribution/module.go | 24 + x/distribution/types/events.pb.go | 336 ++++ x/distribution/types/expected_keepers.go | 56 + x/distribution/types/mock/expected_keepers.go | 1432 +++++++++++++++++ 10 files changed, 2119 insertions(+), 2 deletions(-) create mode 100644 proto/axelar/distribution/v1beta1/events.proto create mode 100644 x/distribution/keeper/keeper.go create mode 100644 x/distribution/keeper/keeper_test.go create mode 100644 x/distribution/module.go create mode 100644 x/distribution/types/events.pb.go create mode 100644 x/distribution/types/expected_keepers.go create mode 100644 x/distribution/types/mock/expected_keepers.go diff --git a/app/app.go b/app/app.go index 58733b70a..071cd4b0b 100644 --- a/app/app.go +++ b/app/app.go @@ -107,6 +107,8 @@ import ( axelarnetKeeper "github.com/axelarnetwork/axelar-core/x/axelarnet/keeper" axelarnetTypes "github.com/axelarnetwork/axelar-core/x/axelarnet/types" axelarbankkeeper "github.com/axelarnetwork/axelar-core/x/bank/keeper" + axelardistr "github.com/axelarnetwork/axelar-core/x/distribution" + axelardistrkeeper "github.com/axelarnetwork/axelar-core/x/distribution/keeper" "github.com/axelarnetwork/axelar-core/x/evm" evmKeeper "github.com/axelarnetwork/axelar-core/x/evm/keeper" evmTypes "github.com/axelarnetwork/axelar-core/x/evm/types" @@ -238,6 +240,7 @@ func NewAxelarApp( SetKeeper(keepers, initIBCKeeper(appCodec, keys, keepers)) // set up custom axelar keepers + SetKeeper(keepers, initAxelarDistributionKeeper(keepers)) SetKeeper(keepers, initAxelarnetKeeper(appCodec, keys, keepers)) SetKeeper(keepers, initEvmKeeper(appCodec, keys, keepers)) SetKeeper(keepers, initNexusKeeper(appCodec, keys, keepers)) @@ -521,6 +524,8 @@ func initAppModules(keepers *KeeperCache, bApp *bam.BaseApp, encodingConfig axel appCodec := encodingConfig.Codec + distrAppModule := distr.NewAppModule(appCodec, *GetKeeper[distrkeeper.Keeper](keepers), GetKeeper[authkeeper.AccountKeeper](keepers), GetKeeper[bankkeeper.BaseKeeper](keepers), GetKeeper[stakingkeeper.Keeper](keepers)) + appModules := []module.AppModule{ genutil.NewAppModule(GetKeeper[authkeeper.AccountKeeper](keepers), GetKeeper[stakingkeeper.Keeper](keepers), bApp.DeliverTx, encodingConfig.TxConfig), auth.NewAppModule(appCodec, *GetKeeper[authkeeper.AccountKeeper](keepers), nil), @@ -532,7 +537,7 @@ func initAppModules(keepers *KeeperCache, bApp *bam.BaseApp, encodingConfig axel gov.NewAppModule(appCodec, *GetKeeper[govkeeper.Keeper](keepers), GetKeeper[authkeeper.AccountKeeper](keepers), GetKeeper[bankkeeper.BaseKeeper](keepers)), mint.NewAppModule(appCodec, *GetKeeper[mintkeeper.Keeper](keepers), GetKeeper[authkeeper.AccountKeeper](keepers)), slashing.NewAppModule(appCodec, *GetKeeper[slashingkeeper.Keeper](keepers), GetKeeper[authkeeper.AccountKeeper](keepers), GetKeeper[bankkeeper.BaseKeeper](keepers), GetKeeper[stakingkeeper.Keeper](keepers)), - distr.NewAppModule(appCodec, *GetKeeper[distrkeeper.Keeper](keepers), GetKeeper[authkeeper.AccountKeeper](keepers), GetKeeper[bankkeeper.BaseKeeper](keepers), GetKeeper[stakingkeeper.Keeper](keepers)), + axelardistr.NewAppModule(distrAppModule, *GetKeeper[axelardistrkeeper.Keeper](keepers)), staking.NewAppModule(appCodec, *GetKeeper[stakingkeeper.Keeper](keepers), GetKeeper[authkeeper.AccountKeeper](keepers), GetKeeper[bankkeeper.BaseKeeper](keepers)), upgrade.NewAppModule(*GetKeeper[upgradekeeper.Keeper](keepers)), evidence.NewAppModule(*GetKeeper[evidencekeeper.Keeper](keepers)), @@ -708,7 +713,7 @@ func initMessageAnteDecorators(encodingConfig axelarParams.EncodingConfig, keepe func InitModuleAccountPermissions() map[string][]string { return map[string][]string{ authtypes.FeeCollectorName: nil, - distrtypes.ModuleName: nil, + distrtypes.ModuleName: {authtypes.Burner}, minttypes.ModuleName: {authtypes.Minter}, stakingtypes.BondedPoolName: {authtypes.Burner, authtypes.Staking}, stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking}, diff --git a/app/keepers.go b/app/keepers.go index d26f25e94..5fb67e898 100644 --- a/app/keepers.go +++ b/app/keepers.go @@ -55,6 +55,7 @@ import ( axelarnetKeeper "github.com/axelarnetwork/axelar-core/x/axelarnet/keeper" axelarnetTypes "github.com/axelarnetwork/axelar-core/x/axelarnet/types" axelarbankkeeper "github.com/axelarnetwork/axelar-core/x/bank/keeper" + axelardistrkeeper "github.com/axelarnetwork/axelar-core/x/distribution/keeper" evmKeeper "github.com/axelarnetwork/axelar-core/x/evm/keeper" evmTypes "github.com/axelarnetwork/axelar-core/x/evm/types" multisigKeeper "github.com/axelarnetwork/axelar-core/x/multisig/keeper" @@ -424,6 +425,18 @@ func initDistributionKeeper(appCodec codec.Codec, keys map[string]*sdk.KVStoreKe return &distrK } +func initAxelarDistributionKeeper(keepers *KeeperCache) *axelardistrkeeper.Keeper { + axelardistrK := axelardistrkeeper.NewKeeper( + *GetKeeper[distrkeeper.Keeper](keepers), + GetKeeper[authkeeper.AccountKeeper](keepers), + GetKeeper[bankkeeper.BaseKeeper](keepers), + GetKeeper[stakingkeeper.Keeper](keepers), + authtypes.FeeCollectorName, + ) + + return &axelardistrK +} + func initMintKeeper(appCodec codec.Codec, keys map[string]*sdk.KVStoreKey, keepers *KeeperCache) *mintkeeper.Keeper { mintK := mintkeeper.NewKeeper( appCodec, diff --git a/docs/proto/proto-docs.md b/docs/proto/proto-docs.md index 13797d078..250739810 100644 --- a/docs/proto/proto-docs.md +++ b/docs/proto/proto-docs.md @@ -169,6 +169,9 @@ - [MsgService](#axelar.axelarnet.v1beta1.MsgService) - [QueryService](#axelar.axelarnet.v1beta1.QueryService) +- [axelar/distribution/v1beta1/events.proto](#axelar/distribution/v1beta1/events.proto) + - [FeeBurnedEvent](#axelar.distribution.v1beta1.FeeBurnedEvent) + - [axelar/snapshot/exported/v1beta1/types.proto](#axelar/snapshot/exported/v1beta1/types.proto) - [Participant](#axelar.snapshot.exported.v1beta1.Participant) - [Snapshot](#axelar.snapshot.exported.v1beta1.Snapshot) @@ -2824,6 +2827,37 @@ QueryService defines the gRPC querier service. + +

Top

+ +## axelar/distribution/v1beta1/events.proto + + + + + +### FeeBurnedEvent + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `coins` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | | + + + + + + + + + + + + + + +

Top

diff --git a/proto/axelar/distribution/v1beta1/events.proto b/proto/axelar/distribution/v1beta1/events.proto new file mode 100644 index 000000000..347337771 --- /dev/null +++ b/proto/axelar/distribution/v1beta1/events.proto @@ -0,0 +1,12 @@ +syntax = "proto3"; +package axelar.distribution.v1beta1; + +import "cosmos/base/v1beta1/coin.proto"; +import "gogoproto/gogo.proto"; + +option go_package = "github.com/axelarnetwork/axelar-core/x/distribution/types"; + +message FeeBurnedEvent { + repeated cosmos.base.v1beta1.Coin coins = 2 + [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; +} diff --git a/x/distribution/keeper/keeper.go b/x/distribution/keeper/keeper.go new file mode 100644 index 000000000..ccbed2271 --- /dev/null +++ b/x/distribution/keeper/keeper.go @@ -0,0 +1,102 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + distribution "github.com/cosmos/cosmos-sdk/x/distribution/keeper" + distributionTypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/axelarnetwork/axelar-core/utils/events" + "github.com/axelarnetwork/axelar-core/x/distribution/types" + "github.com/axelarnetwork/utils/funcs" +) + +// Keeper wraps the distribution keeper to customize fee allocation mechanism +type Keeper struct { + distribution.Keeper + + authKeeper types.AccountKeeper + bankKeeper types.BankKeeper + stakingKeeper types.StakingKeeper + feeCollectorName string +} + +func NewKeeper( + k distribution.Keeper, ak types.AccountKeeper, bk types.BankKeeper, + sk types.StakingKeeper, feeCollectorName string, +) Keeper { + return Keeper{ + Keeper: k, + authKeeper: ak, + bankKeeper: bk, + stakingKeeper: sk, + feeCollectorName: feeCollectorName, + } +} + +// AllocateTokens modifies the fee distribution by: +// - Allocating the community tax portion to the community pool +// - Burning all remaining tokens instead of distributing to validators +func (k Keeper) AllocateTokens( + ctx sdk.Context, _, totalPreviousPower int64, + previousProposer sdk.ConsAddress, _ []abci.VoteInfo, +) { + logger := k.Logger(ctx) + + // fetch and clear the collected fees for distribution, since this is + // called in BeginBlock, collected fees will be from the previous block + // (and distributed to the previous proposer) + feeCollector := k.authKeeper.GetModuleAccount(ctx, k.feeCollectorName) + feesCollectedInt := k.bankKeeper.GetAllBalances(ctx, feeCollector.GetAddress()) + feesCollected := sdk.NewDecCoinsFromCoins(feesCollectedInt...) + + // transfer collected fees to the distribution module account + err := k.bankKeeper.SendCoinsFromModuleToModule(ctx, k.feeCollectorName, distributionTypes.ModuleName, feesCollectedInt) + if err != nil { + panic(err) + } + + // temporary workaround to keep CanWithdrawInvariant happy + // general discussions here: https://github.com/cosmos/cosmos-sdk/issues/2906#issuecomment-441867634 + feePool := k.GetFeePool(ctx) + if totalPreviousPower == 0 { + feePool.CommunityPool = feePool.CommunityPool.Add(feesCollected...) + k.SetFeePool(ctx, feePool) + return + } + + communityTaxRate := k.GetCommunityTax(ctx) + communityPoolAmount := feesCollected.MulDecTruncate(communityTaxRate) + remaining := feesCollected.Sub(communityPoolAmount) + + // truncate the remaining coins, return remainder to community pool + feeToBurn, remainder := remaining.TruncateDecimal() + communityPoolAmount = communityPoolAmount.Add(remainder...) + + // allocate community funding + feePool.CommunityPool = feePool.CommunityPool.Add(communityPoolAmount...) + k.SetFeePool(ctx, feePool) + + // burn the rest + funcs.MustNoErr(k.bankKeeper.BurnCoins(ctx, distributionTypes.ModuleName, feeToBurn)) + events.Emit(ctx, &types.FeeBurnedEvent{ + Coins: feeToBurn, + }) + + // keep the error log from the original implementation + proposerValidator := k.stakingKeeper.ValidatorByConsAddr(ctx, previousProposer) + if proposerValidator == nil { + // previous proposer can be unknown if say, the unbonding period is 1 block, so + // e.g. a validator undelegates at block X, it's removed entirely by + // block X+1's endblock, then X+2 we need to refer to the previous + // proposer for X+1, but we've forgotten about them. + logger.Error(fmt.Sprintf( + "WARNING: Attempt to allocate proposer rewards to unknown proposer %s. "+ + "This should happen only if the proposer unbonded completely within a single block, "+ + "which generally should not happen except in exceptional circumstances (or fuzz testing). "+ + "We recommend you investigate immediately.", + previousProposer.String())) + } +} diff --git a/x/distribution/keeper/keeper_test.go b/x/distribution/keeper/keeper_test.go new file mode 100644 index 000000000..aca9bab2e --- /dev/null +++ b/x/distribution/keeper/keeper_test.go @@ -0,0 +1,103 @@ +package keeper_test + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + distribution "github.com/cosmos/cosmos-sdk/x/distribution/keeper" + distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/gogo/protobuf/proto" + "github.com/stretchr/testify/assert" + "github.com/tendermint/tendermint/libs/log" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + + "github.com/axelarnetwork/axelar-core/app/params" + "github.com/axelarnetwork/axelar-core/testutils/fake" + "github.com/axelarnetwork/axelar-core/testutils/rand" + axelarnettypes "github.com/axelarnetwork/axelar-core/x/axelarnet/exported" + "github.com/axelarnetwork/axelar-core/x/distribution/keeper" + "github.com/axelarnetwork/axelar-core/x/distribution/types" + "github.com/axelarnetwork/axelar-core/x/distribution/types/mock" + "github.com/axelarnetwork/utils/funcs" + "github.com/axelarnetwork/utils/slices" + . "github.com/axelarnetwork/utils/test" +) + +func TestAllocateTokens(t *testing.T) { + var ( + k keeper.Keeper + accBalances map[string]sdk.Coins + bk *mock.BankKeeperMock + ) + + ctx := sdk.NewContext(fake.NewMultiStore(), tmproto.Header{}, false, log.TestingLogger()) + + accBalances = map[string]sdk.Coins{ + authtypes.NewModuleAddress(authtypes.FeeCollectorName).String(): sdk.NewCoins(sdk.NewCoin(axelarnettypes.NativeAsset, sdk.NewInt(rand.PosI64()))), + } + + Given("an axelar distribution keeper", func() { + encCfg := params.MakeEncodingConfig() + subspace := paramstypes.NewSubspace(encCfg.Codec, encCfg.Amino, sdk.NewKVStoreKey(distributiontypes.StoreKey), sdk.NewKVStoreKey("tKey"), distributiontypes.ModuleName) + ak := &mock.AccountKeeperMock{ + GetModuleAccountFunc: func(ctx sdk.Context, name string) authtypes.ModuleAccountI { + return authtypes.NewEmptyModuleAccount(name) + }, + GetModuleAddressFunc: func(name string) sdk.AccAddress { + return authtypes.NewModuleAddress(name) + }, + } + bk = &mock.BankKeeperMock{ + GetAllBalancesFunc: func(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins { + return accBalances[addr.String()] + }, + SendCoinsFromModuleToModuleFunc: func(ctx sdk.Context, senderModule, recipientModule string, amt sdk.Coins) error { + senderModule = authtypes.NewModuleAddress(senderModule).String() + recipientModule = authtypes.NewModuleAddress(recipientModule).String() + + accBalances[senderModule] = accBalances[senderModule].Sub(amt) + accBalances[recipientModule] = accBalances[recipientModule].Add(amt...) + + return nil + }, + BurnCoinsFunc: func(ctx sdk.Context, name string, amt sdk.Coins) error { + acc := authtypes.NewModuleAddress(name).String() + accBalances[acc] = accBalances[acc].Sub(amt) + + return nil + }, + } + sk := &mock.StakingKeeperMock{ + ValidatorByConsAddrFunc: func(ctx sdk.Context, addr sdk.ConsAddress) stakingtypes.ValidatorI { + seed := []byte("key") + consKey := ed25519.GenPrivKeyFromSecret(seed).PubKey() + pk := secp256k1.GenPrivKeyFromSecret(seed) + valAddr := sdk.ValAddress(pk.PubKey().Address().Bytes()) + return funcs.Must(stakingtypes.NewValidator(valAddr, consKey, stakingtypes.Description{})) + }, + } + + distriK := distribution.NewKeeper(encCfg.Codec, sdk.NewKVStoreKey(distributiontypes.StoreKey), subspace, ak, bk, sk, authtypes.FeeCollectorName, map[string]bool{}) + k = keeper.NewKeeper(distriK, ak, bk, sk, authtypes.FeeCollectorName) + k.SetFeePool(ctx, distributiontypes.FeePool{CommunityPool: sdk.DecCoins{}}) + k.SetParams(ctx, distributiontypes.DefaultParams()) + }). + When("allocate token", func() { + k.AllocateTokens(ctx, 0, 1, sdk.ConsAddress{}, nil) + }). + Then("allocate to community pool and burn the rest", func(t *testing.T) { + assert.Len(t, bk.BurnCoinsCalls(), 1) + + feeBurnedType := proto.MessageName(&types.FeeBurnedEvent{}) + assert.Len(t, slices.Filter(ctx.EventManager().Events(), func(e sdk.Event) bool { + return e.Type == feeBurnedType + }), 1) + + }). + Run(t) +} diff --git a/x/distribution/module.go b/x/distribution/module.go new file mode 100644 index 000000000..ae73d7c71 --- /dev/null +++ b/x/distribution/module.go @@ -0,0 +1,24 @@ +package distribution + +import ( + "github.com/cosmos/cosmos-sdk/types/module" + distr "github.com/cosmos/cosmos-sdk/x/distribution" + + "github.com/axelarnetwork/axelar-core/x/distribution/keeper" +) + +var _ module.AppModule = AppModule{} + +type AppModule struct { + distr.AppModule + + keeper keeper.Keeper +} + +// NewAppModule creates a new AppModule object +func NewAppModule(distrAppModule distr.AppModule, keeper keeper.Keeper) AppModule { + return AppModule{ + AppModule: distrAppModule, + keeper: keeper, + } +} diff --git a/x/distribution/types/events.pb.go b/x/distribution/types/events.pb.go new file mode 100644 index 000000000..3baecb1f2 --- /dev/null +++ b/x/distribution/types/events.pb.go @@ -0,0 +1,336 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: axelar/distribution/v1beta1/events.proto + +package types + +import ( + fmt "fmt" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type FeeBurnedEvent struct { + Coins github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,2,rep,name=coins,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"coins"` +} + +func (m *FeeBurnedEvent) Reset() { *m = FeeBurnedEvent{} } +func (m *FeeBurnedEvent) String() string { return proto.CompactTextString(m) } +func (*FeeBurnedEvent) ProtoMessage() {} +func (*FeeBurnedEvent) Descriptor() ([]byte, []int) { + return fileDescriptor_a87ee8e94b3e06c2, []int{0} +} +func (m *FeeBurnedEvent) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *FeeBurnedEvent) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_FeeBurnedEvent.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *FeeBurnedEvent) XXX_Merge(src proto.Message) { + xxx_messageInfo_FeeBurnedEvent.Merge(m, src) +} +func (m *FeeBurnedEvent) XXX_Size() int { + return m.Size() +} +func (m *FeeBurnedEvent) XXX_DiscardUnknown() { + xxx_messageInfo_FeeBurnedEvent.DiscardUnknown(m) +} + +var xxx_messageInfo_FeeBurnedEvent proto.InternalMessageInfo + +func (m *FeeBurnedEvent) GetCoins() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.Coins + } + return nil +} + +func init() { + proto.RegisterType((*FeeBurnedEvent)(nil), "axelar.distribution.v1beta1.FeeBurnedEvent") +} + +func init() { + proto.RegisterFile("axelar/distribution/v1beta1/events.proto", fileDescriptor_a87ee8e94b3e06c2) +} + +var fileDescriptor_a87ee8e94b3e06c2 = []byte{ + // 255 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xd2, 0x48, 0xac, 0x48, 0xcd, + 0x49, 0x2c, 0xd2, 0x4f, 0xc9, 0x2c, 0x2e, 0x29, 0xca, 0x4c, 0x2a, 0x2d, 0xc9, 0xcc, 0xcf, 0xd3, + 0x2f, 0x33, 0x4c, 0x4a, 0x2d, 0x49, 0x34, 0xd4, 0x4f, 0x2d, 0x4b, 0xcd, 0x2b, 0x29, 0xd6, 0x2b, + 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x92, 0x86, 0xa8, 0xd4, 0x43, 0x56, 0xa9, 0x07, 0x55, 0x29, 0x25, + 0x97, 0x9c, 0x5f, 0x9c, 0x9b, 0x5f, 0xac, 0x9f, 0x94, 0x58, 0x9c, 0x0a, 0xd7, 0x9e, 0x9c, 0x9f, + 0x99, 0x07, 0xd1, 0x2c, 0x25, 0x92, 0x9e, 0x9f, 0x9e, 0x0f, 0x66, 0xea, 0x83, 0x58, 0x10, 0x51, + 0xa5, 0x62, 0x2e, 0x3e, 0xb7, 0xd4, 0x54, 0xa7, 0xd2, 0xa2, 0xbc, 0xd4, 0x14, 0x57, 0x90, 0x5d, + 0x42, 0x89, 0x5c, 0xac, 0x20, 0x5d, 0xc5, 0x12, 0x4c, 0x0a, 0xcc, 0x1a, 0xdc, 0x46, 0x92, 0x7a, + 0x10, 0x73, 0xf5, 0x40, 0xe6, 0xc2, 0x2c, 0xd3, 0x73, 0xce, 0xcf, 0xcc, 0x73, 0x32, 0x38, 0x71, + 0x4f, 0x9e, 0x61, 0xd5, 0x7d, 0x79, 0x8d, 0xf4, 0xcc, 0x92, 0x8c, 0xd2, 0x24, 0xbd, 0xe4, 0xfc, + 0x5c, 0x7d, 0xa8, 0x23, 0x20, 0x94, 0x6e, 0x71, 0x4a, 0xb6, 0x7e, 0x49, 0x65, 0x41, 0x6a, 0x31, + 0x58, 0x43, 0x71, 0x10, 0xc4, 0x64, 0xa7, 0xe0, 0x13, 0x8f, 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, + 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x0b, 0x8f, 0xe5, 0x18, 0x6e, 0x3c, 0x96, + 0x63, 0x88, 0xb2, 0x44, 0x32, 0x0a, 0xe2, 0xd9, 0xbc, 0xd4, 0x92, 0xf2, 0xfc, 0xa2, 0x6c, 0x28, + 0x4f, 0x37, 0x39, 0xbf, 0x28, 0x55, 0xbf, 0x02, 0x35, 0xac, 0xc0, 0x36, 0x24, 0xb1, 0x81, 0x3d, + 0x64, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x3e, 0xe1, 0x56, 0x01, 0x4f, 0x01, 0x00, 0x00, +} + +func (m *FeeBurnedEvent) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *FeeBurnedEvent) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *FeeBurnedEvent) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Coins) > 0 { + for iNdEx := len(m.Coins) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Coins[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + return len(dAtA) - i, nil +} + +func encodeVarintEvents(dAtA []byte, offset int, v uint64) int { + offset -= sovEvents(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *FeeBurnedEvent) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Coins) > 0 { + for _, e := range m.Coins { + l = e.Size() + n += 1 + l + sovEvents(uint64(l)) + } + } + return n +} + +func sovEvents(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozEvents(x uint64) (n int) { + return sovEvents(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *FeeBurnedEvent) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: FeeBurnedEvent: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: FeeBurnedEvent: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Coins", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Coins = append(m.Coins, types.Coin{}) + if err := m.Coins[len(m.Coins)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvents(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvents + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipEvents(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowEvents + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowEvents + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowEvents + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthEvents + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupEvents + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthEvents + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthEvents = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowEvents = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupEvents = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/distribution/types/expected_keepers.go b/x/distribution/types/expected_keepers.go new file mode 100644 index 000000000..6789e99e2 --- /dev/null +++ b/x/distribution/types/expected_keepers.go @@ -0,0 +1,56 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/cosmos/cosmos-sdk/x/distribution/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +//go:generate moq -pkg mock -out ./mock/expected_keepers.go . BankKeeper AccountKeeper StakingKeeper + +// BankKeeper provides functionality to the bank module +type BankKeeper interface { + types.BankKeeper + BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error +} + +type AccountKeeper interface { + GetAccount(ctx sdk.Context, addr sdk.AccAddress) authtypes.AccountI + + GetModuleAddress(name string) sdk.AccAddress + GetModuleAccount(ctx sdk.Context, name string) authtypes.ModuleAccountI + + SetModuleAccount(sdk.Context, authtypes.ModuleAccountI) +} + +// StakingKeeper expected staking keeper (noalias) +type StakingKeeper interface { + IterateValidators(sdk.Context, + func(index int64, validator stakingtypes.ValidatorI) (stop bool)) + + IterateBondedValidatorsByPower(sdk.Context, + func(index int64, validator stakingtypes.ValidatorI) (stop bool)) + + IterateLastValidators(sdk.Context, + func(index int64, validator stakingtypes.ValidatorI) (stop bool)) + + Validator(sdk.Context, sdk.ValAddress) stakingtypes.ValidatorI + ValidatorByConsAddr(sdk.Context, sdk.ConsAddress) stakingtypes.ValidatorI + + Slash(sdk.Context, sdk.ConsAddress, int64, int64, sdk.Dec) + Jail(sdk.Context, sdk.ConsAddress) + Unjail(sdk.Context, sdk.ConsAddress) + + Delegation(sdk.Context, sdk.AccAddress, sdk.ValAddress) stakingtypes.DelegationI + + MaxValidators(sdk.Context) uint32 + + IterateDelegations(ctx sdk.Context, delegator sdk.AccAddress, + fn func(index int64, delegation stakingtypes.DelegationI) (stop bool)) + + GetLastTotalPower(ctx sdk.Context) sdk.Int + GetLastValidatorPower(ctx sdk.Context, valAddr sdk.ValAddress) int64 + + GetAllSDKDelegations(ctx sdk.Context) []stakingtypes.Delegation +} diff --git a/x/distribution/types/mock/expected_keepers.go b/x/distribution/types/mock/expected_keepers.go new file mode 100644 index 000000000..f003ef430 --- /dev/null +++ b/x/distribution/types/mock/expected_keepers.go @@ -0,0 +1,1432 @@ +// Code generated by moq; DO NOT EDIT. +// github.com/matryer/moq + +package mock + +import ( + "github.com/axelarnetwork/axelar-core/x/distribution/types" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "sync" +) + +// Ensure, that BankKeeperMock does implement types.BankKeeper. +// If this is not the case, regenerate this file with moq. +var _ types.BankKeeper = &BankKeeperMock{} + +// BankKeeperMock is a mock implementation of types.BankKeeper. +// +// func TestSomethingThatUsesBankKeeper(t *testing.T) { +// +// // make and configure a mocked types.BankKeeper +// mockedBankKeeper := &BankKeeperMock{ +// BurnCoinsFunc: func(ctx sdk.Context, moduleName string, amt sdk.Coins) error { +// panic("mock out the BurnCoins method") +// }, +// GetAllBalancesFunc: func(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins { +// panic("mock out the GetAllBalances method") +// }, +// GetBalanceFunc: func(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin { +// panic("mock out the GetBalance method") +// }, +// LockedCoinsFunc: func(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins { +// panic("mock out the LockedCoins method") +// }, +// SendCoinsFromAccountToModuleFunc: func(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error { +// panic("mock out the SendCoinsFromAccountToModule method") +// }, +// SendCoinsFromModuleToAccountFunc: func(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error { +// panic("mock out the SendCoinsFromModuleToAccount method") +// }, +// SendCoinsFromModuleToModuleFunc: func(ctx sdk.Context, senderModule string, recipientModule string, amt sdk.Coins) error { +// panic("mock out the SendCoinsFromModuleToModule method") +// }, +// SpendableCoinsFunc: func(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins { +// panic("mock out the SpendableCoins method") +// }, +// } +// +// // use mockedBankKeeper in code that requires types.BankKeeper +// // and then make assertions. +// +// } +type BankKeeperMock struct { + // BurnCoinsFunc mocks the BurnCoins method. + BurnCoinsFunc func(ctx sdk.Context, moduleName string, amt sdk.Coins) error + + // GetAllBalancesFunc mocks the GetAllBalances method. + GetAllBalancesFunc func(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + + // GetBalanceFunc mocks the GetBalance method. + GetBalanceFunc func(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin + + // LockedCoinsFunc mocks the LockedCoins method. + LockedCoinsFunc func(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + + // SendCoinsFromAccountToModuleFunc mocks the SendCoinsFromAccountToModule method. + SendCoinsFromAccountToModuleFunc func(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error + + // SendCoinsFromModuleToAccountFunc mocks the SendCoinsFromModuleToAccount method. + SendCoinsFromModuleToAccountFunc func(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error + + // SendCoinsFromModuleToModuleFunc mocks the SendCoinsFromModuleToModule method. + SendCoinsFromModuleToModuleFunc func(ctx sdk.Context, senderModule string, recipientModule string, amt sdk.Coins) error + + // SpendableCoinsFunc mocks the SpendableCoins method. + SpendableCoinsFunc func(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + + // calls tracks calls to the methods. + calls struct { + // BurnCoins holds details about calls to the BurnCoins method. + BurnCoins []struct { + // Ctx is the ctx argument value. + Ctx sdk.Context + // ModuleName is the moduleName argument value. + ModuleName string + // Amt is the amt argument value. + Amt sdk.Coins + } + // GetAllBalances holds details about calls to the GetAllBalances method. + GetAllBalances []struct { + // Ctx is the ctx argument value. + Ctx sdk.Context + // Addr is the addr argument value. + Addr sdk.AccAddress + } + // GetBalance holds details about calls to the GetBalance method. + GetBalance []struct { + // Ctx is the ctx argument value. + Ctx sdk.Context + // Addr is the addr argument value. + Addr sdk.AccAddress + // Denom is the denom argument value. + Denom string + } + // LockedCoins holds details about calls to the LockedCoins method. + LockedCoins []struct { + // Ctx is the ctx argument value. + Ctx sdk.Context + // Addr is the addr argument value. + Addr sdk.AccAddress + } + // SendCoinsFromAccountToModule holds details about calls to the SendCoinsFromAccountToModule method. + SendCoinsFromAccountToModule []struct { + // Ctx is the ctx argument value. + Ctx sdk.Context + // SenderAddr is the senderAddr argument value. + SenderAddr sdk.AccAddress + // RecipientModule is the recipientModule argument value. + RecipientModule string + // Amt is the amt argument value. + Amt sdk.Coins + } + // SendCoinsFromModuleToAccount holds details about calls to the SendCoinsFromModuleToAccount method. + SendCoinsFromModuleToAccount []struct { + // Ctx is the ctx argument value. + Ctx sdk.Context + // SenderModule is the senderModule argument value. + SenderModule string + // RecipientAddr is the recipientAddr argument value. + RecipientAddr sdk.AccAddress + // Amt is the amt argument value. + Amt sdk.Coins + } + // SendCoinsFromModuleToModule holds details about calls to the SendCoinsFromModuleToModule method. + SendCoinsFromModuleToModule []struct { + // Ctx is the ctx argument value. + Ctx sdk.Context + // SenderModule is the senderModule argument value. + SenderModule string + // RecipientModule is the recipientModule argument value. + RecipientModule string + // Amt is the amt argument value. + Amt sdk.Coins + } + // SpendableCoins holds details about calls to the SpendableCoins method. + SpendableCoins []struct { + // Ctx is the ctx argument value. + Ctx sdk.Context + // Addr is the addr argument value. + Addr sdk.AccAddress + } + } + lockBurnCoins sync.RWMutex + lockGetAllBalances sync.RWMutex + lockGetBalance sync.RWMutex + lockLockedCoins sync.RWMutex + lockSendCoinsFromAccountToModule sync.RWMutex + lockSendCoinsFromModuleToAccount sync.RWMutex + lockSendCoinsFromModuleToModule sync.RWMutex + lockSpendableCoins sync.RWMutex +} + +// BurnCoins calls BurnCoinsFunc. +func (mock *BankKeeperMock) BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error { + if mock.BurnCoinsFunc == nil { + panic("BankKeeperMock.BurnCoinsFunc: method is nil but BankKeeper.BurnCoins was just called") + } + callInfo := struct { + Ctx sdk.Context + ModuleName string + Amt sdk.Coins + }{ + Ctx: ctx, + ModuleName: moduleName, + Amt: amt, + } + mock.lockBurnCoins.Lock() + mock.calls.BurnCoins = append(mock.calls.BurnCoins, callInfo) + mock.lockBurnCoins.Unlock() + return mock.BurnCoinsFunc(ctx, moduleName, amt) +} + +// BurnCoinsCalls gets all the calls that were made to BurnCoins. +// Check the length with: +// +// len(mockedBankKeeper.BurnCoinsCalls()) +func (mock *BankKeeperMock) BurnCoinsCalls() []struct { + Ctx sdk.Context + ModuleName string + Amt sdk.Coins +} { + var calls []struct { + Ctx sdk.Context + ModuleName string + Amt sdk.Coins + } + mock.lockBurnCoins.RLock() + calls = mock.calls.BurnCoins + mock.lockBurnCoins.RUnlock() + return calls +} + +// GetAllBalances calls GetAllBalancesFunc. +func (mock *BankKeeperMock) GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins { + if mock.GetAllBalancesFunc == nil { + panic("BankKeeperMock.GetAllBalancesFunc: method is nil but BankKeeper.GetAllBalances was just called") + } + callInfo := struct { + Ctx sdk.Context + Addr sdk.AccAddress + }{ + Ctx: ctx, + Addr: addr, + } + mock.lockGetAllBalances.Lock() + mock.calls.GetAllBalances = append(mock.calls.GetAllBalances, callInfo) + mock.lockGetAllBalances.Unlock() + return mock.GetAllBalancesFunc(ctx, addr) +} + +// GetAllBalancesCalls gets all the calls that were made to GetAllBalances. +// Check the length with: +// +// len(mockedBankKeeper.GetAllBalancesCalls()) +func (mock *BankKeeperMock) GetAllBalancesCalls() []struct { + Ctx sdk.Context + Addr sdk.AccAddress +} { + var calls []struct { + Ctx sdk.Context + Addr sdk.AccAddress + } + mock.lockGetAllBalances.RLock() + calls = mock.calls.GetAllBalances + mock.lockGetAllBalances.RUnlock() + return calls +} + +// GetBalance calls GetBalanceFunc. +func (mock *BankKeeperMock) GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin { + if mock.GetBalanceFunc == nil { + panic("BankKeeperMock.GetBalanceFunc: method is nil but BankKeeper.GetBalance was just called") + } + callInfo := struct { + Ctx sdk.Context + Addr sdk.AccAddress + Denom string + }{ + Ctx: ctx, + Addr: addr, + Denom: denom, + } + mock.lockGetBalance.Lock() + mock.calls.GetBalance = append(mock.calls.GetBalance, callInfo) + mock.lockGetBalance.Unlock() + return mock.GetBalanceFunc(ctx, addr, denom) +} + +// GetBalanceCalls gets all the calls that were made to GetBalance. +// Check the length with: +// +// len(mockedBankKeeper.GetBalanceCalls()) +func (mock *BankKeeperMock) GetBalanceCalls() []struct { + Ctx sdk.Context + Addr sdk.AccAddress + Denom string +} { + var calls []struct { + Ctx sdk.Context + Addr sdk.AccAddress + Denom string + } + mock.lockGetBalance.RLock() + calls = mock.calls.GetBalance + mock.lockGetBalance.RUnlock() + return calls +} + +// LockedCoins calls LockedCoinsFunc. +func (mock *BankKeeperMock) LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins { + if mock.LockedCoinsFunc == nil { + panic("BankKeeperMock.LockedCoinsFunc: method is nil but BankKeeper.LockedCoins was just called") + } + callInfo := struct { + Ctx sdk.Context + Addr sdk.AccAddress + }{ + Ctx: ctx, + Addr: addr, + } + mock.lockLockedCoins.Lock() + mock.calls.LockedCoins = append(mock.calls.LockedCoins, callInfo) + mock.lockLockedCoins.Unlock() + return mock.LockedCoinsFunc(ctx, addr) +} + +// LockedCoinsCalls gets all the calls that were made to LockedCoins. +// Check the length with: +// +// len(mockedBankKeeper.LockedCoinsCalls()) +func (mock *BankKeeperMock) LockedCoinsCalls() []struct { + Ctx sdk.Context + Addr sdk.AccAddress +} { + var calls []struct { + Ctx sdk.Context + Addr sdk.AccAddress + } + mock.lockLockedCoins.RLock() + calls = mock.calls.LockedCoins + mock.lockLockedCoins.RUnlock() + return calls +} + +// SendCoinsFromAccountToModule calls SendCoinsFromAccountToModuleFunc. +func (mock *BankKeeperMock) SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error { + if mock.SendCoinsFromAccountToModuleFunc == nil { + panic("BankKeeperMock.SendCoinsFromAccountToModuleFunc: method is nil but BankKeeper.SendCoinsFromAccountToModule was just called") + } + callInfo := struct { + Ctx sdk.Context + SenderAddr sdk.AccAddress + RecipientModule string + Amt sdk.Coins + }{ + Ctx: ctx, + SenderAddr: senderAddr, + RecipientModule: recipientModule, + Amt: amt, + } + mock.lockSendCoinsFromAccountToModule.Lock() + mock.calls.SendCoinsFromAccountToModule = append(mock.calls.SendCoinsFromAccountToModule, callInfo) + mock.lockSendCoinsFromAccountToModule.Unlock() + return mock.SendCoinsFromAccountToModuleFunc(ctx, senderAddr, recipientModule, amt) +} + +// SendCoinsFromAccountToModuleCalls gets all the calls that were made to SendCoinsFromAccountToModule. +// Check the length with: +// +// len(mockedBankKeeper.SendCoinsFromAccountToModuleCalls()) +func (mock *BankKeeperMock) SendCoinsFromAccountToModuleCalls() []struct { + Ctx sdk.Context + SenderAddr sdk.AccAddress + RecipientModule string + Amt sdk.Coins +} { + var calls []struct { + Ctx sdk.Context + SenderAddr sdk.AccAddress + RecipientModule string + Amt sdk.Coins + } + mock.lockSendCoinsFromAccountToModule.RLock() + calls = mock.calls.SendCoinsFromAccountToModule + mock.lockSendCoinsFromAccountToModule.RUnlock() + return calls +} + +// SendCoinsFromModuleToAccount calls SendCoinsFromModuleToAccountFunc. +func (mock *BankKeeperMock) SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error { + if mock.SendCoinsFromModuleToAccountFunc == nil { + panic("BankKeeperMock.SendCoinsFromModuleToAccountFunc: method is nil but BankKeeper.SendCoinsFromModuleToAccount was just called") + } + callInfo := struct { + Ctx sdk.Context + SenderModule string + RecipientAddr sdk.AccAddress + Amt sdk.Coins + }{ + Ctx: ctx, + SenderModule: senderModule, + RecipientAddr: recipientAddr, + Amt: amt, + } + mock.lockSendCoinsFromModuleToAccount.Lock() + mock.calls.SendCoinsFromModuleToAccount = append(mock.calls.SendCoinsFromModuleToAccount, callInfo) + mock.lockSendCoinsFromModuleToAccount.Unlock() + return mock.SendCoinsFromModuleToAccountFunc(ctx, senderModule, recipientAddr, amt) +} + +// SendCoinsFromModuleToAccountCalls gets all the calls that were made to SendCoinsFromModuleToAccount. +// Check the length with: +// +// len(mockedBankKeeper.SendCoinsFromModuleToAccountCalls()) +func (mock *BankKeeperMock) SendCoinsFromModuleToAccountCalls() []struct { + Ctx sdk.Context + SenderModule string + RecipientAddr sdk.AccAddress + Amt sdk.Coins +} { + var calls []struct { + Ctx sdk.Context + SenderModule string + RecipientAddr sdk.AccAddress + Amt sdk.Coins + } + mock.lockSendCoinsFromModuleToAccount.RLock() + calls = mock.calls.SendCoinsFromModuleToAccount + mock.lockSendCoinsFromModuleToAccount.RUnlock() + return calls +} + +// SendCoinsFromModuleToModule calls SendCoinsFromModuleToModuleFunc. +func (mock *BankKeeperMock) SendCoinsFromModuleToModule(ctx sdk.Context, senderModule string, recipientModule string, amt sdk.Coins) error { + if mock.SendCoinsFromModuleToModuleFunc == nil { + panic("BankKeeperMock.SendCoinsFromModuleToModuleFunc: method is nil but BankKeeper.SendCoinsFromModuleToModule was just called") + } + callInfo := struct { + Ctx sdk.Context + SenderModule string + RecipientModule string + Amt sdk.Coins + }{ + Ctx: ctx, + SenderModule: senderModule, + RecipientModule: recipientModule, + Amt: amt, + } + mock.lockSendCoinsFromModuleToModule.Lock() + mock.calls.SendCoinsFromModuleToModule = append(mock.calls.SendCoinsFromModuleToModule, callInfo) + mock.lockSendCoinsFromModuleToModule.Unlock() + return mock.SendCoinsFromModuleToModuleFunc(ctx, senderModule, recipientModule, amt) +} + +// SendCoinsFromModuleToModuleCalls gets all the calls that were made to SendCoinsFromModuleToModule. +// Check the length with: +// +// len(mockedBankKeeper.SendCoinsFromModuleToModuleCalls()) +func (mock *BankKeeperMock) SendCoinsFromModuleToModuleCalls() []struct { + Ctx sdk.Context + SenderModule string + RecipientModule string + Amt sdk.Coins +} { + var calls []struct { + Ctx sdk.Context + SenderModule string + RecipientModule string + Amt sdk.Coins + } + mock.lockSendCoinsFromModuleToModule.RLock() + calls = mock.calls.SendCoinsFromModuleToModule + mock.lockSendCoinsFromModuleToModule.RUnlock() + return calls +} + +// SpendableCoins calls SpendableCoinsFunc. +func (mock *BankKeeperMock) SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins { + if mock.SpendableCoinsFunc == nil { + panic("BankKeeperMock.SpendableCoinsFunc: method is nil but BankKeeper.SpendableCoins was just called") + } + callInfo := struct { + Ctx sdk.Context + Addr sdk.AccAddress + }{ + Ctx: ctx, + Addr: addr, + } + mock.lockSpendableCoins.Lock() + mock.calls.SpendableCoins = append(mock.calls.SpendableCoins, callInfo) + mock.lockSpendableCoins.Unlock() + return mock.SpendableCoinsFunc(ctx, addr) +} + +// SpendableCoinsCalls gets all the calls that were made to SpendableCoins. +// Check the length with: +// +// len(mockedBankKeeper.SpendableCoinsCalls()) +func (mock *BankKeeperMock) SpendableCoinsCalls() []struct { + Ctx sdk.Context + Addr sdk.AccAddress +} { + var calls []struct { + Ctx sdk.Context + Addr sdk.AccAddress + } + mock.lockSpendableCoins.RLock() + calls = mock.calls.SpendableCoins + mock.lockSpendableCoins.RUnlock() + return calls +} + +// Ensure, that AccountKeeperMock does implement types.AccountKeeper. +// If this is not the case, regenerate this file with moq. +var _ types.AccountKeeper = &AccountKeeperMock{} + +// AccountKeeperMock is a mock implementation of types.AccountKeeper. +// +// func TestSomethingThatUsesAccountKeeper(t *testing.T) { +// +// // make and configure a mocked types.AccountKeeper +// mockedAccountKeeper := &AccountKeeperMock{ +// GetAccountFunc: func(ctx sdk.Context, addr sdk.AccAddress) authtypes.AccountI { +// panic("mock out the GetAccount method") +// }, +// GetModuleAccountFunc: func(ctx sdk.Context, name string) authtypes.ModuleAccountI { +// panic("mock out the GetModuleAccount method") +// }, +// GetModuleAddressFunc: func(name string) sdk.AccAddress { +// panic("mock out the GetModuleAddress method") +// }, +// SetModuleAccountFunc: func(context sdk.Context, moduleAccountI authtypes.ModuleAccountI) { +// panic("mock out the SetModuleAccount method") +// }, +// } +// +// // use mockedAccountKeeper in code that requires types.AccountKeeper +// // and then make assertions. +// +// } +type AccountKeeperMock struct { + // GetAccountFunc mocks the GetAccount method. + GetAccountFunc func(ctx sdk.Context, addr sdk.AccAddress) authtypes.AccountI + + // GetModuleAccountFunc mocks the GetModuleAccount method. + GetModuleAccountFunc func(ctx sdk.Context, name string) authtypes.ModuleAccountI + + // GetModuleAddressFunc mocks the GetModuleAddress method. + GetModuleAddressFunc func(name string) sdk.AccAddress + + // SetModuleAccountFunc mocks the SetModuleAccount method. + SetModuleAccountFunc func(context sdk.Context, moduleAccountI authtypes.ModuleAccountI) + + // calls tracks calls to the methods. + calls struct { + // GetAccount holds details about calls to the GetAccount method. + GetAccount []struct { + // Ctx is the ctx argument value. + Ctx sdk.Context + // Addr is the addr argument value. + Addr sdk.AccAddress + } + // GetModuleAccount holds details about calls to the GetModuleAccount method. + GetModuleAccount []struct { + // Ctx is the ctx argument value. + Ctx sdk.Context + // Name is the name argument value. + Name string + } + // GetModuleAddress holds details about calls to the GetModuleAddress method. + GetModuleAddress []struct { + // Name is the name argument value. + Name string + } + // SetModuleAccount holds details about calls to the SetModuleAccount method. + SetModuleAccount []struct { + // Context is the context argument value. + Context sdk.Context + // ModuleAccountI is the moduleAccountI argument value. + ModuleAccountI authtypes.ModuleAccountI + } + } + lockGetAccount sync.RWMutex + lockGetModuleAccount sync.RWMutex + lockGetModuleAddress sync.RWMutex + lockSetModuleAccount sync.RWMutex +} + +// GetAccount calls GetAccountFunc. +func (mock *AccountKeeperMock) GetAccount(ctx sdk.Context, addr sdk.AccAddress) authtypes.AccountI { + if mock.GetAccountFunc == nil { + panic("AccountKeeperMock.GetAccountFunc: method is nil but AccountKeeper.GetAccount was just called") + } + callInfo := struct { + Ctx sdk.Context + Addr sdk.AccAddress + }{ + Ctx: ctx, + Addr: addr, + } + mock.lockGetAccount.Lock() + mock.calls.GetAccount = append(mock.calls.GetAccount, callInfo) + mock.lockGetAccount.Unlock() + return mock.GetAccountFunc(ctx, addr) +} + +// GetAccountCalls gets all the calls that were made to GetAccount. +// Check the length with: +// +// len(mockedAccountKeeper.GetAccountCalls()) +func (mock *AccountKeeperMock) GetAccountCalls() []struct { + Ctx sdk.Context + Addr sdk.AccAddress +} { + var calls []struct { + Ctx sdk.Context + Addr sdk.AccAddress + } + mock.lockGetAccount.RLock() + calls = mock.calls.GetAccount + mock.lockGetAccount.RUnlock() + return calls +} + +// GetModuleAccount calls GetModuleAccountFunc. +func (mock *AccountKeeperMock) GetModuleAccount(ctx sdk.Context, name string) authtypes.ModuleAccountI { + if mock.GetModuleAccountFunc == nil { + panic("AccountKeeperMock.GetModuleAccountFunc: method is nil but AccountKeeper.GetModuleAccount was just called") + } + callInfo := struct { + Ctx sdk.Context + Name string + }{ + Ctx: ctx, + Name: name, + } + mock.lockGetModuleAccount.Lock() + mock.calls.GetModuleAccount = append(mock.calls.GetModuleAccount, callInfo) + mock.lockGetModuleAccount.Unlock() + return mock.GetModuleAccountFunc(ctx, name) +} + +// GetModuleAccountCalls gets all the calls that were made to GetModuleAccount. +// Check the length with: +// +// len(mockedAccountKeeper.GetModuleAccountCalls()) +func (mock *AccountKeeperMock) GetModuleAccountCalls() []struct { + Ctx sdk.Context + Name string +} { + var calls []struct { + Ctx sdk.Context + Name string + } + mock.lockGetModuleAccount.RLock() + calls = mock.calls.GetModuleAccount + mock.lockGetModuleAccount.RUnlock() + return calls +} + +// GetModuleAddress calls GetModuleAddressFunc. +func (mock *AccountKeeperMock) GetModuleAddress(name string) sdk.AccAddress { + if mock.GetModuleAddressFunc == nil { + panic("AccountKeeperMock.GetModuleAddressFunc: method is nil but AccountKeeper.GetModuleAddress was just called") + } + callInfo := struct { + Name string + }{ + Name: name, + } + mock.lockGetModuleAddress.Lock() + mock.calls.GetModuleAddress = append(mock.calls.GetModuleAddress, callInfo) + mock.lockGetModuleAddress.Unlock() + return mock.GetModuleAddressFunc(name) +} + +// GetModuleAddressCalls gets all the calls that were made to GetModuleAddress. +// Check the length with: +// +// len(mockedAccountKeeper.GetModuleAddressCalls()) +func (mock *AccountKeeperMock) GetModuleAddressCalls() []struct { + Name string +} { + var calls []struct { + Name string + } + mock.lockGetModuleAddress.RLock() + calls = mock.calls.GetModuleAddress + mock.lockGetModuleAddress.RUnlock() + return calls +} + +// SetModuleAccount calls SetModuleAccountFunc. +func (mock *AccountKeeperMock) SetModuleAccount(context sdk.Context, moduleAccountI authtypes.ModuleAccountI) { + if mock.SetModuleAccountFunc == nil { + panic("AccountKeeperMock.SetModuleAccountFunc: method is nil but AccountKeeper.SetModuleAccount was just called") + } + callInfo := struct { + Context sdk.Context + ModuleAccountI authtypes.ModuleAccountI + }{ + Context: context, + ModuleAccountI: moduleAccountI, + } + mock.lockSetModuleAccount.Lock() + mock.calls.SetModuleAccount = append(mock.calls.SetModuleAccount, callInfo) + mock.lockSetModuleAccount.Unlock() + mock.SetModuleAccountFunc(context, moduleAccountI) +} + +// SetModuleAccountCalls gets all the calls that were made to SetModuleAccount. +// Check the length with: +// +// len(mockedAccountKeeper.SetModuleAccountCalls()) +func (mock *AccountKeeperMock) SetModuleAccountCalls() []struct { + Context sdk.Context + ModuleAccountI authtypes.ModuleAccountI +} { + var calls []struct { + Context sdk.Context + ModuleAccountI authtypes.ModuleAccountI + } + mock.lockSetModuleAccount.RLock() + calls = mock.calls.SetModuleAccount + mock.lockSetModuleAccount.RUnlock() + return calls +} + +// Ensure, that StakingKeeperMock does implement types.StakingKeeper. +// If this is not the case, regenerate this file with moq. +var _ types.StakingKeeper = &StakingKeeperMock{} + +// StakingKeeperMock is a mock implementation of types.StakingKeeper. +// +// func TestSomethingThatUsesStakingKeeper(t *testing.T) { +// +// // make and configure a mocked types.StakingKeeper +// mockedStakingKeeper := &StakingKeeperMock{ +// DelegationFunc: func(context sdk.Context, accAddress sdk.AccAddress, valAddress sdk.ValAddress) stakingtypes.DelegationI { +// panic("mock out the Delegation method") +// }, +// GetAllSDKDelegationsFunc: func(ctx sdk.Context) []stakingtypes.Delegation { +// panic("mock out the GetAllSDKDelegations method") +// }, +// GetLastTotalPowerFunc: func(ctx sdk.Context) sdk.Int { +// panic("mock out the GetLastTotalPower method") +// }, +// GetLastValidatorPowerFunc: func(ctx sdk.Context, valAddr sdk.ValAddress) int64 { +// panic("mock out the GetLastValidatorPower method") +// }, +// IterateBondedValidatorsByPowerFunc: func(context sdk.Context, fn func(index int64, validator stakingtypes.ValidatorI) (stop bool)) { +// panic("mock out the IterateBondedValidatorsByPower method") +// }, +// IterateDelegationsFunc: func(ctx sdk.Context, delegator sdk.AccAddress, fn func(index int64, delegation stakingtypes.DelegationI) (stop bool)) { +// panic("mock out the IterateDelegations method") +// }, +// IterateLastValidatorsFunc: func(context sdk.Context, fn func(index int64, validator stakingtypes.ValidatorI) (stop bool)) { +// panic("mock out the IterateLastValidators method") +// }, +// IterateValidatorsFunc: func(context sdk.Context, fn func(index int64, validator stakingtypes.ValidatorI) (stop bool)) { +// panic("mock out the IterateValidators method") +// }, +// JailFunc: func(context sdk.Context, consAddress sdk.ConsAddress) { +// panic("mock out the Jail method") +// }, +// MaxValidatorsFunc: func(context sdk.Context) uint32 { +// panic("mock out the MaxValidators method") +// }, +// SlashFunc: func(context sdk.Context, consAddress sdk.ConsAddress, n1 int64, n2 int64, dec sdk.Dec) { +// panic("mock out the Slash method") +// }, +// UnjailFunc: func(context sdk.Context, consAddress sdk.ConsAddress) { +// panic("mock out the Unjail method") +// }, +// ValidatorFunc: func(context sdk.Context, valAddress sdk.ValAddress) stakingtypes.ValidatorI { +// panic("mock out the Validator method") +// }, +// ValidatorByConsAddrFunc: func(context sdk.Context, consAddress sdk.ConsAddress) stakingtypes.ValidatorI { +// panic("mock out the ValidatorByConsAddr method") +// }, +// } +// +// // use mockedStakingKeeper in code that requires types.StakingKeeper +// // and then make assertions. +// +// } +type StakingKeeperMock struct { + // DelegationFunc mocks the Delegation method. + DelegationFunc func(context sdk.Context, accAddress sdk.AccAddress, valAddress sdk.ValAddress) stakingtypes.DelegationI + + // GetAllSDKDelegationsFunc mocks the GetAllSDKDelegations method. + GetAllSDKDelegationsFunc func(ctx sdk.Context) []stakingtypes.Delegation + + // GetLastTotalPowerFunc mocks the GetLastTotalPower method. + GetLastTotalPowerFunc func(ctx sdk.Context) sdk.Int + + // GetLastValidatorPowerFunc mocks the GetLastValidatorPower method. + GetLastValidatorPowerFunc func(ctx sdk.Context, valAddr sdk.ValAddress) int64 + + // IterateBondedValidatorsByPowerFunc mocks the IterateBondedValidatorsByPower method. + IterateBondedValidatorsByPowerFunc func(context sdk.Context, fn func(index int64, validator stakingtypes.ValidatorI) (stop bool)) + + // IterateDelegationsFunc mocks the IterateDelegations method. + IterateDelegationsFunc func(ctx sdk.Context, delegator sdk.AccAddress, fn func(index int64, delegation stakingtypes.DelegationI) (stop bool)) + + // IterateLastValidatorsFunc mocks the IterateLastValidators method. + IterateLastValidatorsFunc func(context sdk.Context, fn func(index int64, validator stakingtypes.ValidatorI) (stop bool)) + + // IterateValidatorsFunc mocks the IterateValidators method. + IterateValidatorsFunc func(context sdk.Context, fn func(index int64, validator stakingtypes.ValidatorI) (stop bool)) + + // JailFunc mocks the Jail method. + JailFunc func(context sdk.Context, consAddress sdk.ConsAddress) + + // MaxValidatorsFunc mocks the MaxValidators method. + MaxValidatorsFunc func(context sdk.Context) uint32 + + // SlashFunc mocks the Slash method. + SlashFunc func(context sdk.Context, consAddress sdk.ConsAddress, n1 int64, n2 int64, dec sdk.Dec) + + // UnjailFunc mocks the Unjail method. + UnjailFunc func(context sdk.Context, consAddress sdk.ConsAddress) + + // ValidatorFunc mocks the Validator method. + ValidatorFunc func(context sdk.Context, valAddress sdk.ValAddress) stakingtypes.ValidatorI + + // ValidatorByConsAddrFunc mocks the ValidatorByConsAddr method. + ValidatorByConsAddrFunc func(context sdk.Context, consAddress sdk.ConsAddress) stakingtypes.ValidatorI + + // calls tracks calls to the methods. + calls struct { + // Delegation holds details about calls to the Delegation method. + Delegation []struct { + // Context is the context argument value. + Context sdk.Context + // AccAddress is the accAddress argument value. + AccAddress sdk.AccAddress + // ValAddress is the valAddress argument value. + ValAddress sdk.ValAddress + } + // GetAllSDKDelegations holds details about calls to the GetAllSDKDelegations method. + GetAllSDKDelegations []struct { + // Ctx is the ctx argument value. + Ctx sdk.Context + } + // GetLastTotalPower holds details about calls to the GetLastTotalPower method. + GetLastTotalPower []struct { + // Ctx is the ctx argument value. + Ctx sdk.Context + } + // GetLastValidatorPower holds details about calls to the GetLastValidatorPower method. + GetLastValidatorPower []struct { + // Ctx is the ctx argument value. + Ctx sdk.Context + // ValAddr is the valAddr argument value. + ValAddr sdk.ValAddress + } + // IterateBondedValidatorsByPower holds details about calls to the IterateBondedValidatorsByPower method. + IterateBondedValidatorsByPower []struct { + // Context is the context argument value. + Context sdk.Context + // Fn is the fn argument value. + Fn func(index int64, validator stakingtypes.ValidatorI) (stop bool) + } + // IterateDelegations holds details about calls to the IterateDelegations method. + IterateDelegations []struct { + // Ctx is the ctx argument value. + Ctx sdk.Context + // Delegator is the delegator argument value. + Delegator sdk.AccAddress + // Fn is the fn argument value. + Fn func(index int64, delegation stakingtypes.DelegationI) (stop bool) + } + // IterateLastValidators holds details about calls to the IterateLastValidators method. + IterateLastValidators []struct { + // Context is the context argument value. + Context sdk.Context + // Fn is the fn argument value. + Fn func(index int64, validator stakingtypes.ValidatorI) (stop bool) + } + // IterateValidators holds details about calls to the IterateValidators method. + IterateValidators []struct { + // Context is the context argument value. + Context sdk.Context + // Fn is the fn argument value. + Fn func(index int64, validator stakingtypes.ValidatorI) (stop bool) + } + // Jail holds details about calls to the Jail method. + Jail []struct { + // Context is the context argument value. + Context sdk.Context + // ConsAddress is the consAddress argument value. + ConsAddress sdk.ConsAddress + } + // MaxValidators holds details about calls to the MaxValidators method. + MaxValidators []struct { + // Context is the context argument value. + Context sdk.Context + } + // Slash holds details about calls to the Slash method. + Slash []struct { + // Context is the context argument value. + Context sdk.Context + // ConsAddress is the consAddress argument value. + ConsAddress sdk.ConsAddress + // N1 is the n1 argument value. + N1 int64 + // N2 is the n2 argument value. + N2 int64 + // Dec is the dec argument value. + Dec sdk.Dec + } + // Unjail holds details about calls to the Unjail method. + Unjail []struct { + // Context is the context argument value. + Context sdk.Context + // ConsAddress is the consAddress argument value. + ConsAddress sdk.ConsAddress + } + // Validator holds details about calls to the Validator method. + Validator []struct { + // Context is the context argument value. + Context sdk.Context + // ValAddress is the valAddress argument value. + ValAddress sdk.ValAddress + } + // ValidatorByConsAddr holds details about calls to the ValidatorByConsAddr method. + ValidatorByConsAddr []struct { + // Context is the context argument value. + Context sdk.Context + // ConsAddress is the consAddress argument value. + ConsAddress sdk.ConsAddress + } + } + lockDelegation sync.RWMutex + lockGetAllSDKDelegations sync.RWMutex + lockGetLastTotalPower sync.RWMutex + lockGetLastValidatorPower sync.RWMutex + lockIterateBondedValidatorsByPower sync.RWMutex + lockIterateDelegations sync.RWMutex + lockIterateLastValidators sync.RWMutex + lockIterateValidators sync.RWMutex + lockJail sync.RWMutex + lockMaxValidators sync.RWMutex + lockSlash sync.RWMutex + lockUnjail sync.RWMutex + lockValidator sync.RWMutex + lockValidatorByConsAddr sync.RWMutex +} + +// Delegation calls DelegationFunc. +func (mock *StakingKeeperMock) Delegation(context sdk.Context, accAddress sdk.AccAddress, valAddress sdk.ValAddress) stakingtypes.DelegationI { + if mock.DelegationFunc == nil { + panic("StakingKeeperMock.DelegationFunc: method is nil but StakingKeeper.Delegation was just called") + } + callInfo := struct { + Context sdk.Context + AccAddress sdk.AccAddress + ValAddress sdk.ValAddress + }{ + Context: context, + AccAddress: accAddress, + ValAddress: valAddress, + } + mock.lockDelegation.Lock() + mock.calls.Delegation = append(mock.calls.Delegation, callInfo) + mock.lockDelegation.Unlock() + return mock.DelegationFunc(context, accAddress, valAddress) +} + +// DelegationCalls gets all the calls that were made to Delegation. +// Check the length with: +// +// len(mockedStakingKeeper.DelegationCalls()) +func (mock *StakingKeeperMock) DelegationCalls() []struct { + Context sdk.Context + AccAddress sdk.AccAddress + ValAddress sdk.ValAddress +} { + var calls []struct { + Context sdk.Context + AccAddress sdk.AccAddress + ValAddress sdk.ValAddress + } + mock.lockDelegation.RLock() + calls = mock.calls.Delegation + mock.lockDelegation.RUnlock() + return calls +} + +// GetAllSDKDelegations calls GetAllSDKDelegationsFunc. +func (mock *StakingKeeperMock) GetAllSDKDelegations(ctx sdk.Context) []stakingtypes.Delegation { + if mock.GetAllSDKDelegationsFunc == nil { + panic("StakingKeeperMock.GetAllSDKDelegationsFunc: method is nil but StakingKeeper.GetAllSDKDelegations was just called") + } + callInfo := struct { + Ctx sdk.Context + }{ + Ctx: ctx, + } + mock.lockGetAllSDKDelegations.Lock() + mock.calls.GetAllSDKDelegations = append(mock.calls.GetAllSDKDelegations, callInfo) + mock.lockGetAllSDKDelegations.Unlock() + return mock.GetAllSDKDelegationsFunc(ctx) +} + +// GetAllSDKDelegationsCalls gets all the calls that were made to GetAllSDKDelegations. +// Check the length with: +// +// len(mockedStakingKeeper.GetAllSDKDelegationsCalls()) +func (mock *StakingKeeperMock) GetAllSDKDelegationsCalls() []struct { + Ctx sdk.Context +} { + var calls []struct { + Ctx sdk.Context + } + mock.lockGetAllSDKDelegations.RLock() + calls = mock.calls.GetAllSDKDelegations + mock.lockGetAllSDKDelegations.RUnlock() + return calls +} + +// GetLastTotalPower calls GetLastTotalPowerFunc. +func (mock *StakingKeeperMock) GetLastTotalPower(ctx sdk.Context) sdk.Int { + if mock.GetLastTotalPowerFunc == nil { + panic("StakingKeeperMock.GetLastTotalPowerFunc: method is nil but StakingKeeper.GetLastTotalPower was just called") + } + callInfo := struct { + Ctx sdk.Context + }{ + Ctx: ctx, + } + mock.lockGetLastTotalPower.Lock() + mock.calls.GetLastTotalPower = append(mock.calls.GetLastTotalPower, callInfo) + mock.lockGetLastTotalPower.Unlock() + return mock.GetLastTotalPowerFunc(ctx) +} + +// GetLastTotalPowerCalls gets all the calls that were made to GetLastTotalPower. +// Check the length with: +// +// len(mockedStakingKeeper.GetLastTotalPowerCalls()) +func (mock *StakingKeeperMock) GetLastTotalPowerCalls() []struct { + Ctx sdk.Context +} { + var calls []struct { + Ctx sdk.Context + } + mock.lockGetLastTotalPower.RLock() + calls = mock.calls.GetLastTotalPower + mock.lockGetLastTotalPower.RUnlock() + return calls +} + +// GetLastValidatorPower calls GetLastValidatorPowerFunc. +func (mock *StakingKeeperMock) GetLastValidatorPower(ctx sdk.Context, valAddr sdk.ValAddress) int64 { + if mock.GetLastValidatorPowerFunc == nil { + panic("StakingKeeperMock.GetLastValidatorPowerFunc: method is nil but StakingKeeper.GetLastValidatorPower was just called") + } + callInfo := struct { + Ctx sdk.Context + ValAddr sdk.ValAddress + }{ + Ctx: ctx, + ValAddr: valAddr, + } + mock.lockGetLastValidatorPower.Lock() + mock.calls.GetLastValidatorPower = append(mock.calls.GetLastValidatorPower, callInfo) + mock.lockGetLastValidatorPower.Unlock() + return mock.GetLastValidatorPowerFunc(ctx, valAddr) +} + +// GetLastValidatorPowerCalls gets all the calls that were made to GetLastValidatorPower. +// Check the length with: +// +// len(mockedStakingKeeper.GetLastValidatorPowerCalls()) +func (mock *StakingKeeperMock) GetLastValidatorPowerCalls() []struct { + Ctx sdk.Context + ValAddr sdk.ValAddress +} { + var calls []struct { + Ctx sdk.Context + ValAddr sdk.ValAddress + } + mock.lockGetLastValidatorPower.RLock() + calls = mock.calls.GetLastValidatorPower + mock.lockGetLastValidatorPower.RUnlock() + return calls +} + +// IterateBondedValidatorsByPower calls IterateBondedValidatorsByPowerFunc. +func (mock *StakingKeeperMock) IterateBondedValidatorsByPower(context sdk.Context, fn func(index int64, validator stakingtypes.ValidatorI) (stop bool)) { + if mock.IterateBondedValidatorsByPowerFunc == nil { + panic("StakingKeeperMock.IterateBondedValidatorsByPowerFunc: method is nil but StakingKeeper.IterateBondedValidatorsByPower was just called") + } + callInfo := struct { + Context sdk.Context + Fn func(index int64, validator stakingtypes.ValidatorI) (stop bool) + }{ + Context: context, + Fn: fn, + } + mock.lockIterateBondedValidatorsByPower.Lock() + mock.calls.IterateBondedValidatorsByPower = append(mock.calls.IterateBondedValidatorsByPower, callInfo) + mock.lockIterateBondedValidatorsByPower.Unlock() + mock.IterateBondedValidatorsByPowerFunc(context, fn) +} + +// IterateBondedValidatorsByPowerCalls gets all the calls that were made to IterateBondedValidatorsByPower. +// Check the length with: +// +// len(mockedStakingKeeper.IterateBondedValidatorsByPowerCalls()) +func (mock *StakingKeeperMock) IterateBondedValidatorsByPowerCalls() []struct { + Context sdk.Context + Fn func(index int64, validator stakingtypes.ValidatorI) (stop bool) +} { + var calls []struct { + Context sdk.Context + Fn func(index int64, validator stakingtypes.ValidatorI) (stop bool) + } + mock.lockIterateBondedValidatorsByPower.RLock() + calls = mock.calls.IterateBondedValidatorsByPower + mock.lockIterateBondedValidatorsByPower.RUnlock() + return calls +} + +// IterateDelegations calls IterateDelegationsFunc. +func (mock *StakingKeeperMock) IterateDelegations(ctx sdk.Context, delegator sdk.AccAddress, fn func(index int64, delegation stakingtypes.DelegationI) (stop bool)) { + if mock.IterateDelegationsFunc == nil { + panic("StakingKeeperMock.IterateDelegationsFunc: method is nil but StakingKeeper.IterateDelegations was just called") + } + callInfo := struct { + Ctx sdk.Context + Delegator sdk.AccAddress + Fn func(index int64, delegation stakingtypes.DelegationI) (stop bool) + }{ + Ctx: ctx, + Delegator: delegator, + Fn: fn, + } + mock.lockIterateDelegations.Lock() + mock.calls.IterateDelegations = append(mock.calls.IterateDelegations, callInfo) + mock.lockIterateDelegations.Unlock() + mock.IterateDelegationsFunc(ctx, delegator, fn) +} + +// IterateDelegationsCalls gets all the calls that were made to IterateDelegations. +// Check the length with: +// +// len(mockedStakingKeeper.IterateDelegationsCalls()) +func (mock *StakingKeeperMock) IterateDelegationsCalls() []struct { + Ctx sdk.Context + Delegator sdk.AccAddress + Fn func(index int64, delegation stakingtypes.DelegationI) (stop bool) +} { + var calls []struct { + Ctx sdk.Context + Delegator sdk.AccAddress + Fn func(index int64, delegation stakingtypes.DelegationI) (stop bool) + } + mock.lockIterateDelegations.RLock() + calls = mock.calls.IterateDelegations + mock.lockIterateDelegations.RUnlock() + return calls +} + +// IterateLastValidators calls IterateLastValidatorsFunc. +func (mock *StakingKeeperMock) IterateLastValidators(context sdk.Context, fn func(index int64, validator stakingtypes.ValidatorI) (stop bool)) { + if mock.IterateLastValidatorsFunc == nil { + panic("StakingKeeperMock.IterateLastValidatorsFunc: method is nil but StakingKeeper.IterateLastValidators was just called") + } + callInfo := struct { + Context sdk.Context + Fn func(index int64, validator stakingtypes.ValidatorI) (stop bool) + }{ + Context: context, + Fn: fn, + } + mock.lockIterateLastValidators.Lock() + mock.calls.IterateLastValidators = append(mock.calls.IterateLastValidators, callInfo) + mock.lockIterateLastValidators.Unlock() + mock.IterateLastValidatorsFunc(context, fn) +} + +// IterateLastValidatorsCalls gets all the calls that were made to IterateLastValidators. +// Check the length with: +// +// len(mockedStakingKeeper.IterateLastValidatorsCalls()) +func (mock *StakingKeeperMock) IterateLastValidatorsCalls() []struct { + Context sdk.Context + Fn func(index int64, validator stakingtypes.ValidatorI) (stop bool) +} { + var calls []struct { + Context sdk.Context + Fn func(index int64, validator stakingtypes.ValidatorI) (stop bool) + } + mock.lockIterateLastValidators.RLock() + calls = mock.calls.IterateLastValidators + mock.lockIterateLastValidators.RUnlock() + return calls +} + +// IterateValidators calls IterateValidatorsFunc. +func (mock *StakingKeeperMock) IterateValidators(context sdk.Context, fn func(index int64, validator stakingtypes.ValidatorI) (stop bool)) { + if mock.IterateValidatorsFunc == nil { + panic("StakingKeeperMock.IterateValidatorsFunc: method is nil but StakingKeeper.IterateValidators was just called") + } + callInfo := struct { + Context sdk.Context + Fn func(index int64, validator stakingtypes.ValidatorI) (stop bool) + }{ + Context: context, + Fn: fn, + } + mock.lockIterateValidators.Lock() + mock.calls.IterateValidators = append(mock.calls.IterateValidators, callInfo) + mock.lockIterateValidators.Unlock() + mock.IterateValidatorsFunc(context, fn) +} + +// IterateValidatorsCalls gets all the calls that were made to IterateValidators. +// Check the length with: +// +// len(mockedStakingKeeper.IterateValidatorsCalls()) +func (mock *StakingKeeperMock) IterateValidatorsCalls() []struct { + Context sdk.Context + Fn func(index int64, validator stakingtypes.ValidatorI) (stop bool) +} { + var calls []struct { + Context sdk.Context + Fn func(index int64, validator stakingtypes.ValidatorI) (stop bool) + } + mock.lockIterateValidators.RLock() + calls = mock.calls.IterateValidators + mock.lockIterateValidators.RUnlock() + return calls +} + +// Jail calls JailFunc. +func (mock *StakingKeeperMock) Jail(context sdk.Context, consAddress sdk.ConsAddress) { + if mock.JailFunc == nil { + panic("StakingKeeperMock.JailFunc: method is nil but StakingKeeper.Jail was just called") + } + callInfo := struct { + Context sdk.Context + ConsAddress sdk.ConsAddress + }{ + Context: context, + ConsAddress: consAddress, + } + mock.lockJail.Lock() + mock.calls.Jail = append(mock.calls.Jail, callInfo) + mock.lockJail.Unlock() + mock.JailFunc(context, consAddress) +} + +// JailCalls gets all the calls that were made to Jail. +// Check the length with: +// +// len(mockedStakingKeeper.JailCalls()) +func (mock *StakingKeeperMock) JailCalls() []struct { + Context sdk.Context + ConsAddress sdk.ConsAddress +} { + var calls []struct { + Context sdk.Context + ConsAddress sdk.ConsAddress + } + mock.lockJail.RLock() + calls = mock.calls.Jail + mock.lockJail.RUnlock() + return calls +} + +// MaxValidators calls MaxValidatorsFunc. +func (mock *StakingKeeperMock) MaxValidators(context sdk.Context) uint32 { + if mock.MaxValidatorsFunc == nil { + panic("StakingKeeperMock.MaxValidatorsFunc: method is nil but StakingKeeper.MaxValidators was just called") + } + callInfo := struct { + Context sdk.Context + }{ + Context: context, + } + mock.lockMaxValidators.Lock() + mock.calls.MaxValidators = append(mock.calls.MaxValidators, callInfo) + mock.lockMaxValidators.Unlock() + return mock.MaxValidatorsFunc(context) +} + +// MaxValidatorsCalls gets all the calls that were made to MaxValidators. +// Check the length with: +// +// len(mockedStakingKeeper.MaxValidatorsCalls()) +func (mock *StakingKeeperMock) MaxValidatorsCalls() []struct { + Context sdk.Context +} { + var calls []struct { + Context sdk.Context + } + mock.lockMaxValidators.RLock() + calls = mock.calls.MaxValidators + mock.lockMaxValidators.RUnlock() + return calls +} + +// Slash calls SlashFunc. +func (mock *StakingKeeperMock) Slash(context sdk.Context, consAddress sdk.ConsAddress, n1 int64, n2 int64, dec sdk.Dec) { + if mock.SlashFunc == nil { + panic("StakingKeeperMock.SlashFunc: method is nil but StakingKeeper.Slash was just called") + } + callInfo := struct { + Context sdk.Context + ConsAddress sdk.ConsAddress + N1 int64 + N2 int64 + Dec sdk.Dec + }{ + Context: context, + ConsAddress: consAddress, + N1: n1, + N2: n2, + Dec: dec, + } + mock.lockSlash.Lock() + mock.calls.Slash = append(mock.calls.Slash, callInfo) + mock.lockSlash.Unlock() + mock.SlashFunc(context, consAddress, n1, n2, dec) +} + +// SlashCalls gets all the calls that were made to Slash. +// Check the length with: +// +// len(mockedStakingKeeper.SlashCalls()) +func (mock *StakingKeeperMock) SlashCalls() []struct { + Context sdk.Context + ConsAddress sdk.ConsAddress + N1 int64 + N2 int64 + Dec sdk.Dec +} { + var calls []struct { + Context sdk.Context + ConsAddress sdk.ConsAddress + N1 int64 + N2 int64 + Dec sdk.Dec + } + mock.lockSlash.RLock() + calls = mock.calls.Slash + mock.lockSlash.RUnlock() + return calls +} + +// Unjail calls UnjailFunc. +func (mock *StakingKeeperMock) Unjail(context sdk.Context, consAddress sdk.ConsAddress) { + if mock.UnjailFunc == nil { + panic("StakingKeeperMock.UnjailFunc: method is nil but StakingKeeper.Unjail was just called") + } + callInfo := struct { + Context sdk.Context + ConsAddress sdk.ConsAddress + }{ + Context: context, + ConsAddress: consAddress, + } + mock.lockUnjail.Lock() + mock.calls.Unjail = append(mock.calls.Unjail, callInfo) + mock.lockUnjail.Unlock() + mock.UnjailFunc(context, consAddress) +} + +// UnjailCalls gets all the calls that were made to Unjail. +// Check the length with: +// +// len(mockedStakingKeeper.UnjailCalls()) +func (mock *StakingKeeperMock) UnjailCalls() []struct { + Context sdk.Context + ConsAddress sdk.ConsAddress +} { + var calls []struct { + Context sdk.Context + ConsAddress sdk.ConsAddress + } + mock.lockUnjail.RLock() + calls = mock.calls.Unjail + mock.lockUnjail.RUnlock() + return calls +} + +// Validator calls ValidatorFunc. +func (mock *StakingKeeperMock) Validator(context sdk.Context, valAddress sdk.ValAddress) stakingtypes.ValidatorI { + if mock.ValidatorFunc == nil { + panic("StakingKeeperMock.ValidatorFunc: method is nil but StakingKeeper.Validator was just called") + } + callInfo := struct { + Context sdk.Context + ValAddress sdk.ValAddress + }{ + Context: context, + ValAddress: valAddress, + } + mock.lockValidator.Lock() + mock.calls.Validator = append(mock.calls.Validator, callInfo) + mock.lockValidator.Unlock() + return mock.ValidatorFunc(context, valAddress) +} + +// ValidatorCalls gets all the calls that were made to Validator. +// Check the length with: +// +// len(mockedStakingKeeper.ValidatorCalls()) +func (mock *StakingKeeperMock) ValidatorCalls() []struct { + Context sdk.Context + ValAddress sdk.ValAddress +} { + var calls []struct { + Context sdk.Context + ValAddress sdk.ValAddress + } + mock.lockValidator.RLock() + calls = mock.calls.Validator + mock.lockValidator.RUnlock() + return calls +} + +// ValidatorByConsAddr calls ValidatorByConsAddrFunc. +func (mock *StakingKeeperMock) ValidatorByConsAddr(context sdk.Context, consAddress sdk.ConsAddress) stakingtypes.ValidatorI { + if mock.ValidatorByConsAddrFunc == nil { + panic("StakingKeeperMock.ValidatorByConsAddrFunc: method is nil but StakingKeeper.ValidatorByConsAddr was just called") + } + callInfo := struct { + Context sdk.Context + ConsAddress sdk.ConsAddress + }{ + Context: context, + ConsAddress: consAddress, + } + mock.lockValidatorByConsAddr.Lock() + mock.calls.ValidatorByConsAddr = append(mock.calls.ValidatorByConsAddr, callInfo) + mock.lockValidatorByConsAddr.Unlock() + return mock.ValidatorByConsAddrFunc(context, consAddress) +} + +// ValidatorByConsAddrCalls gets all the calls that were made to ValidatorByConsAddr. +// Check the length with: +// +// len(mockedStakingKeeper.ValidatorByConsAddrCalls()) +func (mock *StakingKeeperMock) ValidatorByConsAddrCalls() []struct { + Context sdk.Context + ConsAddress sdk.ConsAddress +} { + var calls []struct { + Context sdk.Context + ConsAddress sdk.ConsAddress + } + mock.lockValidatorByConsAddr.RLock() + calls = mock.calls.ValidatorByConsAddr + mock.lockValidatorByConsAddr.RUnlock() + return calls +} From 431f854f69c8b4a8228b9c1645c04c19844072f9 Mon Sep 17 00:00:00 2001 From: Haiyi Zhong Date: Wed, 29 Jan 2025 14:45:49 -0500 Subject: [PATCH 2/4] track burned fee --- app/app.go | 2 +- utils/events/event_imports_test.go | 1 + x/distribution/keeper/keeper.go | 41 ++++---------- x/distribution/keeper/keeper_test.go | 28 +++++++++- x/distribution/types/expected_keepers.go | 1 + x/distribution/types/mock/expected_keepers.go | 56 +++++++++++++++++++ x/distribution/types/types.go | 16 ++++++ 7 files changed, 112 insertions(+), 33 deletions(-) create mode 100644 x/distribution/types/types.go diff --git a/app/app.go b/app/app.go index 071cd4b0b..919c0cb6d 100644 --- a/app/app.go +++ b/app/app.go @@ -713,7 +713,7 @@ func initMessageAnteDecorators(encodingConfig axelarParams.EncodingConfig, keepe func InitModuleAccountPermissions() map[string][]string { return map[string][]string{ authtypes.FeeCollectorName: nil, - distrtypes.ModuleName: {authtypes.Burner}, + distrtypes.ModuleName: {authtypes.Minter, authtypes.Burner}, minttypes.ModuleName: {authtypes.Minter}, stakingtypes.BondedPoolName: {authtypes.Burner, authtypes.Staking}, stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking}, diff --git a/utils/events/event_imports_test.go b/utils/events/event_imports_test.go index 646e60920..19f7fee02 100644 --- a/utils/events/event_imports_test.go +++ b/utils/events/event_imports_test.go @@ -5,6 +5,7 @@ import ( _ "github.com/axelarnetwork/axelar-core/x/ante/types" _ "github.com/axelarnetwork/axelar-core/x/auxiliary/types" _ "github.com/axelarnetwork/axelar-core/x/axelarnet/types" + _ "github.com/axelarnetwork/axelar-core/x/distribution/types" _ "github.com/axelarnetwork/axelar-core/x/evm/types" _ "github.com/axelarnetwork/axelar-core/x/multisig/types" _ "github.com/axelarnetwork/axelar-core/x/nexus/types" diff --git a/x/distribution/keeper/keeper.go b/x/distribution/keeper/keeper.go index ccbed2271..557e64df5 100644 --- a/x/distribution/keeper/keeper.go +++ b/x/distribution/keeper/keeper.go @@ -1,8 +1,6 @@ package keeper import ( - "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" distribution "github.com/cosmos/cosmos-sdk/x/distribution/keeper" distributionTypes "github.com/cosmos/cosmos-sdk/x/distribution/types" @@ -11,6 +9,7 @@ import ( "github.com/axelarnetwork/axelar-core/utils/events" "github.com/axelarnetwork/axelar-core/x/distribution/types" "github.com/axelarnetwork/utils/funcs" + "github.com/axelarnetwork/utils/slices" ) // Keeper wraps the distribution keeper to customize fee allocation mechanism @@ -39,12 +38,7 @@ func NewKeeper( // AllocateTokens modifies the fee distribution by: // - Allocating the community tax portion to the community pool // - Burning all remaining tokens instead of distributing to validators -func (k Keeper) AllocateTokens( - ctx sdk.Context, _, totalPreviousPower int64, - previousProposer sdk.ConsAddress, _ []abci.VoteInfo, -) { - logger := k.Logger(ctx) - +func (k Keeper) AllocateTokens(ctx sdk.Context, _, _ int64, _ sdk.ConsAddress, _ []abci.VoteInfo) { // fetch and clear the collected fees for distribution, since this is // called in BeginBlock, collected fees will be from the previous block // (and distributed to the previous proposer) @@ -58,22 +52,15 @@ func (k Keeper) AllocateTokens( panic(err) } - // temporary workaround to keep CanWithdrawInvariant happy - // general discussions here: https://github.com/cosmos/cosmos-sdk/issues/2906#issuecomment-441867634 feePool := k.GetFeePool(ctx) - if totalPreviousPower == 0 { - feePool.CommunityPool = feePool.CommunityPool.Add(feesCollected...) - k.SetFeePool(ctx, feePool) - return - } communityTaxRate := k.GetCommunityTax(ctx) communityPoolAmount := feesCollected.MulDecTruncate(communityTaxRate) remaining := feesCollected.Sub(communityPoolAmount) // truncate the remaining coins, return remainder to community pool - feeToBurn, remainder := remaining.TruncateDecimal() - communityPoolAmount = communityPoolAmount.Add(remainder...) + feeToBurn, truncationRemainder := remaining.TruncateDecimal() + communityPoolAmount = communityPoolAmount.Add(truncationRemainder...) // allocate community funding feePool.CommunityPool = feePool.CommunityPool.Add(communityPoolAmount...) @@ -85,18 +72,10 @@ func (k Keeper) AllocateTokens( Coins: feeToBurn, }) - // keep the error log from the original implementation - proposerValidator := k.stakingKeeper.ValidatorByConsAddr(ctx, previousProposer) - if proposerValidator == nil { - // previous proposer can be unknown if say, the unbonding period is 1 block, so - // e.g. a validator undelegates at block X, it's removed entirely by - // block X+1's endblock, then X+2 we need to refer to the previous - // proposer for X+1, but we've forgotten about them. - logger.Error(fmt.Sprintf( - "WARNING: Attempt to allocate proposer rewards to unknown proposer %s. "+ - "This should happen only if the proposer unbonded completely within a single block, "+ - "which generally should not happen except in exceptional circumstances (or fuzz testing). "+ - "We recommend you investigate immediately.", - previousProposer.String())) - } + // track cumulative burned fee + feeBurned := slices.Map(feeToBurn, func(coin sdk.Coin) sdk.Coin { + return types.WithBurnedPrefix(coin) + }) + funcs.MustNoErr(k.bankKeeper.MintCoins(ctx, distributionTypes.ModuleName, feeBurned)) + funcs.MustNoErr(k.bankKeeper.SendCoinsFromModuleToAccount(ctx, distributionTypes.ModuleName, types.ZeroAddress, feeBurned)) } diff --git a/x/distribution/keeper/keeper_test.go b/x/distribution/keeper/keeper_test.go index aca9bab2e..4a52b9c3e 100644 --- a/x/distribution/keeper/keeper_test.go +++ b/x/distribution/keeper/keeper_test.go @@ -33,12 +33,14 @@ func TestAllocateTokens(t *testing.T) { k keeper.Keeper accBalances map[string]sdk.Coins bk *mock.BankKeeperMock + fee sdk.Coins ) ctx := sdk.NewContext(fake.NewMultiStore(), tmproto.Header{}, false, log.TestingLogger()) + fee = sdk.NewCoins(sdk.NewCoin(axelarnettypes.NativeAsset, sdk.NewInt(rand.PosI64()))) accBalances = map[string]sdk.Coins{ - authtypes.NewModuleAddress(authtypes.FeeCollectorName).String(): sdk.NewCoins(sdk.NewCoin(axelarnettypes.NativeAsset, sdk.NewInt(rand.PosI64()))), + authtypes.NewModuleAddress(authtypes.FeeCollectorName).String(): fee, } Given("an axelar distribution keeper", func() { @@ -65,10 +67,24 @@ func TestAllocateTokens(t *testing.T) { return nil }, + SendCoinsFromModuleToAccountFunc: func(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error { + senderModule = authtypes.NewModuleAddress(senderModule).String() + + accBalances[senderModule] = accBalances[senderModule].Sub(amt) + accBalances[recipientAddr.String()] = accBalances[recipientAddr.String()].Add(amt...) + + return nil + }, BurnCoinsFunc: func(ctx sdk.Context, name string, amt sdk.Coins) error { acc := authtypes.NewModuleAddress(name).String() accBalances[acc] = accBalances[acc].Sub(amt) + return nil + }, + MintCoinsFunc: func(ctx sdk.Context, name string, amt sdk.Coins) error { + acc := authtypes.NewModuleAddress(name).String() + accBalances[acc] = accBalances[acc].Add(amt...) + return nil }, } @@ -98,6 +114,16 @@ func TestAllocateTokens(t *testing.T) { return e.Type == feeBurnedType }), 1) + expectedBurnedFee := sdk.NewCoins(slices.Map(expectedBurnedFee(ctx, k, fee), types.WithBurnedPrefix)...) + assert.Equal(t, expectedBurnedFee, accBalances[types.ZeroAddress.String()]) }). Run(t) } + +func expectedBurnedFee(ctx sdk.Context, k keeper.Keeper, fee sdk.Coins) sdk.Coins { + feesDec := sdk.NewDecCoinsFromCoins(fee...) + tax := feesDec.MulDecTruncate(k.GetCommunityTax(ctx)) + burnAmt, _ := feesDec.Sub(tax).TruncateDecimal() + + return burnAmt +} diff --git a/x/distribution/types/expected_keepers.go b/x/distribution/types/expected_keepers.go index 6789e99e2..9be6b149b 100644 --- a/x/distribution/types/expected_keepers.go +++ b/x/distribution/types/expected_keepers.go @@ -13,6 +13,7 @@ import ( type BankKeeper interface { types.BankKeeper BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error + MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error } type AccountKeeper interface { diff --git a/x/distribution/types/mock/expected_keepers.go b/x/distribution/types/mock/expected_keepers.go index f003ef430..3b255ab92 100644 --- a/x/distribution/types/mock/expected_keepers.go +++ b/x/distribution/types/mock/expected_keepers.go @@ -33,6 +33,9 @@ var _ types.BankKeeper = &BankKeeperMock{} // LockedCoinsFunc: func(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins { // panic("mock out the LockedCoins method") // }, +// MintCoinsFunc: func(ctx sdk.Context, moduleName string, amt sdk.Coins) error { +// panic("mock out the MintCoins method") +// }, // SendCoinsFromAccountToModuleFunc: func(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error { // panic("mock out the SendCoinsFromAccountToModule method") // }, @@ -64,6 +67,9 @@ type BankKeeperMock struct { // LockedCoinsFunc mocks the LockedCoins method. LockedCoinsFunc func(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + // MintCoinsFunc mocks the MintCoins method. + MintCoinsFunc func(ctx sdk.Context, moduleName string, amt sdk.Coins) error + // SendCoinsFromAccountToModuleFunc mocks the SendCoinsFromAccountToModule method. SendCoinsFromAccountToModuleFunc func(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error @@ -110,6 +116,15 @@ type BankKeeperMock struct { // Addr is the addr argument value. Addr sdk.AccAddress } + // MintCoins holds details about calls to the MintCoins method. + MintCoins []struct { + // Ctx is the ctx argument value. + Ctx sdk.Context + // ModuleName is the moduleName argument value. + ModuleName string + // Amt is the amt argument value. + Amt sdk.Coins + } // SendCoinsFromAccountToModule holds details about calls to the SendCoinsFromAccountToModule method. SendCoinsFromAccountToModule []struct { // Ctx is the ctx argument value. @@ -155,6 +170,7 @@ type BankKeeperMock struct { lockGetAllBalances sync.RWMutex lockGetBalance sync.RWMutex lockLockedCoins sync.RWMutex + lockMintCoins sync.RWMutex lockSendCoinsFromAccountToModule sync.RWMutex lockSendCoinsFromModuleToAccount sync.RWMutex lockSendCoinsFromModuleToModule sync.RWMutex @@ -313,6 +329,46 @@ func (mock *BankKeeperMock) LockedCoinsCalls() []struct { return calls } +// MintCoins calls MintCoinsFunc. +func (mock *BankKeeperMock) MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error { + if mock.MintCoinsFunc == nil { + panic("BankKeeperMock.MintCoinsFunc: method is nil but BankKeeper.MintCoins was just called") + } + callInfo := struct { + Ctx sdk.Context + ModuleName string + Amt sdk.Coins + }{ + Ctx: ctx, + ModuleName: moduleName, + Amt: amt, + } + mock.lockMintCoins.Lock() + mock.calls.MintCoins = append(mock.calls.MintCoins, callInfo) + mock.lockMintCoins.Unlock() + return mock.MintCoinsFunc(ctx, moduleName, amt) +} + +// MintCoinsCalls gets all the calls that were made to MintCoins. +// Check the length with: +// +// len(mockedBankKeeper.MintCoinsCalls()) +func (mock *BankKeeperMock) MintCoinsCalls() []struct { + Ctx sdk.Context + ModuleName string + Amt sdk.Coins +} { + var calls []struct { + Ctx sdk.Context + ModuleName string + Amt sdk.Coins + } + mock.lockMintCoins.RLock() + calls = mock.calls.MintCoins + mock.lockMintCoins.RUnlock() + return calls +} + // SendCoinsFromAccountToModule calls SendCoinsFromAccountToModuleFunc. func (mock *BankKeeperMock) SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error { if mock.SendCoinsFromAccountToModuleFunc == nil { diff --git a/x/distribution/types/types.go b/x/distribution/types/types.go new file mode 100644 index 000000000..629338457 --- /dev/null +++ b/x/distribution/types/types.go @@ -0,0 +1,16 @@ +package types + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +const feeBurnedPrefix = "burned" + +var ZeroAddress = sdk.AccAddress(make([]byte, 32)) + +// WithBurnedPrefix converts a coin to a coin with 'burned' prefix +func WithBurnedPrefix(coin sdk.Coin) sdk.Coin { + return sdk.NewCoin(fmt.Sprintf("%s-%s", feeBurnedPrefix, coin.Denom), coin.Amount) +} From b339195396a4a9914c79ccbe2cc924870b1a60fc Mon Sep 17 00:00:00 2001 From: Haiyi Zhong Date: Fri, 31 Jan 2025 11:00:09 -0500 Subject: [PATCH 3/4] address comment --- x/distribution/keeper/keeper.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/x/distribution/keeper/keeper.go b/x/distribution/keeper/keeper.go index 557e64df5..f37bbbb1f 100644 --- a/x/distribution/keeper/keeper.go +++ b/x/distribution/keeper/keeper.go @@ -73,9 +73,7 @@ func (k Keeper) AllocateTokens(ctx sdk.Context, _, _ int64, _ sdk.ConsAddress, _ }) // track cumulative burned fee - feeBurned := slices.Map(feeToBurn, func(coin sdk.Coin) sdk.Coin { - return types.WithBurnedPrefix(coin) - }) + feeBurned := slices.Map(feeToBurn, types.WithBurnedPrefix) funcs.MustNoErr(k.bankKeeper.MintCoins(ctx, distributionTypes.ModuleName, feeBurned)) funcs.MustNoErr(k.bankKeeper.SendCoinsFromModuleToAccount(ctx, distributionTypes.ModuleName, types.ZeroAddress, feeBurned)) } From a1e6f25f5066f324e417391f190b30fbab37a1d9 Mon Sep 17 00:00:00 2001 From: Haiyi Zhong Date: Fri, 31 Jan 2025 11:16:09 -0500 Subject: [PATCH 4/4] address comment --- x/distribution/keeper/keeper_test.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/x/distribution/keeper/keeper_test.go b/x/distribution/keeper/keeper_test.go index 4a52b9c3e..cc8e21c05 100644 --- a/x/distribution/keeper/keeper_test.go +++ b/x/distribution/keeper/keeper_test.go @@ -114,16 +114,19 @@ func TestAllocateTokens(t *testing.T) { return e.Type == feeBurnedType }), 1) - expectedBurnedFee := sdk.NewCoins(slices.Map(expectedBurnedFee(ctx, k, fee), types.WithBurnedPrefix)...) + burned, tax := expectedBurnAndTax(ctx, k, fee) + expectedBurnedFee := sdk.NewCoins(slices.Map(burned, types.WithBurnedPrefix)...) + assert.Equal(t, expectedBurnedFee, accBalances[types.ZeroAddress.String()]) + assert.Equal(t, k.GetFeePool(ctx).CommunityPool, tax) }). Run(t) } -func expectedBurnedFee(ctx sdk.Context, k keeper.Keeper, fee sdk.Coins) sdk.Coins { +func expectedBurnAndTax(ctx sdk.Context, k keeper.Keeper, fee sdk.Coins) (sdk.Coins, sdk.DecCoins) { feesDec := sdk.NewDecCoinsFromCoins(fee...) tax := feesDec.MulDecTruncate(k.GetCommunityTax(ctx)) - burnAmt, _ := feesDec.Sub(tax).TruncateDecimal() + burnAmt, remainder := feesDec.Sub(tax).TruncateDecimal() - return burnAmt + return burnAmt, tax.Add(remainder...) }