diff --git a/proto/lavanet/lava/rewards/iprpc.proto b/proto/lavanet/lava/rewards/iprpc.proto index 749fd1cb54..151ba86bb4 100644 --- a/proto/lavanet/lava/rewards/iprpc.proto +++ b/proto/lavanet/lava/rewards/iprpc.proto @@ -5,9 +5,9 @@ option go_package = "github.com/lavanet/lava/x/rewards/types"; import "gogoproto/gogo.proto"; import "cosmos/base/v1beta1/coin.proto"; -// list object that holds the +// object that holds the list for iprpc funcs for a specific month id message IprpcReward { - uint64 id = 1; + uint64 id = 1; // month id repeated Specfund spec_funds = 2 [(gogoproto.nullable) = false]; } diff --git a/x/pairing/keeper/pairing_next_epoch_time_block.go b/x/pairing/keeper/pairing_next_epoch_time_block.go index 039f7284e7..b5d192d317 100644 --- a/x/pairing/keeper/pairing_next_epoch_time_block.go +++ b/x/pairing/keeper/pairing_next_epoch_time_block.go @@ -78,7 +78,7 @@ func (k Keeper) calculateAverageBlockTime(ctx sdk.Context, epoch uint64) (uint64 } // Calculate the average block time from prevEpochTimestampAndHeightList - averageBlockTime, err := calculateAverageBlockTimeFromList(ctx, prevEpochTimestampAndHeightList, sampleStep) + averageBlockTime, err := calculateAverageBlockTimeFromList(prevEpochTimestampAndHeightList, sampleStep) if pairingtypes.NotEnoughBlocksToCalculateAverageBlockTimeError.Is(err) || pairingtypes.AverageBlockTimeIsLessOrEqualToZeroError.Is(err) { // we shouldn't fail the get-pairing query because the average block time calculation failed (to indicate the fail, we return 0) return 0, nil @@ -126,7 +126,7 @@ func (k Keeper) getPreviousEpochTimestampsByHeight(ctx sdk.Context, epoch, sampl return prevEpochTimestampAndHeightList, nil } -func calculateAverageBlockTimeFromList(ctx sdk.Context, blockHeightAndTimeList []blockHeightAndTime, sampleStep uint64) (uint64, error) { +func calculateAverageBlockTimeFromList(blockHeightAndTimeList []blockHeightAndTime, sampleStep uint64) (uint64, error) { if len(blockHeightAndTimeList) <= 1 { return 0, utils.LavaFormatError("There isn't enough blockHeight structs in the previous epoch to calculate average block time", pairingtypes.NotEnoughBlocksToCalculateAverageBlockTimeError) } diff --git a/x/pairing/keeper/staking.go b/x/pairing/keeper/staking.go index 66d17271b6..3d908cbb4f 100644 --- a/x/pairing/keeper/staking.go +++ b/x/pairing/keeper/staking.go @@ -47,7 +47,7 @@ func (k Keeper) StakeNewEntry(ctx sdk.Context, validator, creator, chainID strin ) } - endpointsVerified, err := k.validateGeoLocationAndApiInterfaces(ctx, endpoints, geolocation, spec) + endpointsVerified, err := k.validateGeoLocationAndApiInterfaces(endpoints, geolocation, spec) if err != nil { return utils.LavaFormatWarning("invalid endpoints implementation for the given spec", err, utils.Attribute{Key: "provider", Value: creator}, @@ -201,7 +201,7 @@ func (k Keeper) StakeNewEntry(ctx sdk.Context, validator, creator, chainID strin return err } -func (k Keeper) validateGeoLocationAndApiInterfaces(ctx sdk.Context, endpoints []epochstoragetypes.Endpoint, geolocation int32, spec spectypes.Spec) (endpointsFormatted []epochstoragetypes.Endpoint, err error) { +func (k Keeper) validateGeoLocationAndApiInterfaces(endpoints []epochstoragetypes.Endpoint, geolocation int32, spec spectypes.Spec) (endpointsFormatted []epochstoragetypes.Endpoint, err error) { expectedInterfaces := k.specKeeper.GetExpectedServicesForExpandedSpec(spec, true) allowedInterfaces := k.specKeeper.GetExpectedServicesForExpandedSpec(spec, false) diff --git a/x/pairing/keeper/unresponsive_provider.go b/x/pairing/keeper/unresponsive_provider.go index 60dcb12cb6..bb7fa00600 100644 --- a/x/pairing/keeper/unresponsive_provider.go +++ b/x/pairing/keeper/unresponsive_provider.go @@ -102,7 +102,7 @@ func (k Keeper) UnstakeUnresponsiveProviders(ctx sdk.Context, epochsNumToCheckCU // providerPaymentStorageKeyList is not empty -> provider should be punished if len(providerPaymentStorageKeyList) != 0 && existingProviders[providerStakeEntry.GetChain()] > minProviders { - err = k.punishUnresponsiveProvider(ctx, minPaymentBlock, providerPaymentStorageKeyList, providerStakeEntry.GetAddress(), providerStakeEntry.GetChain(), complaintCU, servicedCU) + err = k.punishUnresponsiveProvider(ctx, providerPaymentStorageKeyList, providerStakeEntry.GetAddress(), providerStakeEntry.GetChain(), complaintCU, servicedCU) existingProviders[providerStakeEntry.GetChain()]-- if err != nil { utils.LavaFormatError("unstake unresponsive providers failed to punish provider", err, @@ -212,7 +212,7 @@ func (k Keeper) getCurrentProviderStakeStorageList(ctx sdk.Context) []epochstora } // Function that punishes providers. Current punishment is freeze -func (k Keeper) punishUnresponsiveProvider(ctx sdk.Context, epoch uint64, providerPaymentStorageKeyList []string, providerAddress, chainID string, complaintCU uint64, servicedCU uint64) error { +func (k Keeper) punishUnresponsiveProvider(ctx sdk.Context, providerPaymentStorageKeyList []string, providerAddress, chainID string, complaintCU uint64, servicedCU uint64) error { // freeze the unresponsive provider err := k.FreezeProvider(ctx, providerAddress, []string{chainID}, "unresponsiveness") if err != nil { diff --git a/x/rewards/genesis.go b/x/rewards/genesis.go index caf95b8f2b..bfe82663a5 100644 --- a/x/rewards/genesis.go +++ b/x/rewards/genesis.go @@ -22,7 +22,7 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) for _, iprpcReward := range genState.IprpcRewards { k.SetIprpcReward(ctx, iprpcReward) } - k.SetIprpcRewardsCurrent(ctx, genState.IprpcRewardsCurrent) + k.SetIprpcRewardsCurrentId(ctx, genState.IprpcRewardsCurrent) k.SetIprpcData(ctx, genState.MinIprpcCost, genState.IprpcSubscriptions) } @@ -35,7 +35,7 @@ func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState { genesis.IprpcSubscriptions = k.GetAllIprpcSubscription(ctx) genesis.MinIprpcCost = k.GetMinIprpcCost(ctx) genesis.IprpcRewards = k.GetAllIprpcReward(ctx) - genesis.IprpcRewardsCurrent = k.GetIprpcRewardsCurrent(ctx) + genesis.IprpcRewardsCurrent = k.GetIprpcRewardsCurrentId(ctx) // this line is used by starport scaffolding # genesis/module/export return genesis diff --git a/x/rewards/keeper/iprpc.go b/x/rewards/keeper/iprpc.go index a8e32f35c8..c0d57f4ce8 100644 --- a/x/rewards/keeper/iprpc.go +++ b/x/rewards/keeper/iprpc.go @@ -2,7 +2,6 @@ package keeper import ( "fmt" - "sort" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/lavanet/lava/utils" @@ -11,20 +10,15 @@ import ( // handleNoIprpcRewardToProviders handles the situation in which there are no providers to send IPRPC rewards to // so the IPRPC rewards transfer to the next month -func (k Keeper) handleNoIprpcRewardToProviders(ctx sdk.Context, iprpcReward types.IprpcReward) { - nextMonthIprpcReward, found := k.PopIprpcReward(ctx, false) - nextMonthId := k.GetIprpcRewardsCurrent(ctx) - if !found { - nextMonthIprpcReward = types.IprpcReward{Id: nextMonthId, SpecFunds: iprpcReward.SpecFunds} - } else { - nextMonthIprpcReward.SpecFunds = k.transferSpecFundsToNextMonth(iprpcReward.SpecFunds, nextMonthIprpcReward.SpecFunds) +func (k Keeper) handleNoIprpcRewardToProviders(ctx sdk.Context, iprpcFunds []types.Specfund) { + for _, fund := range iprpcFunds { + k.addSpecFunds(ctx, fund.Spec, fund.Fund, 1) } - k.SetIprpcReward(ctx, nextMonthIprpcReward) + details := map[string]string{ - "transferred_funds": iprpcReward.String(), - "next_month_updated_funds": nextMonthIprpcReward.String(), + "transferred_funds": fmt.Sprint(iprpcFunds), } - utils.LogLavaEvent(ctx, k.Logger(ctx), types.TransferIprpcRewardToNextMonth, details, + utils.LogLavaEvent(ctx, k.Logger(ctx), types.TransferIprpcRewardToNextMonthEventName, details, "No provider serviced an IPRPC eligible subscription, transferring current month IPRPC funds to next month") } @@ -34,16 +28,11 @@ func (k Keeper) countIprpcCu(specCuMap map[string]types.SpecCuType, iprpcCu uint specCu, ok := specCuMap[spec] if !ok { specCuMap[spec] = types.SpecCuType{ - ProvidersCu: map[string]uint64{provider: iprpcCu}, + ProvidersCu: []types.ProviderCuType{{Provider: provider, CU: iprpcCu}}, TotalCu: iprpcCu, } } else { - _, ok := specCu.ProvidersCu[provider] - if !ok { - specCu.ProvidersCu[provider] = iprpcCu - } else { - specCu.ProvidersCu[provider] += iprpcCu - } + specCu.ProvidersCu = append(specCu.ProvidersCu, types.ProviderCuType{Provider: provider, CU: iprpcCu}) specCu.TotalCu += iprpcCu specCuMap[spec] = specCu } @@ -53,7 +42,7 @@ func (k Keeper) countIprpcCu(specCuMap map[string]types.SpecCuType, iprpcCu uint // AddSpecFunds adds funds for a specific spec for of months. // This function is used by the fund-iprpc TX. func (k Keeper) addSpecFunds(ctx sdk.Context, spec string, fund sdk.Coins, duration uint64) { - startID := k.GetIprpcRewardsCurrent(ctx) + 1 // fund IPRPC only from the next month for months + startID := k.GetIprpcRewardsCurrentId(ctx) + 1 // fund IPRPC only from the next month for months for i := startID; i < startID+duration; i++ { iprpcReward, found := k.GetIprpcReward(ctx, i) if found { @@ -78,51 +67,20 @@ func (k Keeper) addSpecFunds(ctx sdk.Context, spec string, fund sdk.Coins, durat } } -// transferSpecFundsToNextMonth transfer the specFunds to the next month's IPRPC funds -// this function is used when there are no providers that should get the monthly IPRPC reward, -// so the reward transfers to the next month -func (k Keeper) transferSpecFundsToNextMonth(specFunds []types.Specfund, nextMonthSpecFunds []types.Specfund) []types.Specfund { - // Create a slice to store leftover spec funds - var leftoverList []types.Specfund - - // Loop through current spec funds - for _, current := range specFunds { - found := false - - // Loop through next month spec funds - for i, next := range nextMonthSpecFunds { - // If the spec is found in next month spec funds, merge the funds - if current.Spec == next.Spec { - // Add current month's fund to next month's fund - nextMonthSpecFunds[i].Fund = nextMonthSpecFunds[i].Fund.Add(current.Fund...) - found = true - break - } - } - - // If spec is not found in next month spec funds, add it to the merged list - if !found { - leftoverList = append(leftoverList, current) - } - } - - // Append any remaining spec funds from next month that were not merged - return append(nextMonthSpecFunds, leftoverList...) -} - // distributeIprpcRewards is distributing the IPRPC rewards for providers according to their serviced CU func (k Keeper) distributeIprpcRewards(ctx sdk.Context, iprpcReward types.IprpcReward, specCuMap map[string]types.SpecCuType) { // none of the providers will get the IPRPC reward this month, transfer the funds to the next month if len(specCuMap) == 0 { - k.handleNoIprpcRewardToProviders(ctx, iprpcReward) + k.handleNoIprpcRewardToProviders(ctx, iprpcReward.SpecFunds) return } - usedReward := sdk.NewCoins() + leftovers := sdk.NewCoins() for _, specFund := range iprpcReward.SpecFunds { // verify specCuMap holds an entry for the relevant spec specCu, ok := specCuMap[specFund.Spec] if !ok { + k.handleNoIprpcRewardToProviders(ctx, []types.Specfund{specFund}) utils.LavaFormatError("did not distribute iprpc rewards to providers in spec", fmt.Errorf("specCU not found"), utils.LogAttr("spec", specFund.Spec), utils.LogAttr("rewards", specFund.Fund.String()), @@ -130,40 +88,39 @@ func (k Keeper) distributeIprpcRewards(ctx sdk.Context, iprpcReward types.IprpcR continue } - // collect providers details - providers := []string{} - for provider := range specCu.ProvidersCu { - providers = append(providers, provider) - } - sort.Strings(providers) - + UsedReward := sdk.NewCoins() // distribute IPRPC reward for spec - for _, provider := range providers { - providerAddr, err := sdk.AccAddressFromBech32(provider) + for _, providerCU := range specCu.ProvidersCu { + providerAddr, err := sdk.AccAddressFromBech32(providerCU.Provider) if err != nil { continue } // calculate provider IPRPC reward - providerIprpcReward := specFund.Fund.MulInt(sdk.NewIntFromUint64(specCu.ProvidersCu[provider])).QuoInt(sdk.NewIntFromUint64(specCu.TotalCu)) + providerIprpcReward := specFund.Fund.MulInt(sdk.NewIntFromUint64(providerCU.CU)).QuoInt(sdk.NewIntFromUint64(specCu.TotalCu)) + + UsedRewardTemp := UsedReward.Add(providerIprpcReward...) + if UsedReward.IsAnyGT(specFund.Fund) { + utils.LavaFormatError("failed to send iprpc rewards to provider", fmt.Errorf("tried to send more rewards than funded"), utils.LogAttr("provider", providerCU)) + break + } + UsedReward = UsedRewardTemp // reward the provider _, _, err = k.dualstakingKeeper.RewardProvidersAndDelegators(ctx, providerAddr, specFund.Spec, providerIprpcReward, string(types.IprpcPoolName), false, false, false) if err != nil { - utils.LavaFormatError("failed to send iprpc rewards to provider", err, utils.LogAttr("provider", provider)) + utils.LavaFormatError("failed to send iprpc rewards to provider", err, utils.LogAttr("provider", providerCU)) } - - usedReward = usedReward.Add(providerIprpcReward...) } // count used rewards - usedReward = specFund.Fund.Sub(usedReward...) + leftovers = leftovers.Add(specFund.Fund.Sub(UsedReward...)...) } // handle leftovers - err := k.FundCommunityPoolFromModule(ctx, usedReward, string(types.IprpcPoolName)) + err := k.FundCommunityPoolFromModule(ctx, leftovers, string(types.IprpcPoolName)) if err != nil { utils.LavaFormatError("could not send iprpc leftover to community pool", err) } - utils.LogLavaEvent(ctx, k.Logger(ctx), types.IprpcPoolEmissionEventName, map[string]string{"iprpc_rewards_leftovers": usedReward.String()}, "IPRPC monthly rewards distributed successfully") + utils.LogLavaEvent(ctx, k.Logger(ctx), types.IprpcPoolEmissionEventName, map[string]string{"iprpc_rewards_leftovers": leftovers.String()}, "IPRPC monthly rewards distributed successfully") } diff --git a/x/rewards/keeper/iprpc_reward.go b/x/rewards/keeper/iprpc_reward.go index 4db13f6b88..4df6b9c713 100644 --- a/x/rewards/keeper/iprpc_reward.go +++ b/x/rewards/keeper/iprpc_reward.go @@ -8,8 +8,8 @@ import ( "github.com/lavanet/lava/x/rewards/types" ) -// GetIprpcRewardsCurrent get the total number of IprpcReward -func (k Keeper) GetIprpcRewardsCurrent(ctx sdk.Context) uint64 { +// GetIprpcRewardsCurrentId get the total number of IprpcReward +func (k Keeper) GetIprpcRewardsCurrentId(ctx sdk.Context) uint64 { store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte{}) byteKey := types.KeyPrefix(types.IprpcRewardsCurrentPrefix) bz := store.Get(byteKey) @@ -23,8 +23,8 @@ func (k Keeper) GetIprpcRewardsCurrent(ctx sdk.Context) uint64 { return binary.BigEndian.Uint64(bz) } -// SetIprpcRewardsCurrent set the total number of IprpcReward -func (k Keeper) SetIprpcRewardsCurrent(ctx sdk.Context, current uint64) { +// SetIprpcRewardsCurrentId set the total number of IprpcReward +func (k Keeper) SetIprpcRewardsCurrentId(ctx sdk.Context, current uint64) { store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte{}) byteKey := types.KeyPrefix(types.IprpcRewardsCurrentPrefix) bz := make([]byte, 8) @@ -85,10 +85,15 @@ func GetIprpcRewardIDFromBytes(bz []byte) uint64 { } // PopIprpcReward gets the lowest id IprpcReward object and removes it -func (k Keeper) PopIprpcReward(ctx sdk.Context, advanceCurrent bool) (types.IprpcReward, bool) { - current := k.GetIprpcRewardsCurrent(ctx) - if advanceCurrent { - k.SetIprpcRewardsCurrent(ctx, current+1) - } +func (k Keeper) PopIprpcReward(ctx sdk.Context) (types.IprpcReward, bool) { + current := k.GetIprpcRewardsCurrentId(ctx) + k.SetIprpcRewardsCurrentId(ctx, current+1) + defer k.RemoveIprpcReward(ctx, current) + return k.GetIprpcReward(ctx, current) +} + +// GetCurrentIprpcReward gets the lowest id IprpcReward object +func (k Keeper) GetCurrentIprpcReward(ctx sdk.Context) (types.IprpcReward, bool) { + current := k.GetIprpcRewardsCurrentId(ctx) return k.GetIprpcReward(ctx, current) } diff --git a/x/rewards/keeper/providers.go b/x/rewards/keeper/providers.go index 6acd975bf7..cc22684c6b 100644 --- a/x/rewards/keeper/providers.go +++ b/x/rewards/keeper/providers.go @@ -12,7 +12,11 @@ import ( const DAY_SECONDS = 60 * 60 * 24 -func (k Keeper) AggregateCU(ctx sdk.Context, provider string, chainID string, cu uint64) { +func (k Keeper) AggregateCU(ctx sdk.Context, subscription, provider string, chainID string, cu uint64) { + if !k.IsIprpcSubscription(ctx, subscription) { + return + } + index := types.BasePayIndex{Provider: provider, ChainID: chainID} basepay, found := k.getBasePay(ctx, index) if !found { @@ -98,12 +102,11 @@ func (k Keeper) distributeMonthlyBonusRewards(ctx sdk.Context) { } // Get current month IprpcReward and use it to distribute rewards - iprpcReward, found := k.PopIprpcReward(ctx, true) + iprpcReward, found := k.PopIprpcReward(ctx) if !found { utils.LavaFormatError("current month iprpc reward not found", fmt.Errorf("did not reward providers IPRPC bonus")) return } - k.RemoveIprpcReward(ctx, iprpcReward.Id) // distribute IPRPC rewards k.distributeIprpcRewards(ctx, iprpcReward, specCuMap) diff --git a/x/rewards/types/genesis.go b/x/rewards/types/genesis.go index 41929c2435..67850a259c 100644 --- a/x/rewards/types/genesis.go +++ b/x/rewards/types/genesis.go @@ -17,12 +17,13 @@ const DefaultIndex uint64 = 1 func DefaultGenesis() *GenesisState { return &GenesisState{ // this line is used by starport scaffolding # genesis/types/default - Params: DefaultParams(), - RefillRewardsTS: *types.DefaultGenesis(), - BasePays: []BasePayGenesis{}, - IprpcSubscriptions: []string{}, - MinIprpcCost: sdk.NewCoin(commontypes.TokenDenom, sdk.ZeroInt()), - IprpcRewards: []IprpcReward{}, + Params: DefaultParams(), + RefillRewardsTS: *types.DefaultGenesis(), + BasePays: []BasePayGenesis{}, + IprpcSubscriptions: []string{}, + MinIprpcCost: sdk.NewCoin(commontypes.TokenDenom, sdk.ZeroInt()), + IprpcRewards: []IprpcReward{}, + IprpcRewardsCurrent: 0, } } diff --git a/x/rewards/types/genesis_test.go b/x/rewards/types/genesis_test.go index faadd5ac5f..e7745ca5ad 100644 --- a/x/rewards/types/genesis_test.go +++ b/x/rewards/types/genesis_test.go @@ -21,12 +21,13 @@ func TestGenesisState_Validate(t *testing.T) { { desc: "invalid iprpc subscriptions", genState: &types.GenesisState{ - Params: types.DefaultParams(), - RefillRewardsTS: types.DefaultGenesis().RefillRewardsTS, - BasePays: types.DefaultGenesis().BasePays, - IprpcSubscriptions: []string{"invalidAddress"}, - MinIprpcCost: types.DefaultGenesis().MinIprpcCost, - IprpcRewards: types.DefaultGenesis().IprpcRewards, + Params: types.DefaultParams(), + RefillRewardsTS: types.DefaultGenesis().RefillRewardsTS, + BasePays: types.DefaultGenesis().BasePays, + IprpcSubscriptions: []string{"invalidAddress"}, + MinIprpcCost: types.DefaultGenesis().MinIprpcCost, + IprpcRewards: types.DefaultGenesis().IprpcRewards, + IprpcRewardsCurrent: types.DefaultGenesis().GetIprpcRewardsCurrent(), }, valid: false, }, diff --git a/x/rewards/types/types.go b/x/rewards/types/types.go index c3134beb44..537d3ea288 100644 --- a/x/rewards/types/types.go +++ b/x/rewards/types/types.go @@ -48,15 +48,20 @@ const ( // provide service on specific specs. The rewards from this pool are distributed on a monthly // basis const ( - IprpcPoolName Pool = "iprpc_pool" - IprpcPoolEmissionEventName string = "iprpc-pool-emmission" - SetIprpcDataEventName = "set-iprpc-data" - FundIprpcEventName = "fund-iprpc" - TransferIprpcRewardToNextMonth = "transfer-iprpc-reward-to-next-month" + IprpcPoolName Pool = "iprpc_pool" + IprpcPoolEmissionEventName string = "iprpc-pool-emmission" + SetIprpcDataEventName = "set-iprpc-data" + FundIprpcEventName = "fund-iprpc" + TransferIprpcRewardToNextMonthEventName = "transfer-iprpc-reward-to-next-month" ) // helper struct to track the serviced IPRPC CU for each spec+provider type SpecCuType struct { - ProvidersCu map[string]uint64 // provider -> cu + ProvidersCu []ProviderCuType TotalCu uint64 } + +type ProviderCuType struct { + Provider string + CU uint64 +} diff --git a/x/subscription/keeper/cu_tracker.go b/x/subscription/keeper/cu_tracker.go index 7081345ec4..2feae44f69 100644 --- a/x/subscription/keeper/cu_tracker.go +++ b/x/subscription/keeper/cu_tracker.go @@ -31,9 +31,7 @@ func (k Keeper) GetTrackedCu(ctx sdk.Context, sub string, provider string, chain // AddTrackedCu adds CU to the CU counters in relevant trackedCu entry // Also, it counts the IPRPC CU if the subscription is IPRPC eligible func (k Keeper) AddTrackedCu(ctx sdk.Context, sub string, provider string, chainID string, cuToAdd uint64, block uint64) error { - if k.rewardsKeeper.IsIprpcSubscription(ctx, sub) { - k.rewardsKeeper.AggregateCU(ctx, provider, chainID, cuToAdd) - } + k.rewardsKeeper.AggregateCU(ctx, sub, provider, chainID, cuToAdd) cu, found, key := k.GetTrackedCu(ctx, sub, provider, chainID, block) diff --git a/x/subscription/types/expected_keepers.go b/x/subscription/types/expected_keepers.go index effaf444be..8ee53de62d 100644 --- a/x/subscription/types/expected_keepers.go +++ b/x/subscription/types/expected_keepers.go @@ -70,7 +70,7 @@ type RewardsKeeper interface { ContributeToValidatorsAndCommunityPool(ctx sdk.Context, reward sdk.Coin, senderModule string) (updatedReward sdk.Coin, err error) FundCommunityPoolFromModule(ctx sdk.Context, amount sdk.Coins, senderModule string) error IsIprpcSubscription(ctx sdk.Context, address string) bool - AggregateCU(ctx sdk.Context, provider string, chainID string, cu uint64) + AggregateCU(ctx sdk.Context, subscription, provider string, chainID string, cu uint64) } type StakingKeeper interface {