From 6b9867e26d83becf659feaf261a799cf3587c0b0 Mon Sep 17 00:00:00 2001 From: keruch Date: Fri, 31 Jan 2025 18:59:00 +0100 Subject: [PATCH] feat(dividends): msg server and epoch hooks --- proto/dividends/gauge.proto | 52 +- proto/dividends/tx.proto | 4 +- x/dividends/keeper/allocation.go | 54 ++ x/dividends/keeper/distribute.go | 141 ------ x/dividends/keeper/distribute_test.go | 260 ---------- x/dividends/keeper/export_test.go | 37 -- x/dividends/keeper/gauge.go | 254 ---------- x/dividends/keeper/gauge_asset.go | 225 --------- x/dividends/keeper/gauge_rollapp.go | 60 --- x/dividends/keeper/gauge_rollapp_test.go | 147 ------ x/dividends/keeper/gauge_test.go | 226 --------- x/dividends/keeper/genesis.go | 21 +- x/dividends/keeper/genesis_test.go | 118 ----- x/dividends/keeper/grpc_query.go | 23 +- x/dividends/keeper/grpc_query_test.go | 432 ---------------- x/dividends/keeper/hooks.go | 52 +- x/dividends/keeper/keeper.go | 64 ++- x/dividends/keeper/msg_server.go | 103 +--- x/dividends/keeper/params.go | 23 - x/dividends/keeper/storage.go | 35 ++ x/dividends/types/expected_keepers.go | 24 + x/dividends/types/gauge.go | 15 + x/dividends/types/gauge.pb.go | 601 ++++++++--------------- x/dividends/types/keys.go | 21 +- x/dividends/types/tx.pb.go | 87 +++- x/dividends/types/types.go | 1 + 26 files changed, 534 insertions(+), 2546 deletions(-) create mode 100644 x/dividends/keeper/allocation.go delete mode 100644 x/dividends/keeper/distribute.go delete mode 100644 x/dividends/keeper/distribute_test.go delete mode 100644 x/dividends/keeper/export_test.go delete mode 100644 x/dividends/keeper/gauge.go delete mode 100644 x/dividends/keeper/gauge_asset.go delete mode 100644 x/dividends/keeper/gauge_rollapp.go delete mode 100644 x/dividends/keeper/gauge_rollapp_test.go delete mode 100644 x/dividends/keeper/gauge_test.go delete mode 100644 x/dividends/keeper/genesis_test.go delete mode 100644 x/dividends/keeper/grpc_query_test.go delete mode 100644 x/dividends/keeper/params.go create mode 100644 x/dividends/keeper/storage.go create mode 100644 x/dividends/types/expected_keepers.go create mode 100644 x/dividends/types/gauge.go create mode 100644 x/dividends/types/types.go diff --git a/proto/dividends/gauge.proto b/proto/dividends/gauge.proto index de98c7c6..9fb06fc3 100644 --- a/proto/dividends/gauge.proto +++ b/proto/dividends/gauge.proto @@ -17,50 +17,52 @@ message Gauge { string address = 2; // query_condition is *where* the gauge rewards are distributed to QueryCondition query_condition = 3; - // vesting_condition is *when* the gauge rewards are distributed to + // vesting_condition is *how long* the gauge rewards are distributed to VestingCondition vesting_condition = 4; + // vesting_condition is *how frequent* the gauge rewards are distributed to + VestingFrequency vesting_frequency = 5; } message QueryCondition { oneof condition { QueryConditionStakers stakers = 1; - QueryConditionFunds funds = 2; } } message VestingCondition { oneof condition { - VestingConditionImmediate immediate = 1; - VestingConditionEpoch epoch = 2; + VestingConditionPerpetual perpetual = 1; + VestingConditionLimited epoch = 2; } } +enum VestingFrequency { + VESTING_FREQUENCY_UNSPECIFIED = 0; + VESTING_FREQUENCY_BLOCK = 1; + VESTING_FREQUENCY_EPOCH = 2; +} + // QueryConditionStakers queries the stakers message QueryConditionStakers {} -// QueryConditionFunds queries the users with funds above a certain threshold -message QueryConditionFunds { - repeated cosmos.base.v1beta1.Coin threshold = 8 [ - (gogoproto.nullable) = false, - (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" - ]; -} - -// VestingConditionImmediate is a vesting condition that distributes rewards -// immediately. This gauge is perpetual by default. -// Non-perpetual gauges distribute their tokens equally per epoch while the +// VestingConditionPerpetual is a vesting condition that distributes rewards +// infinitely. Perpetual gauges distribute all their tokens at a single time +// and only distribute their tokens again once the gauge is refilled. +// +// Non-perpetual gauges distribute their tokens equally per period while the // gauge is in the active period. Perpetual gauges distribute all their tokens // at a single time and only distribute their tokens again once the gauge is -// refilled, Intended for use with incentives that get refilled daily. -message VestingConditionImmediate {} +// refilled. +message VestingConditionPerpetual {} -// VestingConditionEpoch is a vesting condition that distributes rewards over -// epochs -message VestingConditionEpoch { - // num_epochs_paid_over is the number of total epochs distribution will be +// VestingConditionLimited is a vesting condition that distributes rewards over +// the specified time. Non-perpetual gauges distribute their tokens equally per +// period while the gauge is in the active period. +message VestingConditionLimited { + // num_units is the number of total epochs/blocks distribution will be // completed over - uint64 num_epochs_paid_over = 1; - // filled_epochs is the number of epochs distribution has been completed on - // already - uint64 filled_epochs = 2; + uint64 num_units = 1; + // filled_epochs is the number of epochs/blocks distribution has been + // completed on already + uint64 filled_units = 2; } diff --git a/proto/dividends/tx.proto b/proto/dividends/tx.proto index 050559c2..31be5526 100644 --- a/proto/dividends/tx.proto +++ b/proto/dividends/tx.proto @@ -20,8 +20,10 @@ message MsgCreateGauge { string address = 2; // query_condition is *where* the gauge rewards are distributed to QueryCondition query_condition = 3; - // vesting_condition is *when* the gauge rewards are distributed to + // vesting_condition is *how long* the gauge rewards are distributed to VestingCondition vesting_condition = 4; + // vesting_condition is *how frequent* the gauge rewards are distributed to + VestingFrequency vesting_frequency = 5; } message MsgCreateGaugeResponse {} diff --git a/x/dividends/keeper/allocation.go b/x/dividends/keeper/allocation.go new file mode 100644 index 00000000..05f18127 --- /dev/null +++ b/x/dividends/keeper/allocation.go @@ -0,0 +1,54 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/dymensionxyz/dymension-rdk/x/dividends/types" +) + +func (k Keeper) Allocate(ctx sdk.Context) error { + var ( + totalStakingPower = k.stakingKeeper.GetLastTotalPower(ctx) + totalStakingPowerDec = sdk.NewDecFromInt(totalStakingPower) + ) + + err := k.IterateGauges(ctx, func(_ uint64, gauge types.Gauge) (stop bool, err error) { + var ( + address = sdk.MustAccAddressFromBech32(gauge.Address) + gaugeRewards = sdk.NewDecCoinsFromCoins(k.bankKeeper.GetAllBalances(ctx, address)...) + ) + + switch gauge.VestingCondition.Condition.(type) { + case *types.VestingCondition_Block: + case *types.VestingCondition_Epoch: + } + + switch gauge.QueryCondition.Condition.(type) { + case *types.QueryCondition_Stakers: + k.AllocateStakers(ctx, totalStakingPowerDec, gaugeRewards) + case *types.QueryCondition_Funds: + } + + return false, nil + }) + if err != nil { + return fmt.Errorf("iterate gauges: %w", err) + } + + return nil +} + +func (k Keeper) AllocateStakers(ctx sdk.Context, stakingPower sdk.Dec, gaugeRewards sdk.DecCoins) { + k.stakingKeeper.IterateBondedValidatorsByPower(ctx, func(index int64, validator stakingtypes.ValidatorI) (stop bool) { + var ( + valPower = validator.GetConsensusPower(sdk.DefaultPowerReduction) + powerFraction = sdk.NewDec(valPower).QuoTruncate(stakingPower) + reward = gaugeRewards.MulDecTruncate(powerFraction) + ) + + k.distrKeeper.AllocateTokensToValidator(ctx, validator, reward) + return false + }) +} diff --git a/x/dividends/keeper/distribute.go b/x/dividends/keeper/distribute.go deleted file mode 100644 index 60ae5026..00000000 --- a/x/dividends/keeper/distribute.go +++ /dev/null @@ -1,141 +0,0 @@ -package keeper - -import ( - "fmt" - - errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - - "github.com/dymensionxyz/dymension-rdk/x/dividends/types" -) - -// DistributeOnEpochEnd distributes coins from an array of gauges. -// It is called at the end of each epoch to distribute coins to the gauges that are active at that time. -func (k Keeper) DistributeOnEpochEnd(ctx sdk.Context, gauges []types.Gauge) (sdk.Coins, error) { - cache := types.NewDenomLocksCache() - - const EpochEnd = true - totalDistributedCoins, err := k.Distribute(ctx, gauges, cache, EpochEnd) - if err != nil { - return nil, fmt.Errorf("distribute gauges: %w", err) - } - - // call post distribution hooks - k.hooks.AfterEpochDistribution(ctx) - - k.checkFinishedGauges(ctx, gauges) - - return totalDistributedCoins, nil -} - -// Distribute distributes coins from an array of gauges. It may be called either at the end or at the middle of -// the epoch. If it's called at the end, then the FilledEpochs field for every gauge is increased. Also, it uses -// a cache specific for asset gauges that helps reduce the number of x/lockup requests. -func (k Keeper) Distribute(ctx sdk.Context, gauges []types.Gauge, cache types.DenomLocksCache, epochEnd bool) (sdk.Coins, error) { - // lockHolders is a map of address -> coins - // it used as an aggregator for owners of the locks over all gauges - lockHolders := NewRewardDistributionTracker() - totalDistributedCoins := sdk.Coins{} - - for _, gauge := range gauges { - var ( - gaugeDistributedCoins sdk.Coins - err error - ) - switch gauge.DistributeTo.(type) { - case *types.Gauge_Asset: - filteredLocks := k.GetDistributeToBaseLocks(ctx, gauge, cache) // get all locks that satisfy the gauge - gaugeDistributedCoins, err = k.calculateAssetGaugeRewards(ctx, gauge, filteredLocks, &lockHolders) - case *types.Gauge_Rollapp: - gaugeDistributedCoins, err = k.calculateRollappGaugeRewards(ctx, gauge, &lockHolders) - default: - return nil, errorsmod.WithType(sdkerrors.ErrInvalidType, fmt.Errorf("gauge %d has an unsupported distribution type", gauge.Id)) - } - if err != nil { - return nil, err - } - - if !gaugeDistributedCoins.Empty() { - err = k.updateGaugePostDistribute(ctx, gauge, gaugeDistributedCoins, epochEnd) - if err != nil { - return nil, err - } - totalDistributedCoins = totalDistributedCoins.Add(gaugeDistributedCoins...) - } - } - - // apply the distribution to asset gauges - err := k.distributeTrackedRewards(ctx, &lockHolders) - if err != nil { - return nil, err - } - - return totalDistributedCoins, nil -} - -// GetModuleToDistributeCoins returns sum of coins yet to be distributed for all of the module. -func (k Keeper) GetModuleToDistributeCoins(ctx sdk.Context) sdk.Coins { - activeGaugesDistr := k.getToDistributeCoinsFromGauges(k.getGaugesFromIterator(ctx, k.ActiveGaugesIterator(ctx))) - upcomingGaugesDistr := k.getToDistributeCoinsFromGauges(k.getGaugesFromIterator(ctx, k.UpcomingGaugesIterator(ctx))) - return activeGaugesDistr.Add(upcomingGaugesDistr...) -} - -// GetModuleDistributedCoins returns sum of coins that have been distributed so far for all of the module. -func (k Keeper) GetModuleDistributedCoins(ctx sdk.Context) sdk.Coins { - activeGaugesDistr := k.getDistributedCoinsFromGauges(k.getGaugesFromIterator(ctx, k.ActiveGaugesIterator(ctx))) - finishedGaugesDistr := k.getDistributedCoinsFromGauges(k.getGaugesFromIterator(ctx, k.FinishedGaugesIterator(ctx))) - - return activeGaugesDistr.Add(finishedGaugesDistr...) -} - -// getDistributedCoinsFromGauges returns coins that have been distributed already from the provided gauges -func (k Keeper) getDistributedCoinsFromGauges(gauges []types.Gauge) sdk.Coins { - coins := sdk.Coins{} - for _, gauge := range gauges { - coins = coins.Add(gauge.DistributedCoins...) - } - return coins -} - -// getToDistributeCoinsFromGauges returns coins that have not been distributed yet from the provided gauges -func (k Keeper) getToDistributeCoinsFromGauges(gauges []types.Gauge) sdk.Coins { - coins := sdk.Coins{} - distributed := sdk.Coins{} - - for _, gauge := range gauges { - coins = coins.Add(gauge.Coins...) - distributed = distributed.Add(gauge.DistributedCoins...) - } - return coins.Sub(distributed...) -} - -// updateGaugePostDistribute increments the gauge's filled epochs field. -// Also adds the coins that were just distributed to the gauge's distributed coins field. -func (k Keeper) updateGaugePostDistribute(ctx sdk.Context, gauge types.Gauge, newlyDistributedCoins sdk.Coins, epochEnd bool) error { - if epochEnd { - gauge.FilledEpochs += 1 - } - gauge.DistributedCoins = gauge.DistributedCoins.Add(newlyDistributedCoins...) - if err := k.setGauge(ctx, &gauge); err != nil { - return err - } - return nil -} - -// checkFinishedGauges checks if all non perpetual gauges provided have completed their required distributions. -// If complete, move the gauge from an active to a finished status. -func (k Keeper) checkFinishedGauges(ctx sdk.Context, gauges []types.Gauge) { - for _, gauge := range gauges { - if gauge.IsPerpetual { - continue - } - - // filled epoch is increased in this step and we compare with +1 - if gauge.NumEpochsPaidOver <= gauge.FilledEpochs+1 { - if err := k.moveActiveGaugeToFinishedGauge(ctx, gauge); err != nil { - panic(err) - } - } - } -} diff --git a/x/dividends/keeper/distribute_test.go b/x/dividends/keeper/distribute_test.go deleted file mode 100644 index 87d58b98..00000000 --- a/x/dividends/keeper/distribute_test.go +++ /dev/null @@ -1,260 +0,0 @@ -package keeper_test - -import ( - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/dymensionxyz/dymension/v3/x/incentives/types" - lockuptypes "github.com/dymensionxyz/dymension/v3/x/lockup/types" - "github.com/stretchr/testify/suite" -) - -var _ = suite.TestingSuite(nil) - -// TestDistribute tests that when the distribute command is executed on a provided gauge -// that the correct amount of rewards is sent to the correct lock owners. -func (suite *KeeperTestSuite) TestDistribute() { - defaultGauge := perpGaugeDesc{ - lockDenom: defaultLPDenom, - lockDuration: defaultLockDuration, - rewardAmount: sdk.Coins{sdk.NewInt64Coin(defaultRewardDenom, 3000)}, - } - doubleLengthGauge := perpGaugeDesc{ - lockDenom: defaultLPDenom, - lockDuration: 2 * defaultLockDuration, - rewardAmount: sdk.Coins{sdk.NewInt64Coin(defaultRewardDenom, 3000)}, - } - noRewardGauge := perpGaugeDesc{ - lockDenom: defaultLPDenom, - lockDuration: defaultLockDuration, - rewardAmount: sdk.Coins{}, - } - noRewardCoins := sdk.Coins{} - oneKRewardCoins := sdk.Coins{sdk.NewInt64Coin(defaultRewardDenom, 1000)} - twoKRewardCoins := sdk.Coins{sdk.NewInt64Coin(defaultRewardDenom, 2000)} - fiveKRewardCoins := sdk.Coins{sdk.NewInt64Coin(defaultRewardDenom, 5000)} - tests := []struct { - name string - users []userLocks - gauges []perpGaugeDesc - expectedRewards []sdk.Coins - }{ - // gauge 1 gives 3k coins. three locks, all eligible. 1k coins per lock. - // 1k should go to oneLockupUser and 2k to twoLockupUser. - { - name: "One user with one lockup, another user with two lockups, single default gauge", - users: []userLocks{oneLockupUser, twoLockupUser}, - gauges: []perpGaugeDesc{defaultGauge}, - expectedRewards: []sdk.Coins{oneKRewardCoins, twoKRewardCoins}, - }, - // gauge 1 gives 3k coins. three locks, all eligible. - // gauge 2 gives 3k coins. one lock, to twoLockupUser. - // 1k should to oneLockupUser and 5k to twoLockupUser. - { - name: "One user with one lockup (default gauge), another user with two lockups (double length gauge)", - users: []userLocks{oneLockupUser, twoLockupUser}, - gauges: []perpGaugeDesc{defaultGauge, doubleLengthGauge}, - expectedRewards: []sdk.Coins{oneKRewardCoins, fiveKRewardCoins}, - }, - // gauge 1 gives zero rewards. - // both oneLockupUser and twoLockupUser should get no rewards. - { - name: "One user with one lockup, another user with two lockups, both with no rewards gauge", - users: []userLocks{oneLockupUser, twoLockupUser}, - gauges: []perpGaugeDesc{noRewardGauge}, - expectedRewards: []sdk.Coins{noRewardCoins, noRewardCoins}, - }, - // gauge 1 gives no rewards. - // gauge 2 gives 3k coins. three locks, all eligible. 1k coins per lock. - // 1k should to oneLockupUser and 2k to twoLockupUser. - { - name: "One user with one lockup and another user with two lockups. No rewards and a default gauge", - users: []userLocks{oneLockupUser, twoLockupUser}, - gauges: []perpGaugeDesc{noRewardGauge, defaultGauge}, - expectedRewards: []sdk.Coins{oneKRewardCoins, twoKRewardCoins}, - }, - } - for _, tc := range tests { - suite.SetupTest() - // setup gauges and the locks defined in the above tests, then distribute to them - gauges := suite.SetupGauges(tc.gauges, defaultLPDenom) - addrs := suite.SetupUserLocks(tc.users) - _, err := suite.App.IncentivesKeeper.DistributeOnEpochEnd(suite.Ctx, gauges) - suite.Require().NoError(err) - // check expected rewards against actual rewards received - for i, addr := range addrs { - bal := suite.App.BankKeeper.GetAllBalances(suite.Ctx, addr) - suite.Require().Equal(tc.expectedRewards[i].String(), bal.String(), "test %v, person %d", tc.name, i) - } - } -} - -// TestGetModuleToDistributeCoins tests the sum of coins yet to be distributed for all of the module is correct. -func (suite *KeeperTestSuite) TestGetModuleToDistributeCoins() { - suite.SetupTest() - - // check that the sum of coins yet to be distributed is nil - coins := suite.App.IncentivesKeeper.GetModuleToDistributeCoins(suite.Ctx) - suite.Require().Equal(coins, sdk.Coins{}) - - // setup a non perpetual lock and gauge - _, gaugeID, gaugeCoins, startTime := suite.SetupLockAndGauge(false) - - // check that the sum of coins yet to be distributed is equal to the newly created gaugeCoins - coins = suite.App.IncentivesKeeper.GetModuleToDistributeCoins(suite.Ctx) - suite.Require().Equal(coins, gaugeCoins) - - // add coins to the previous gauge and check that the sum of coins yet to be distributed includes these new coins - addCoins := sdk.Coins{sdk.NewInt64Coin("stake", 200)} - suite.AddToGauge(addCoins, gaugeID) - coins = suite.App.IncentivesKeeper.GetModuleToDistributeCoins(suite.Ctx) - suite.Require().Equal(coins, gaugeCoins.Add(addCoins...)) - - // create a new gauge - // check that the sum of coins yet to be distributed is equal to the gauge1 and gauge2 coins combined - _, _, gaugeCoins2, _ := suite.SetupNewGauge(false, sdk.Coins{sdk.NewInt64Coin("stake", 1000)}) - coins = suite.App.IncentivesKeeper.GetModuleToDistributeCoins(suite.Ctx) - suite.Require().Equal(coins, gaugeCoins.Add(addCoins...).Add(gaugeCoins2...)) - - // move all created gauges from upcoming to active - suite.Ctx = suite.Ctx.WithBlockTime(startTime) - gauge, err := suite.App.IncentivesKeeper.GetGaugeByID(suite.Ctx, gaugeID) - suite.Require().NoError(err) - err = suite.App.IncentivesKeeper.MoveUpcomingGaugeToActiveGauge(suite.Ctx, *gauge) - suite.Require().NoError(err) - - // distribute coins to stakers - distrCoins, err := suite.App.IncentivesKeeper.DistributeOnEpochEnd(suite.Ctx, []types.Gauge{*gauge}) - suite.Require().NoError(err) - suite.Require().Equal(distrCoins, sdk.Coins{sdk.NewInt64Coin("stake", 105)}) - - // check gauge changes after distribution - coins = suite.App.IncentivesKeeper.GetModuleToDistributeCoins(suite.Ctx) - suite.Require().Equal(coins, gaugeCoins.Add(addCoins...).Add(gaugeCoins2...).Sub(distrCoins...)) -} - -// TestGetModuleDistributedCoins tests that the sum of coins that have been distributed so far for all of the module is correct. -func (suite *KeeperTestSuite) TestGetModuleDistributedCoins() { - suite.SetupTest() - - // check that the sum of coins yet to be distributed is nil - coins := suite.App.IncentivesKeeper.GetModuleDistributedCoins(suite.Ctx) - suite.Require().Equal(coins, sdk.Coins{}) - - // setup a non perpetual lock and gauge - _, gaugeID, _, startTime := suite.SetupLockAndGauge(false) - - // check that the sum of coins yet to be distributed is equal to the newly created gaugeCoins - coins = suite.App.IncentivesKeeper.GetModuleDistributedCoins(suite.Ctx) - suite.Require().Equal(coins, sdk.Coins{}) - - // move all created gauges from upcoming to active - suite.Ctx = suite.Ctx.WithBlockTime(startTime) - gauge, err := suite.App.IncentivesKeeper.GetGaugeByID(suite.Ctx, gaugeID) - suite.Require().NoError(err) - err = suite.App.IncentivesKeeper.MoveUpcomingGaugeToActiveGauge(suite.Ctx, *gauge) - suite.Require().NoError(err) - - // distribute coins to stakers - distrCoins, err := suite.App.IncentivesKeeper.DistributeOnEpochEnd(suite.Ctx, []types.Gauge{*gauge}) - suite.Require().NoError(err) - suite.Require().Equal(distrCoins, sdk.Coins{sdk.NewInt64Coin("stake", 5)}) - - // check gauge changes after distribution - coins = suite.App.IncentivesKeeper.GetModuleToDistributeCoins(suite.Ctx) - suite.Require().Equal(coins, distrCoins) -} - -// TestNoLockPerpetualGaugeDistribution tests that the creation of a perp gauge that has no locks associated does not distribute any tokens. -func (suite *KeeperTestSuite) TestNoLockPerpetualGaugeDistribution() { - suite.SetupTest() - - // setup a perpetual gauge with no associated locks - coins := sdk.Coins{sdk.NewInt64Coin("stake", 10)} - gaugeID, _, _, startTime := suite.SetupNewGauge(true, coins) - - // ensure the created gauge has not completed distribution - gauges := suite.App.IncentivesKeeper.GetNotFinishedGauges(suite.Ctx) - suite.Require().Len(gauges, 1) - - // ensure the not finished gauge matches the previously created gauge - expectedGauge := types.Gauge{ - Id: gaugeID, - IsPerpetual: true, - DistributeTo: &types.Gauge_Asset{Asset: &lockuptypes.QueryCondition{ - LockQueryType: lockuptypes.ByDuration, - Denom: "lptoken", - Duration: time.Second, - }}, - Coins: coins, - NumEpochsPaidOver: 1, - FilledEpochs: 0, - DistributedCoins: sdk.Coins{}, - StartTime: startTime, - } - suite.Require().Equal(gauges[0].String(), expectedGauge.String()) - - // move the created gauge from upcoming to active - suite.Ctx = suite.Ctx.WithBlockTime(startTime) - gauge, err := suite.App.IncentivesKeeper.GetGaugeByID(suite.Ctx, gaugeID) - suite.Require().NoError(err) - err = suite.App.IncentivesKeeper.MoveUpcomingGaugeToActiveGauge(suite.Ctx, *gauge) - suite.Require().NoError(err) - - // distribute coins to stakers, since it's perpetual distribute everything on single distribution - distrCoins, err := suite.App.IncentivesKeeper.DistributeOnEpochEnd(suite.Ctx, []types.Gauge{*gauge}) - suite.Require().NoError(err) - suite.Require().Equal(distrCoins, sdk.Coins{}) - - // check state is same after distribution - gauges = suite.App.IncentivesKeeper.GetNotFinishedGauges(suite.Ctx) - suite.Require().Len(gauges, 1) - suite.Require().Equal(gauges[0].String(), expectedGauge.String()) -} - -// TestNoLockNonPerpetualGaugeDistribution tests that the creation of a non perp gauge that has no locks associated does not distribute any tokens. -func (suite *KeeperTestSuite) TestNoLockNonPerpetualGaugeDistribution() { - suite.SetupTest() - - // setup non-perpetual gauge with no associated locks - coins := sdk.Coins{sdk.NewInt64Coin("stake", 10)} - gaugeID, _, _, startTime := suite.SetupNewGauge(false, coins) - - // ensure the created gauge has not completed distribution - gauges := suite.App.IncentivesKeeper.GetNotFinishedGauges(suite.Ctx) - suite.Require().Len(gauges, 1) - - // ensure the not finished gauge matches the previously created gauge - expectedGauge := types.Gauge{ - Id: gaugeID, - IsPerpetual: false, - DistributeTo: &types.Gauge_Asset{Asset: &lockuptypes.QueryCondition{ - LockQueryType: lockuptypes.ByDuration, - Denom: "lptoken", - Duration: time.Second, - }}, - Coins: coins, - NumEpochsPaidOver: 2, - FilledEpochs: 0, - DistributedCoins: sdk.Coins{}, - StartTime: startTime, - } - suite.Require().Equal(gauges[0].String(), expectedGauge.String()) - - // move the created gauge from upcoming to active - suite.Ctx = suite.Ctx.WithBlockTime(startTime) - gauge, err := suite.App.IncentivesKeeper.GetGaugeByID(suite.Ctx, gaugeID) - suite.Require().NoError(err) - err = suite.App.IncentivesKeeper.MoveUpcomingGaugeToActiveGauge(suite.Ctx, *gauge) - suite.Require().NoError(err) - - // distribute coins to stakers - distrCoins, err := suite.App.IncentivesKeeper.DistributeOnEpochEnd(suite.Ctx, []types.Gauge{*gauge}) - suite.Require().NoError(err) - suite.Require().Equal(distrCoins, sdk.Coins{}) - - // check state is same after distribution - gauges = suite.App.IncentivesKeeper.GetNotFinishedGauges(suite.Ctx) - suite.Require().Len(gauges, 1) - suite.Require().Equal(gauges[0].String(), expectedGauge.String()) -} diff --git a/x/dividends/keeper/export_test.go b/x/dividends/keeper/export_test.go deleted file mode 100644 index 4cc96a81..00000000 --- a/x/dividends/keeper/export_test.go +++ /dev/null @@ -1,37 +0,0 @@ -package keeper - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/dymensionxyz/dymension/v3/x/incentives/types" -) - -// AddGaugeRefByKey appends the provided gauge ID into an array associated with the provided key. -func (k Keeper) AddGaugeRefByKey(ctx sdk.Context, key []byte, gaugeID uint64) error { - return k.addGaugeRefByKey(ctx, key, gaugeID) -} - -// DeleteGaugeRefByKey removes the provided gauge ID from an array associated with the provided key. -func (k Keeper) DeleteGaugeRefByKey(ctx sdk.Context, key []byte, guageID uint64) error { - return k.deleteGaugeRefByKey(ctx, key, guageID) -} - -// GetGaugeRefs returns the gauge IDs specified by the provided key. -func (k Keeper) GetGaugeRefs(ctx sdk.Context, key []byte) []uint64 { - return k.getGaugeRefs(ctx, key) -} - -// GetAllGaugeIDsByDenom returns all active gauge-IDs associated with lockups of the provided denom. -func (k Keeper) GetAllGaugeIDsByDenom(ctx sdk.Context, denom string) []uint64 { - return k.getAllGaugeIDsByDenom(ctx, denom) -} - -// MoveUpcomingGaugeToActiveGauge moves a gauge that has reached it's start time from an upcoming to an active status. -func (k Keeper) MoveUpcomingGaugeToActiveGauge(ctx sdk.Context, gauge types.Gauge) error { - return k.moveUpcomingGaugeToActiveGauge(ctx, gauge) -} - -// MoveActiveGaugeToFinishedGauge moves a gauge that has completed its distribution from an active to a finished status. -func (k Keeper) MoveActiveGaugeToFinishedGauge(ctx sdk.Context, gauge types.Gauge) error { - return k.moveActiveGaugeToFinishedGauge(ctx, gauge) -} diff --git a/x/dividends/keeper/gauge.go b/x/dividends/keeper/gauge.go deleted file mode 100644 index f8202f08..00000000 --- a/x/dividends/keeper/gauge.go +++ /dev/null @@ -1,254 +0,0 @@ -package keeper - -import ( - "encoding/json" - "fmt" - "time" - - db "github.com/cometbft/cometbft-db" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/gogoproto/proto" - - "github.com/dymensionxyz/dymension-rdk/x/dividends/types" -) - -// getGaugesFromIterator iterates over everything in a gauge's iterator, until it reaches the end. Return all gauges iterated over. -func (k Keeper) getGaugesFromIterator(ctx sdk.Context, iterator db.Iterator) []types.Gauge { - gauges := []types.Gauge{} - defer iterator.Close() // nolint: errcheck - for ; iterator.Valid(); iterator.Next() { - gaugeIDs := []uint64{} - err := json.Unmarshal(iterator.Value(), &gaugeIDs) - if err != nil { - panic(err) - } - for _, gaugeID := range gaugeIDs { - gauge, err := k.GetGaugeByID(ctx, gaugeID) - if err != nil { - panic(err) - } - gauges = append(gauges, *gauge) - } - } - return gauges -} - -// setGauge set the gauge inside store. -func (k Keeper) setGauge(ctx sdk.Context, gauge *types.Gauge) error { - store := ctx.KVStore(k.storeKey) - bz, err := proto.Marshal(gauge) - if err != nil { - return err - } - store.Set(gaugeStoreKey(gauge.Id), bz) - return nil -} - -// CreateGaugeRefKeys takes combinedKey (the keyPrefix for upcoming, active, or finished gauges combined with gauge start time) and adds a reference to the respective gauge ID. -// If gauge is active or upcoming, creates reference between the denom and gauge ID. -// Used to consolidate codepaths for InitGenesis and CreateGauge. -func (k Keeper) CreateGaugeRefKeys(ctx sdk.Context, gauge *types.Gauge, combinedKeys []byte, activeOrUpcomingGauge bool) error { - if err := k.addGaugeRefByKey(ctx, combinedKeys, gauge.Id); err != nil { - return err - } - - // create denom reference for active or upcoming asset gauges - gaugeAsset := gauge.GetAsset() - if activeOrUpcomingGauge && gaugeAsset != nil { - if err := k.addGaugeIDForDenom(ctx, gauge.Id, gaugeAsset.Denom); err != nil { - return err - } - } - return nil -} - -// SetGaugeWithRefKey takes a single gauge and assigns a key. -// Takes combinedKey (the keyPrefix for upcoming, active, or finished gauges combined with gauge start time) and adds a reference to the respective gauge ID. -// If this gauge is active or upcoming, creates reference between the denom and gauge ID. -func (k Keeper) SetGaugeWithRefKey(ctx sdk.Context, gauge *types.Gauge) error { - err := k.setGauge(ctx, gauge) - if err != nil { - return err - } - - curTime := ctx.BlockTime() - timeKey := getTimeKey(gauge.StartTime) - activeOrUpcomingGauge := gauge.IsActiveGauge(curTime) || gauge.IsUpcomingGauge(curTime) - - if gauge.IsUpcomingGauge(curTime) { - combinedKeys := combineKeys(types.KeyPrefixUpcomingGauges, timeKey) - return k.CreateGaugeRefKeys(ctx, gauge, combinedKeys, activeOrUpcomingGauge) - } else if gauge.IsActiveGauge(curTime) { - combinedKeys := combineKeys(types.KeyPrefixActiveGauges, timeKey) - return k.CreateGaugeRefKeys(ctx, gauge, combinedKeys, activeOrUpcomingGauge) - } else { - combinedKeys := combineKeys(types.KeyPrefixFinishedGauges, timeKey) - return k.CreateGaugeRefKeys(ctx, gauge, combinedKeys, activeOrUpcomingGauge) - } -} - -// CreateGauge creates a gauge and sends coins to the gauge. -func (k Keeper) CreateGauge(ctx sdk.Context, isPerpetual bool, owner sdk.AccAddress, coins sdk.Coins, distrTo lockuptypes.QueryCondition, startTime time.Time, numEpochsPaidOver uint64) (uint64, error) { - // Ensure that this gauge's duration is one of the allowed durations on chain - durations := k.GetLockableDurations(ctx) - if distrTo.LockQueryType == lockuptypes.ByDuration { - durationOk := false - for _, duration := range durations { - if duration == distrTo.Duration { - durationOk = true - break - } - } - if !durationOk { - return 0, fmt.Errorf("invalid duration: %d", distrTo.Duration) - } - } - - // Ensure that the denom this gauge pays out to exists on-chain - if !k.bk.HasSupply(ctx, distrTo.Denom) { - return 0, fmt.Errorf("denom does not exist: %s", distrTo.Denom) - } - - gauge := types.NewAssetGauge(k.GetLastGaugeID(ctx)+1, isPerpetual, distrTo, coins, startTime, numEpochsPaidOver) - - if err := k.bk.SendCoinsFromAccountToModule(ctx, owner, types.ModuleName, gauge.Coins); err != nil { - return 0, err - } - - err := k.setGauge(ctx, &gauge) - if err != nil { - return 0, err - } - k.SetLastGaugeID(ctx, gauge.Id) - - combinedKeys := combineKeys(types.KeyPrefixUpcomingGauges, getTimeKey(gauge.StartTime)) - activeOrUpcomingGauge := true - - err = k.CreateGaugeRefKeys(ctx, &gauge, combinedKeys, activeOrUpcomingGauge) - if err != nil { - return 0, err - } - k.hooks.AfterCreateGauge(ctx, gauge.Id) - return gauge.Id, nil -} - -// AddToGaugeRewards adds coins to gauge. -func (k Keeper) AddToGaugeRewards(ctx sdk.Context, owner sdk.AccAddress, coins sdk.Coins, gauge *types.Gauge) error { - if gauge.IsFinishedGauge(ctx.BlockTime()) { - return types.UnexpectedFinishedGaugeError{GaugeId: gauge.Id} - } - - if err := k.bk.SendCoinsFromAccountToModule(ctx, owner, types.ModuleName, coins); err != nil { - return err - } - - gauge.Coins = gauge.Coins.Add(coins...) - err := k.setGauge(ctx, gauge) - if err != nil { - return err - } - k.hooks.AfterAddToGauge(ctx, gauge.Id) - return nil -} - -// GetGaugeByID returns gauge from gauge ID. -func (k Keeper) GetGaugeByID(ctx sdk.Context, gaugeID uint64) (*types.Gauge, error) { - gauge := types.Gauge{} - store := ctx.KVStore(k.storeKey) - gaugeKey := gaugeStoreKey(gaugeID) - if !store.Has(gaugeKey) { - return nil, fmt.Errorf("gauge with ID %d does not exist", gaugeID) - } - bz := store.Get(gaugeKey) - if err := proto.Unmarshal(bz, &gauge); err != nil { - return nil, err - } - return &gauge, nil -} - -// GetGaugesForDenom returns the gauge for a given denom. -// ActiveGaugesPerDenom returns all active gauges for the specified denom. -func (k Keeper) GetGaugesForDenom(ctx sdk.Context, denom string) ([]types.Gauge, error) { - _, gauges, err := k.filterByPrefixAndDenom(ctx, types.KeyPrefixGauges, denom, nil) - if err != nil { - return nil, err - } - - return gauges, nil -} - -// GetGaugeFromIDs returns multiple gauges from a gaugeIDs array. -func (k Keeper) GetGaugeFromIDs(ctx sdk.Context, gaugeIDs []uint64) ([]types.Gauge, error) { - gauges := []types.Gauge{} - for _, gaugeID := range gaugeIDs { - gauge, err := k.GetGaugeByID(ctx, gaugeID) - if err != nil { - return []types.Gauge{}, err - } - gauges = append(gauges, *gauge) - } - return gauges, nil -} - -// GetGauges returns upcoming, active, and finished gauges. -func (k Keeper) GetGauges(ctx sdk.Context) []types.Gauge { - return k.getGaugesFromIterator(ctx, k.GaugesIterator(ctx)) -} - -// GetNotFinishedGauges returns both upcoming and active gauges. -func (k Keeper) GetNotFinishedGauges(ctx sdk.Context) []types.Gauge { - return append(k.GetActiveGauges(ctx), k.GetUpcomingGauges(ctx)...) -} - -// GetActiveGauges returns active gauges. -func (k Keeper) GetActiveGauges(ctx sdk.Context) []types.Gauge { - return k.getGaugesFromIterator(ctx, k.ActiveGaugesIterator(ctx)) -} - -// GetUpcomingGauges returns upcoming gauges. -func (k Keeper) GetUpcomingGauges(ctx sdk.Context) []types.Gauge { - return k.getGaugesFromIterator(ctx, k.UpcomingGaugesIterator(ctx)) -} - -// GetFinishedGauges returns finished gauges. -func (k Keeper) GetFinishedGauges(ctx sdk.Context) []types.Gauge { - return k.getGaugesFromIterator(ctx, k.FinishedGaugesIterator(ctx)) -} - -// moveUpcomingGaugeToActiveGauge moves a gauge that has reached it's start time from an upcoming to an active status. -func (k Keeper) moveUpcomingGaugeToActiveGauge(ctx sdk.Context, gauge types.Gauge) error { - // validation for current time and distribution start time - if ctx.BlockTime().Before(gauge.StartTime) { - return fmt.Errorf("gauge is not able to start distribution yet: %s >= %s", ctx.BlockTime().String(), gauge.StartTime.String()) - } - - timeKey := getTimeKey(gauge.StartTime) - if err := k.deleteGaugeRefByKey(ctx, combineKeys(types.KeyPrefixUpcomingGauges, timeKey), gauge.Id); err != nil { - return err - } - if err := k.addGaugeRefByKey(ctx, combineKeys(types.KeyPrefixActiveGauges, timeKey), gauge.Id); err != nil { - return err - } - return nil -} - -// moveActiveGaugeToFinishedGauge moves a gauge that has completed its distribution from an active to a finished status. -func (k Keeper) moveActiveGaugeToFinishedGauge(ctx sdk.Context, gauge types.Gauge) error { - timeKey := getTimeKey(gauge.StartTime) - if err := k.deleteGaugeRefByKey(ctx, combineKeys(types.KeyPrefixActiveGauges, timeKey), gauge.Id); err != nil { - return err - } - if err := k.addGaugeRefByKey(ctx, combineKeys(types.KeyPrefixFinishedGauges, timeKey), gauge.Id); err != nil { - return err - } - - // delete denom reference for active or upcoming asset gauges - gaugeAsset := gauge.GetAsset() - if gaugeAsset != nil { - if err := k.deleteGaugeIDForDenom(ctx, gauge.Id, gaugeAsset.Denom); err != nil { - return err - } - } - k.hooks.GaugeFinished(ctx, gauge.Id) - return nil -} diff --git a/x/dividends/keeper/gauge_asset.go b/x/dividends/keeper/gauge_asset.go deleted file mode 100644 index 4f9cf6a2..00000000 --- a/x/dividends/keeper/gauge_asset.go +++ /dev/null @@ -1,225 +0,0 @@ -package keeper - -import ( - "fmt" - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/dymensionxyz/dymension/v3/x/incentives/types" - lockuptypes "github.com/dymensionxyz/dymension/v3/x/lockup/types" -) - -// RewardDistributionTracker maintains the state of pending reward distributions, -// tracking both total rewards and per-gauge rewards for each recipient. -// It uses array-based storage for better cache locality during distribution. -type RewardDistributionTracker struct { - nextID int // Next available ID for new recipients - lockOwnerAddrToID map[string]int // Maps lock owner addresses to their array index - idToBech32Addr []string // Recipient bech32 addresses indexed by ID - idToDecodedAddr []sdk.AccAddress // Decoded recipient addresses indexed by ID - idToDistrCoins []sdk.Coins // Total rewards per recipient indexed by ID - idToGaugeRewards []map[uint64]sdk.Coins // Per-gauge rewards for each recipient indexed by ID -} - -// NewRewardDistributionTracker creates a new tracker for managing reward distributions -func NewRewardDistributionTracker() RewardDistributionTracker { - return RewardDistributionTracker{ - nextID: 0, - lockOwnerAddrToID: make(map[string]int), - idToBech32Addr: []string{}, - idToDecodedAddr: []sdk.AccAddress{}, - idToDistrCoins: []sdk.Coins{}, - idToGaugeRewards: []map[uint64]sdk.Coins{}, - } -} - -// getLocksToDistributionWithMaxDuration returns locks that match the provided lockuptypes QueryCondition, -// are greater than the provided minDuration, AND have yet to be distributed to. -func (k Keeper) getLocksToDistributionWithMaxDuration(ctx sdk.Context, distrTo lockuptypes.QueryCondition, minDuration time.Duration) []lockuptypes.PeriodLock { - switch distrTo.LockQueryType { - case lockuptypes.ByDuration: - // TODO: what the meaning of minDuration here? it's set to time.Millisecond in the caller. - duration := min(distrTo.Duration, minDuration) - return k.lk.GetLocksLongerThanDurationDenom(ctx, distrTo.Denom, duration) - case lockuptypes.ByTime: - panic("Gauge by time is present, however is no longer supported. This should have been blocked in ValidateBasic") - default: - } - return []lockuptypes.PeriodLock{} -} - -// addLockRewards adds the provided rewards to the lockID mapped to the provided owner address. -func (d *RewardDistributionTracker) addLockRewards(owner string, gaugeID uint64, rewards sdk.Coins) error { - if id, ok := d.lockOwnerAddrToID[owner]; ok { - // Update total rewards - oldDistrCoins := d.idToDistrCoins[id] - d.idToDistrCoins[id] = rewards.Add(oldDistrCoins...) - - // Update gauge rewards (idToGaugeRewards[id] already initialized on first creation) - if existing, ok := d.idToGaugeRewards[id][gaugeID]; ok { - d.idToGaugeRewards[id][gaugeID] = existing.Add(rewards...) - } else { - d.idToGaugeRewards[id][gaugeID] = rewards - } - } else { - id := d.nextID - d.nextID++ - d.lockOwnerAddrToID[owner] = id - decodedOwnerAddr, err := sdk.AccAddressFromBech32(owner) - if err != nil { - return err - } - d.idToBech32Addr = append(d.idToBech32Addr, owner) - d.idToDecodedAddr = append(d.idToDecodedAddr, decodedOwnerAddr) - d.idToDistrCoins = append(d.idToDistrCoins, rewards) - - // Initialize and set gauge rewards - gaugeRewards := make(map[uint64]sdk.Coins) - gaugeRewards[gaugeID] = rewards - d.idToGaugeRewards = append(d.idToGaugeRewards, gaugeRewards) - } - return nil -} - -// GetEvents returns distribution events for all recipients. -// For each recipient, it creates a single event with attributes for each gauge's rewards. -func (d *RewardDistributionTracker) GetEvents() sdk.Events { - events := make(sdk.Events, 0, len(d.idToBech32Addr)) - - for id := 0; id < len(d.idToBech32Addr); id++ { - attributes := []sdk.Attribute{ - sdk.NewAttribute(types.AttributeReceiver, d.idToBech32Addr[id]), - sdk.NewAttribute(types.AttributeAmount, d.idToDistrCoins[id].String()), - } - - // Add attributes for each gauge's rewards (events doesn't requires deterministic order) - for gaugeID, gaugeRewards := range d.idToGaugeRewards[id] { - attributes = append(attributes, - sdk.NewAttribute( - fmt.Sprintf("%s_%d", types.AttributeGaugeID, gaugeID), - gaugeRewards.String(), - ), - ) - } - - events = append(events, sdk.NewEvent( - types.TypeEvtDistribution, - attributes..., - )) - } - - return events -} - -// distributeTrackedRewards sends the tracked rewards from the module account to recipients -// and emits corresponding events for each gauge's rewards. -func (k Keeper) distributeTrackedRewards(ctx sdk.Context, tracker *RewardDistributionTracker) error { - numIDs := len(tracker.idToDecodedAddr) - if len(tracker.idToDistrCoins) != numIDs || len(tracker.idToGaugeRewards) != numIDs { - return fmt.Errorf("number of addresses, coins, and gauge rewards to distribute must be equal") - } - ctx.Logger().Debug("Beginning distribution to users", "num_of_user", numIDs) - - // First send all rewards - for id := 0; id < numIDs; id++ { - err := k.bk.SendCoinsFromModuleToAccount( - ctx, - types.ModuleName, - tracker.idToDecodedAddr[id], - tracker.idToDistrCoins[id]) - if err != nil { - return err - } - } - - // Emit all events - ctx.EventManager().EmitEvents(tracker.GetEvents()) - - ctx.Logger().Debug("Finished Distributing to users") - return nil -} - -// calculateAssetGaugeRewards computes the reward distribution for an asset gauge based on lock amounts. -// It calculates rewards for each qualifying lock and tracks them in the distribution tracker. -// Returns the total coins allocated for distribution. -func (k Keeper) calculateAssetGaugeRewards(ctx sdk.Context, gauge types.Gauge, locks []lockuptypes.PeriodLock, tracker *RewardDistributionTracker) (sdk.Coins, error) { - assetDist := gauge.GetAsset() - if assetDist == nil { - return sdk.Coins{}, fmt.Errorf("gauge %d is not an asset gauge", gauge.Id) - } - - denom := assetDist.Denom - lockSum := lockuptypes.SumLocksByDenom(locks, denom) - - if lockSum.IsZero() { - return sdk.Coins{}, nil - } - - remainCoins := gauge.Coins.Sub(gauge.DistributedCoins...) - // if it's a perpetual gauge, we set remaining epochs to 1. - // otherwise it is a non perpetual gauge and we determine how many epoch payouts are left - remainEpochs := uint64(1) - if !gauge.IsPerpetual { - remainEpochs = gauge.NumEpochsPaidOver - gauge.FilledEpochs - } - - /* ---------------------------- defense in depth ---------------------------- */ - // this should never happen in practice since gauge passed in should always be an active gauge. - if remainEpochs == 0 { - ctx.Logger().Error(fmt.Sprintf("gauge %d has no remaining epochs, skipping", gauge.Id)) - return sdk.Coins{}, nil - } - - // this should never happen in practice - if remainCoins.Empty() { - ctx.Logger().Error(fmt.Sprintf("gauge %d is empty, skipping", gauge.Id)) - return sdk.Coins{}, nil - } - - totalDistrCoins := sdk.NewCoins() - for _, lock := range locks { - distrCoins := sdk.Coins{} - for _, coin := range remainCoins { - // distribution amount = gauge_size * denom_lock_amount / (total_denom_lock_amount * remain_epochs) - denomLockAmt := lock.Coins.AmountOfNoDenomValidation(denom) - amt := coin.Amount.Mul(denomLockAmt).Quo(lockSum.Mul(sdk.NewInt(int64(remainEpochs)))) - if amt.IsPositive() { - newlyDistributedCoin := sdk.Coin{Denom: coin.Denom, Amount: amt} - distrCoins = distrCoins.Add(newlyDistributedCoin) - } - } - distrCoins = distrCoins.Sort() - if distrCoins.Empty() { - continue - } - // update the amount for that address - err := tracker.addLockRewards(lock.Owner, gauge.Id, distrCoins) - if err != nil { - return sdk.Coins{}, err - } - - totalDistrCoins = totalDistrCoins.Add(distrCoins...) - } - - return totalDistrCoins, nil -} - -// GetDistributeToBaseLocks takes a gauge along with cached period locks by denom and returns locks that must be distributed to -func (k Keeper) GetDistributeToBaseLocks(ctx sdk.Context, gauge types.Gauge, cache types.DenomLocksCache) []lockuptypes.PeriodLock { - // if gauge is empty, don't get the locks - if gauge.Coins.Empty() { - return []lockuptypes.PeriodLock{} - } - - // All gauges have a precondition of being ByDuration. - asset := gauge.GetAsset() // this should never be nil - distributeBaseDenom := asset.Denom - if _, ok := cache[distributeBaseDenom]; !ok { - cache[distributeBaseDenom] = k.getLocksToDistributionWithMaxDuration(ctx, *asset, time.Millisecond) - } - // get this from memory instead of hitting iterators / underlying stores. - // due to many details of cacheKVStore, iteration will still cause expensive IAVL reads. - allLocks := cache[distributeBaseDenom] - return FilterLocksByMinDuration(allLocks, asset.Duration) -} diff --git a/x/dividends/keeper/gauge_rollapp.go b/x/dividends/keeper/gauge_rollapp.go deleted file mode 100644 index aa9229c1..00000000 --- a/x/dividends/keeper/gauge_rollapp.go +++ /dev/null @@ -1,60 +0,0 @@ -package keeper - -import ( - "fmt" - - "github.com/dymensionxyz/dymension/v3/x/incentives/types" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// CreateRollappGauge creates a gauge and sends coins to the gauge. -func (k Keeper) CreateRollappGauge(ctx sdk.Context, rollappId string) (uint64, error) { - // Ensure the rollapp exists - _, found := k.rk.GetRollapp(ctx, rollappId) - if !found { - return 0, fmt.Errorf("rollapp %s not found", rollappId) - } - - gauge := types.NewRollappGauge(k.GetLastGaugeID(ctx)+1, rollappId) - - err := k.setGauge(ctx, &gauge) - if err != nil { - return 0, err - } - k.SetLastGaugeID(ctx, gauge.Id) - - combinedKeys := combineKeys(types.KeyPrefixUpcomingGauges, getTimeKey(gauge.StartTime)) - err = k.CreateGaugeRefKeys(ctx, &gauge, combinedKeys, true) - if err != nil { - return 0, err - } - k.hooks.AfterCreateGauge(ctx, gauge.Id) - return gauge.Id, nil -} - -// calculateRollappGaugeRewards computes the reward distribution for a rollapp gauge. -// Returns the total coins allocated for distribution. -func (k Keeper) calculateRollappGaugeRewards(ctx sdk.Context, gauge types.Gauge, tracker *RewardDistributionTracker) (sdk.Coins, error) { - // Get the rollapp owner - rollapp, found := k.rk.GetRollapp(ctx, gauge.GetRollapp().RollappId) - if !found { - return sdk.Coins{}, fmt.Errorf("gauge %d: rollapp %s not found", gauge.Id, gauge.GetRollapp().RollappId) - } - // Ignore the error since the owner must always be valid in x/rollapp - owner := rollapp.Owner - - totalDistrCoins := gauge.Coins.Sub(gauge.DistributedCoins...) // distribute all remaining coins - if totalDistrCoins.Empty() { - ctx.Logger().Debug(fmt.Sprintf("gauge %d is empty, skipping", gauge.Id)) - return sdk.Coins{}, nil - } - - // Add rewards to the tracker - err := tracker.addLockRewards(owner, gauge.Id, totalDistrCoins) - if err != nil { - return sdk.Coins{}, err - } - - return totalDistrCoins, nil -} diff --git a/x/dividends/keeper/gauge_rollapp_test.go b/x/dividends/keeper/gauge_rollapp_test.go deleted file mode 100644 index 82eff8c6..00000000 --- a/x/dividends/keeper/gauge_rollapp_test.go +++ /dev/null @@ -1,147 +0,0 @@ -package keeper_test - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/dymensionxyz/dymension/v3/app/apptesting" - "github.com/dymensionxyz/dymension/v3/x/incentives/types" -) - -// TestDistributeToRollappGauges tests distributing rewards to rollapp gauges. -func (suite *KeeperTestSuite) TestDistributeToRollappGauges() { - oneKRewardCoins := sdk.Coins{sdk.NewInt64Coin(defaultRewardDenom, 1000)} - addrs := apptesting.CreateRandomAccounts(1) - - testCases := []struct { - name string - rewards sdk.Coins - rollappOwner sdk.AccAddress - }{ - { - name: "rollapp gauge", - rewards: oneKRewardCoins, - rollappOwner: addrs[0], - }, - { - name: "rollapp gauge with no rewards", - rewards: sdk.Coins{}, - rollappOwner: addrs[0], - }, - } - - for _, tc := range testCases { - suite.Run(tc.name, func() { - suite.SetupTest() - - // Create rollapp and check rollapp gauge created - _ = suite.CreateDefaultRollapp(tc.rollappOwner) - res, err := suite.querier.RollappGauges(sdk.WrapSDKContext(suite.Ctx), new(types.GaugesRequest)) - suite.Require().NoError(err) - suite.Require().NotNil(res) - suite.Require().Len(res.Data, 1) - suite.Require().NotNil(res.Data[0].GetRollapp()) - - gaugeId := res.Data[0].Id - - // Top up the gauge before distributing - if tc.rewards.Len() > 0 { - suite.AddToGauge(tc.rewards, gaugeId) - } - - gauge, err := suite.App.IncentivesKeeper.GetGaugeByID(suite.Ctx, gaugeId) - suite.Require().NoError(err) - - // Distribute to the rollapp owner - _, err = suite.App.IncentivesKeeper.DistributeOnEpochEnd(suite.Ctx, []types.Gauge{*gauge}) - suite.Require().NoError(err) - - // Check expected rewards against actual rewards received - ownerBalances := suite.App.BankKeeper.GetAllBalances(suite.Ctx, tc.rollappOwner) - suite.Require().ElementsMatch(tc.rewards, ownerBalances, "expect: %v, actual: %v", tc.rewards, ownerBalances) - }) - } -} - -// TestDistributeToRollappGaugesAfterOwnerChange tests distributing rewards to rollapp gauges given the -// fact that the owner might change. The test: -// 1. Distributes rewards to the gauge with the initial owner -// 2. Changes the rollapp owner -// 3. Distributes rewards to the gauge with the final owner -// 4. Validates balances of both initial and final owners -func (suite *KeeperTestSuite) TestDistributeToRollappGaugesAfterOwnerChange() { - oneKRewardCoins := sdk.Coins{sdk.NewInt64Coin(defaultRewardDenom, 1000)} - addrs := apptesting.CreateRandomAccounts(2) - - testCases := []struct { - name string - rewards sdk.Coins - initialOwner sdk.AccAddress - finalOwner sdk.AccAddress - }{ - { - name: "rollapp gauge", - rewards: oneKRewardCoins, - initialOwner: addrs[0], - finalOwner: addrs[1], - }, - { - name: "rollapp gauge with no rewards", - rewards: sdk.Coins{}, - initialOwner: addrs[0], - finalOwner: addrs[1], - }, - } - - for _, tc := range testCases { - suite.Run(tc.name, func() { - suite.SetupTest() - - // Create rollapp and check rollapp gauge created - _ = suite.CreateDefaultRollapp(tc.initialOwner) - res, err := suite.querier.RollappGauges(sdk.WrapSDKContext(suite.Ctx), new(types.GaugesRequest)) - suite.Require().NoError(err) - suite.Require().NotNil(res) - suite.Require().Len(res.Data, 1) - suite.Require().NotNil(res.Data[0].GetRollapp()) - - gaugeId := res.Data[0].Id - rollappID := res.Data[0].GetRollapp().RollappId - - // Distribute to the initial owner - { - if tc.rewards.Len() > 0 { - suite.AddToGauge(tc.rewards, gaugeId) - } - - gauge, err := suite.App.IncentivesKeeper.GetGaugeByID(suite.Ctx, gaugeId) - suite.Require().NoError(err) - - _, err = suite.App.IncentivesKeeper.DistributeOnEpochEnd(suite.Ctx, []types.Gauge{*gauge}) - suite.Require().NoError(err) - } - - // Transfer rollapp ownership - suite.TransferRollappOwnership(tc.initialOwner, tc.finalOwner, rollappID) - - // Distribute to the final owner - { - if tc.rewards.Len() > 0 { - suite.AddToGauge(tc.rewards, gaugeId) - } - - gauge, err := suite.App.IncentivesKeeper.GetGaugeByID(suite.Ctx, gaugeId) - suite.Require().NoError(err) - - _, err = suite.App.IncentivesKeeper.DistributeOnEpochEnd(suite.Ctx, []types.Gauge{*gauge}) - suite.Require().NoError(err) - } - - // Check expected rewards against actual rewards received - initialOwnerBalances := suite.App.BankKeeper.GetAllBalances(suite.Ctx, tc.initialOwner) - suite.Require().ElementsMatch(tc.rewards, initialOwnerBalances, "expect: %v, actual: %v", tc.rewards, initialOwnerBalances) - - finalOwnerBalances := suite.App.BankKeeper.GetAllBalances(suite.Ctx, tc.finalOwner) - suite.Require().ElementsMatch(tc.rewards, finalOwnerBalances, "expect: %v, actual: %v", tc.rewards, finalOwnerBalances) - }) - } -} diff --git a/x/dividends/keeper/gauge_test.go b/x/dividends/keeper/gauge_test.go deleted file mode 100644 index 774fe22a..00000000 --- a/x/dividends/keeper/gauge_test.go +++ /dev/null @@ -1,226 +0,0 @@ -package keeper_test - -import ( - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/stretchr/testify/suite" - - "github.com/dymensionxyz/dymension/v3/x/incentives/types" - lockuptypes "github.com/dymensionxyz/dymension/v3/x/lockup/types" -) - -var _ = suite.TestingSuite(nil) - -// TestInvalidDurationGaugeCreationValidation tests error handling for creating a gauge with an invalid duration. -func (suite *KeeperTestSuite) TestInvalidDurationGaugeCreationValidation() { - suite.SetupTest() - - addrs := suite.SetupManyLocks(1, defaultLiquidTokens, defaultLPTokens, defaultLockDuration) - distrTo := lockuptypes.QueryCondition{ - LockQueryType: lockuptypes.ByDuration, - Denom: defaultLPDenom, - Duration: defaultLockDuration / 2, // 0.5 second, invalid duration - } - _, err := suite.App.IncentivesKeeper.CreateGauge(suite.Ctx, false, addrs[0], defaultLiquidTokens, distrTo, time.Time{}, 1) - suite.Require().Error(err) - - distrTo.Duration = defaultLockDuration - _, err = suite.App.IncentivesKeeper.CreateGauge(suite.Ctx, false, addrs[0], defaultLiquidTokens, distrTo, time.Time{}, 1) - suite.Require().NoError(err) -} - -// TestNonExistentDenomGaugeCreation tests error handling for creating a gauge with an invalid denom. -func (suite *KeeperTestSuite) TestNonExistentDenomGaugeCreation() { - suite.SetupTest() - - addrNoSupply := sdk.AccAddress([]byte("Gauge_Creation_Addr_")) - addrs := suite.SetupManyLocks(1, defaultLiquidTokens, defaultLPTokens, defaultLockDuration) - distrTo := lockuptypes.QueryCondition{ - LockQueryType: lockuptypes.ByDuration, - Denom: defaultLPDenom, - Duration: defaultLockDuration, - } - _, err := suite.App.IncentivesKeeper.CreateGauge(suite.Ctx, false, addrNoSupply, defaultLiquidTokens, distrTo, time.Time{}, 1) - suite.Require().Error(err) - - _, err = suite.App.IncentivesKeeper.CreateGauge(suite.Ctx, false, addrs[0], defaultLiquidTokens, distrTo, time.Time{}, 1) - suite.Require().NoError(err) -} - -// TestGaugeOperations tests perpetual and non-perpetual gauge distribution logic using the gauges by denom keeper. -func (suite *KeeperTestSuite) TestGaugeOperations() { - testCases := []struct { - isPerpetual bool - numLocks int - }{ - { - isPerpetual: true, - numLocks: 1, - }, - { - isPerpetual: false, - numLocks: 1, - }, - { - isPerpetual: true, - numLocks: 2, - }, - { - isPerpetual: false, - numLocks: 2, - }, - } - for _, tc := range testCases { - // test for module get gauges - suite.SetupTest() - - // initial module gauges check - gauges := suite.App.IncentivesKeeper.GetNotFinishedGauges(suite.Ctx) - suite.Require().Len(gauges, 0) - gaugeIdsByDenom := suite.App.IncentivesKeeper.GetAllGaugeIDsByDenom(suite.Ctx, "lptoken") - suite.Require().Len(gaugeIdsByDenom, 0) - - // setup lock and gauge - _ = suite.SetupManyLocks(tc.numLocks, defaultLiquidTokens, defaultLPTokens, time.Second) - gaugeID, _, coins, startTime := suite.SetupNewGauge(tc.isPerpetual, sdk.Coins{sdk.NewInt64Coin("stake", 12)}) - // set expected epochs - var expectedNumEpochsPaidOver int - if tc.isPerpetual { - expectedNumEpochsPaidOver = 1 - } else { - expectedNumEpochsPaidOver = 2 - } - - // check gauges - gauges = suite.App.IncentivesKeeper.GetNotFinishedGauges(suite.Ctx) - suite.Require().Len(gauges, 1) - expectedGauge := types.Gauge{ - Id: gaugeID, - IsPerpetual: tc.isPerpetual, - DistributeTo: &types.Gauge_Asset{Asset: &lockuptypes.QueryCondition{ - LockQueryType: lockuptypes.ByDuration, - Denom: "lptoken", - Duration: time.Second, - }}, - Coins: coins, - NumEpochsPaidOver: uint64(expectedNumEpochsPaidOver), - FilledEpochs: 0, - DistributedCoins: sdk.Coins{}, - StartTime: startTime, - } - suite.Require().Equal(expectedGauge.String(), gauges[0].String()) - - // check gauge ids by denom - gaugeIdsByDenom = suite.App.IncentivesKeeper.GetAllGaugeIDsByDenom(suite.Ctx, "lptoken") - suite.Require().Len(gaugeIdsByDenom, 1) - suite.Require().Equal(gaugeID, gaugeIdsByDenom[0]) - - // check gauges - gauges = suite.App.IncentivesKeeper.GetNotFinishedGauges(suite.Ctx) - suite.Require().Len(gauges, 1) - suite.Require().Equal(expectedGauge.String(), gauges[0].String()) - - // check upcoming gauges - gauges = suite.App.IncentivesKeeper.GetUpcomingGauges(suite.Ctx) - suite.Require().Len(gauges, 1) - - // start distribution - suite.Ctx = suite.Ctx.WithBlockTime(startTime) - gauge, err := suite.App.IncentivesKeeper.GetGaugeByID(suite.Ctx, gaugeID) - suite.Require().NoError(err) - err = suite.App.IncentivesKeeper.MoveUpcomingGaugeToActiveGauge(suite.Ctx, *gauge) - suite.Require().NoError(err) - - // check active gauges - gauges = suite.App.IncentivesKeeper.GetActiveGauges(suite.Ctx) - suite.Require().Len(gauges, 1) - - // check upcoming gauges - gauges = suite.App.IncentivesKeeper.GetUpcomingGauges(suite.Ctx) - suite.Require().Len(gauges, 0) - - // check gauge ids by denom - gaugeIdsByDenom = suite.App.IncentivesKeeper.GetAllGaugeIDsByDenom(suite.Ctx, "lptoken") - suite.Require().Len(gaugeIdsByDenom, 1) - - // check gauge ids by other denom - gaugeIdsByDenom = suite.App.IncentivesKeeper.GetAllGaugeIDsByDenom(suite.Ctx, "lpt") - suite.Require().Len(gaugeIdsByDenom, 0) - - // distribute coins to stakers - distrCoins, err := suite.App.IncentivesKeeper.DistributeOnEpochEnd(suite.Ctx, []types.Gauge{*gauge}) - suite.Require().NoError(err) - // We hardcoded 12 "stake" tokens when initializing gauge - suite.Require().Equal(sdk.Coins{sdk.NewInt64Coin("stake", int64(12/expectedNumEpochsPaidOver))}, distrCoins) - - if tc.isPerpetual { - // distributing twice without adding more for perpetual gauge - gauge, err = suite.App.IncentivesKeeper.GetGaugeByID(suite.Ctx, gaugeID) - suite.Require().NoError(err) - distrCoins, err = suite.App.IncentivesKeeper.DistributeOnEpochEnd(suite.Ctx, []types.Gauge{*gauge}) - suite.Require().NoError(err) - suite.Require().True(distrCoins.Empty()) - - // add to gauge - addCoins := sdk.Coins{sdk.NewInt64Coin("stake", 200)} - suite.AddToGauge(addCoins, gaugeID) - - // distributing twice with adding more for perpetual gauge - gauge, err = suite.App.IncentivesKeeper.GetGaugeByID(suite.Ctx, gaugeID) - suite.Require().NoError(err) - distrCoins, err = suite.App.IncentivesKeeper.DistributeOnEpochEnd(suite.Ctx, []types.Gauge{*gauge}) - suite.Require().NoError(err) - suite.Require().Equal(sdk.Coins{sdk.NewInt64Coin("stake", 200)}, distrCoins) - } else { - // add to gauge - addCoins := sdk.Coins{sdk.NewInt64Coin("stake", 200)} - suite.AddToGauge(addCoins, gaugeID) - } - - // check active gauges - gauges = suite.App.IncentivesKeeper.GetActiveGauges(suite.Ctx) - suite.Require().Len(gauges, 1) - - // check gauge ids by denom - gaugeIdsByDenom = suite.App.IncentivesKeeper.GetAllGaugeIDsByDenom(suite.Ctx, "lptoken") - suite.Require().Len(gaugeIdsByDenom, 1) - - // finish distribution for non perpetual gauge - if !tc.isPerpetual { - err = suite.App.IncentivesKeeper.MoveActiveGaugeToFinishedGauge(suite.Ctx, *gauge) - suite.Require().NoError(err) - } - - // check non-perpetual gauges (finished + rewards estimate empty) - if !tc.isPerpetual { - - // check finished gauges - gauges = suite.App.IncentivesKeeper.GetFinishedGauges(suite.Ctx) - suite.Require().Len(gauges, 1) - - // check gauge by ID - gauge, err = suite.App.IncentivesKeeper.GetGaugeByID(suite.Ctx, gaugeID) - suite.Require().NoError(err) - suite.Require().NotNil(gauge) - suite.Require().Equal(gauges[0], *gauge) - - // check invalid gauge ID - _, err = suite.App.IncentivesKeeper.GetGaugeByID(suite.Ctx, gaugeID+1000) - suite.Require().Error(err) - - // check gauge ids by denom - gaugeIdsByDenom = suite.App.IncentivesKeeper.GetAllGaugeIDsByDenom(suite.Ctx, "lptoken") - suite.Require().Len(gaugeIdsByDenom, 0) - } else { // check perpetual gauges (not finished + rewards estimate empty) - - // check finished gauges - gauges = suite.App.IncentivesKeeper.GetFinishedGauges(suite.Ctx) - suite.Require().Len(gauges, 0) - - // check gauge ids by denom - gaugeIdsByDenom = suite.App.IncentivesKeeper.GetAllGaugeIDsByDenom(suite.Ctx, "lptoken") - suite.Require().Len(gaugeIdsByDenom, 1) - } - } -} diff --git a/x/dividends/keeper/genesis.go b/x/dividends/keeper/genesis.go index 49fabfb4..c301bda0 100644 --- a/x/dividends/keeper/genesis.go +++ b/x/dividends/keeper/genesis.go @@ -3,29 +3,12 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/dymensionxyz/dymension/v3/x/incentives/types" + "github.com/dymensionxyz/dymension-rdk/x/dividends/types" ) -// InitGenesis initializes the incentives module's state from a provided genesis state. func (k Keeper) InitGenesis(ctx sdk.Context, genState types.GenesisState) { - k.SetParams(ctx, genState.Params) - k.SetLockableDurations(ctx, genState.LockableDurations) - for _, gauge := range genState.Gauges { - gauge := gauge - err := k.SetGaugeWithRefKey(ctx, &gauge) - if err != nil { - panic(err) - } - } - k.SetLastGaugeID(ctx, genState.LastGaugeId) } -// ExportGenesis returns the x/incentives module's exported genesis. func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { - return &types.GenesisState{ - Params: k.GetParams(ctx), - LockableDurations: k.GetLockableDurations(ctx), - Gauges: k.GetNotFinishedGauges(ctx), - LastGaugeId: k.GetLastGaugeID(ctx), - } + return nil } diff --git a/x/dividends/keeper/genesis_test.go b/x/dividends/keeper/genesis_test.go deleted file mode 100644 index dc72d3c8..00000000 --- a/x/dividends/keeper/genesis_test.go +++ /dev/null @@ -1,118 +0,0 @@ -package keeper_test - -import ( - "testing" - "time" - - "cosmossdk.io/math" - tmproto "github.com/cometbft/cometbft/proto/tendermint/types" - sdk "github.com/cosmos/cosmos-sdk/types" - bankutil "github.com/cosmos/cosmos-sdk/x/bank/testutil" - "github.com/stretchr/testify/require" - - "github.com/dymensionxyz/dymension/v3/app/apptesting" - "github.com/dymensionxyz/dymension/v3/x/incentives/types" - lockuptypes "github.com/dymensionxyz/dymension/v3/x/lockup/types" -) - -// TestIncentivesExportGenesis tests export genesis command for the incentives module. -func TestIncentivesExportGenesis(t *testing.T) { - // export genesis using default configurations - // ensure resulting genesis params match default params - app := apptesting.Setup(t) - ctx := app.BaseApp.NewContext(false, tmproto.Header{}) - genesis := app.IncentivesKeeper.ExportGenesis(ctx) - require.Equal(t, genesis.Params.DistrEpochIdentifier, "week") - require.Len(t, genesis.Gauges, 0) - - // create an address and fund with coins - addr := sdk.AccAddress([]byte("addr1---------------")) - coins := sdk.Coins{sdk.NewInt64Coin("stake", 10000)} - err := bankutil.FundAccount(app.BankKeeper, ctx, addr, coins) - require.NoError(t, err) - - // mints LP tokens and send to address created earlier - // this ensures the supply exists on chain - distrTo := lockuptypes.QueryCondition{ - LockQueryType: lockuptypes.ByDuration, - Denom: "lptoken", - Duration: time.Second, - } - mintLPtokens := sdk.Coins{sdk.NewInt64Coin(distrTo.Denom, 200)} - err = bankutil.FundAccount(app.BankKeeper, ctx, addr, mintLPtokens) - require.NoError(t, err) - - // create a gauge that distributes coins to earlier created LP token and duration - startTime := time.Now() - gaugeID, err := app.IncentivesKeeper.CreateGauge(ctx, true, addr, coins, distrTo, startTime, 1) - require.NoError(t, err) - - // export genesis using default configurations - // ensure resulting genesis params match default params - genesis = app.IncentivesKeeper.ExportGenesis(ctx) - require.Equal(t, genesis.Params.DistrEpochIdentifier, "week") - require.Len(t, genesis.Gauges, 1) - - // ensure the first gauge listed in the exported genesis explicitly matches expectation - require.Equal(t, genesis.Gauges[0], types.Gauge{ - Id: gaugeID, - IsPerpetual: true, - DistributeTo: &types.Gauge_Asset{Asset: &distrTo}, - Coins: coins, - NumEpochsPaidOver: 1, - FilledEpochs: 0, - DistributedCoins: sdk.Coins(nil), - StartTime: startTime.UTC(), - }) -} - -// TestIncentivesInitGenesis takes a genesis state and tests initializing that genesis for the incentives module. -func TestIncentivesInitGenesis(t *testing.T) { - app := apptesting.Setup(t) - ctx := app.BaseApp.NewContext(false, tmproto.Header{}) - - // checks that the default genesis parameters pass validation - validateGenesis := types.DefaultGenesis().Params.Validate() - require.NoError(t, validateGenesis) - - // create coins, lp tokens with lockup durations, and a gauge for this lockup - coins := sdk.Coins{sdk.NewInt64Coin("stake", 10000)} - startTime := time.Now() - distrTo := lockuptypes.QueryCondition{ - LockQueryType: lockuptypes.ByDuration, - Denom: "lptoken", - Duration: time.Second, - } - gauge := types.Gauge{ - Id: 1, - IsPerpetual: false, - DistributeTo: &types.Gauge_Asset{Asset: &distrTo}, - Coins: coins, - NumEpochsPaidOver: 2, - FilledEpochs: 0, - DistributedCoins: sdk.Coins(nil), - StartTime: startTime.UTC(), - } - - // initialize genesis with specified parameter, the gauge created earlier, and lockable durations - app.IncentivesKeeper.InitGenesis(ctx, types.GenesisState{ - Params: types.Params{ - DistrEpochIdentifier: "week", - CreateGaugeBaseFee: math.ZeroInt(), - AddToGaugeBaseFee: math.ZeroInt(), - AddDenomFee: math.ZeroInt(), - }, - Gauges: []types.Gauge{gauge}, - LockableDurations: []time.Duration{ - time.Second, - time.Hour, - time.Hour * 3, - time.Hour * 7, - }, - }) - - // check that the gauge created earlier was initialized through initGenesis and still exists on chain - gauges := app.IncentivesKeeper.GetGauges(ctx) - require.Len(t, gauges, 1) - require.Equal(t, gauges[0], gauge) -} diff --git a/x/dividends/keeper/grpc_query.go b/x/dividends/keeper/grpc_query.go index 86355896..2f7710c0 100644 --- a/x/dividends/keeper/grpc_query.go +++ b/x/dividends/keeper/grpc_query.go @@ -2,11 +2,8 @@ package keeper import ( "context" - "encoding/json" - "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/query" "github.com/dymensionxyz/dymension-rdk/x/dividends/types" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -14,17 +11,14 @@ import ( var _ types.QueryServer = Querier{} -// Querier defines a wrapper around the incentives module keeper providing gRPC method handlers. type Querier struct { - Keeper + keeper Keeper } -// NewQuerier creates a new Querier struct. func NewQuerier(k Keeper) Querier { - return Querier{Keeper: k} + return Querier{keeper: k} } -// GaugeByID takes a gaugeID and returns its respective gauge. func (q Querier) GaugeByID(goCtx context.Context, req *types.GaugeByIDRequest) (*types.GaugeByIDResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "empty request") @@ -32,37 +26,36 @@ func (q Querier) GaugeByID(goCtx context.Context, req *types.GaugeByIDRequest) ( ctx := sdk.UnwrapSDKContext(goCtx) - gauge, err := q.Keeper.GetGaugeByID(ctx, req.Id) + gauge, err := q.keeper.GetGaugeByID(ctx, req.Id) if err != nil { - return nil, err + return nil, status.Error(codes.Internal, err.Error()) } return &types.GaugeByIDResponse{Gauge: gauge}, nil } -// Gauges returns all upcoming and active gauges. func (q Querier) Gauges(goCtx context.Context, req *types.GaugesRequest) (*types.GaugesResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "empty request") } ctx := sdk.UnwrapSDKContext(goCtx) - pageRes, gauges, err := q.filterByPrefixAndDenom(ctx, types.KeyPrefixGauges, "", req.Pagination) + + gauges, err := q.keeper.GetAllGauges(ctx) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } - return &types.GaugesResponse{Data: gauges, Pagination: pageRes}, nil + return &types.GaugesResponse{Data: gauges, Pagination: nil}, nil } -// Params implements types.QueryServer. func (q Querier) Params(goCtx context.Context, req *types.ParamsRequest) (*types.ParamsResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "empty request") } ctx := sdk.UnwrapSDKContext(goCtx) - params := q.Keeper.GetParams(ctx) + params := q.keeper.MustGetParams(ctx) return &types.ParamsResponse{Params: ¶ms}, nil } diff --git a/x/dividends/keeper/grpc_query_test.go b/x/dividends/keeper/grpc_query_test.go deleted file mode 100644 index 91e5c95f..00000000 --- a/x/dividends/keeper/grpc_query_test.go +++ /dev/null @@ -1,432 +0,0 @@ -package keeper_test - -import ( - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/query" - "github.com/stretchr/testify/suite" - - "github.com/dymensionxyz/dymension/v3/x/incentives/types" - lockuptypes "github.com/dymensionxyz/dymension/v3/x/lockup/types" -) - -var _ = suite.TestingSuite(nil) - -// TestGRPCGaugeByID tests querying gauges via gRPC returns the correct response. -func (suite *KeeperTestSuite) TestGRPCGaugeByID() { - // create a gauge - gaugeID, _, coins, startTime := suite.SetupNewGauge(false, sdk.Coins{sdk.NewInt64Coin("stake", 10)}) - - // ensure that querying for a gauge with an ID that doesn't exist returns an error. - res, err := suite.querier.GaugeByID(sdk.WrapSDKContext(suite.Ctx), &types.GaugeByIDRequest{Id: 1000}) - suite.Require().Error(err) - suite.Require().Equal(res, (*types.GaugeByIDResponse)(nil)) - - // check that querying a gauge with an ID that exists returns the gauge. - res, err = suite.querier.GaugeByID(sdk.WrapSDKContext(suite.Ctx), &types.GaugeByIDRequest{Id: gaugeID}) - suite.Require().NoError(err) - suite.Require().NotEqual(res.Gauge, nil) - expectedGauge := types.Gauge{ - Id: gaugeID, - IsPerpetual: false, - DistributeTo: &types.Gauge_Asset{Asset: &lockuptypes.QueryCondition{ - LockQueryType: lockuptypes.ByDuration, - Denom: "lptoken", - Duration: time.Second, - }}, - Coins: coins, - NumEpochsPaidOver: 2, - FilledEpochs: 0, - DistributedCoins: sdk.Coins{}, - StartTime: startTime, - } - suite.Require().Equal(res.Gauge.String(), expectedGauge.String()) -} - -// TestGRPCGauges tests querying upcoming and active gauges via gRPC returns the correct response. -func (suite *KeeperTestSuite) TestGRPCGauges() { - // ensure initially querying gauges returns no gauges - res, err := suite.querier.Gauges(sdk.WrapSDKContext(suite.Ctx), &types.GaugesRequest{}) - suite.Require().NoError(err) - suite.Require().Len(res.Data, 0) - - // create a gauge - gaugeID, _, coins, startTime := suite.SetupNewGauge(false, sdk.Coins{sdk.NewInt64Coin("stake", 10)}) - - // query gauges again, but this time expect the gauge created earlier in the response - res, err = suite.querier.Gauges(sdk.WrapSDKContext(suite.Ctx), &types.GaugesRequest{}) - suite.Require().NoError(err) - suite.Require().Len(res.Data, 1) - expectedGauge := types.Gauge{ - Id: gaugeID, - IsPerpetual: false, - DistributeTo: &types.Gauge_Asset{Asset: &lockuptypes.QueryCondition{ - LockQueryType: lockuptypes.ByDuration, - Denom: "lptoken", - Duration: time.Second, - }}, - Coins: coins, - NumEpochsPaidOver: 2, - FilledEpochs: 0, - DistributedCoins: sdk.Coins{}, - StartTime: startTime, - } - suite.Require().Equal(res.Data[0].String(), expectedGauge.String()) - - // create 10 more gauges - for i := 0; i < 10; i++ { - suite.SetupNewGauge(false, sdk.Coins{sdk.NewInt64Coin("stake", 3)}) - suite.Ctx = suite.Ctx.WithBlockTime(startTime.Add(time.Second)) - } - - // check that setting page request limit to 10 will only return 10 out of the 11 gauges - filter := query.PageRequest{Limit: 10} - res, err = suite.querier.Gauges(sdk.WrapSDKContext(suite.Ctx), &types.GaugesRequest{Pagination: &filter}) - suite.Require().NoError(err) - suite.Require().Len(res.Data, 10) -} - -// TestGRPCActiveGauges tests querying active gauges via gRPC returns the correct response. -func (suite *KeeperTestSuite) TestGRPCActiveGauges() { - // ensure initially querying active gauges returns no gauges - res, err := suite.querier.ActiveGauges(sdk.WrapSDKContext(suite.Ctx), &types.ActiveGaugesRequest{}) - suite.Require().NoError(err) - suite.Require().Len(res.Data, 0) - - // create a gauge and move it from upcoming to active - gaugeID, gauge, coins, startTime := suite.SetupNewGauge(false, sdk.Coins{sdk.NewInt64Coin("stake", 10)}) - suite.Ctx = suite.Ctx.WithBlockTime(startTime.Add(time.Second)) - err = suite.querier.MoveUpcomingGaugeToActiveGauge(suite.Ctx, *gauge) - suite.Require().NoError(err) - - // query active gauges again, but this time expect the gauge created earlier in the response - res, err = suite.querier.ActiveGauges(sdk.WrapSDKContext(suite.Ctx), &types.ActiveGaugesRequest{}) - suite.Require().NoError(err) - suite.Require().Len(res.Data, 1) - expectedGauge := types.Gauge{ - Id: gaugeID, - IsPerpetual: false, - DistributeTo: &types.Gauge_Asset{Asset: &lockuptypes.QueryCondition{ - LockQueryType: lockuptypes.ByDuration, - Denom: "lptoken", - Duration: time.Second, - }}, - Coins: coins, - NumEpochsPaidOver: 2, - FilledEpochs: 0, - DistributedCoins: sdk.Coins{}, - StartTime: startTime, - } - suite.Require().Equal(res.Data[0].String(), expectedGauge.String()) - - // create 20 more gauges - for i := 0; i < 20; i++ { - _, gauge, _, _ := suite.SetupNewGauge(false, sdk.Coins{sdk.NewInt64Coin("stake", 3)}) - suite.Ctx = suite.Ctx.WithBlockTime(startTime.Add(time.Second)) - - // move the first 9 gauges from upcoming to active (now 10 active gauges, 30 total gauges) - if i < 9 { - err := suite.querier.MoveUpcomingGaugeToActiveGauge(suite.Ctx, *gauge) - suite.Require().NoError(err) - } - } - - // set page request limit to 5, expect only 5 active gauge responses - res, err = suite.querier.ActiveGauges(sdk.WrapSDKContext(suite.Ctx), &types.ActiveGaugesRequest{Pagination: &query.PageRequest{Limit: 5}}) - suite.Require().NoError(err) - suite.Require().Len(res.Data, 5) - - // set page request limit to 15, expect only 10 active gauge responses - res, err = suite.querier.ActiveGauges(sdk.WrapSDKContext(suite.Ctx), &types.ActiveGaugesRequest{Pagination: &query.PageRequest{Limit: 15}}) - suite.Require().NoError(err) - suite.Require().Len(res.Data, 10) -} - -// TestGRPCActiveGaugesPerDenom tests querying active gauges by denom via gRPC returns the correct response. -func (suite *KeeperTestSuite) TestGRPCActiveGaugesPerDenom() { - // ensure initially querying gauges by denom returns no gauges - res, err := suite.querier.ActiveGaugesPerDenom(sdk.WrapSDKContext(suite.Ctx), &types.ActiveGaugesPerDenomRequest{}) - suite.Require().NoError(err) - suite.Require().Len(res.Data, 0) - - // create a gauge - gaugeID, gauge, coins, startTime := suite.SetupNewGauge(false, sdk.Coins{sdk.NewInt64Coin("stake", 10)}) - suite.Ctx = suite.Ctx.WithBlockTime(startTime.Add(time.Second)) - err = suite.App.IncentivesKeeper.MoveUpcomingGaugeToActiveGauge(suite.Ctx, *gauge) - suite.Require().NoError(err) - - // query gauges by denom again, but this time expect the gauge created earlier in the response - res, err = suite.querier.ActiveGaugesPerDenom(sdk.WrapSDKContext(suite.Ctx), &types.ActiveGaugesPerDenomRequest{Denom: "lptoken", Pagination: nil}) - suite.Require().NoError(err) - suite.Require().Len(res.Data, 1) - expectedGauge := types.Gauge{ - Id: gaugeID, - IsPerpetual: false, - DistributeTo: &types.Gauge_Asset{Asset: &lockuptypes.QueryCondition{ - LockQueryType: lockuptypes.ByDuration, - Denom: "lptoken", - Duration: time.Second, - }}, - Coins: coins, - NumEpochsPaidOver: 2, - FilledEpochs: 0, - DistributedCoins: sdk.Coins{}, - StartTime: startTime, - } - suite.Require().Equal(res.Data[0].String(), expectedGauge.String()) - - // setup 20 more gauges with the pool denom - for i := 0; i < 20; i++ { - _, gauge, _, _ := suite.SetupNewGaugeWithDenom(false, sdk.Coins{sdk.NewInt64Coin("stake", 3)}, "pool") - suite.Ctx = suite.Ctx.WithBlockTime(startTime.Add(time.Second)) - - // move the first 10 of 20 gauges to an active status - if i < 10 { - err := suite.querier.MoveUpcomingGaugeToActiveGauge(suite.Ctx, *gauge) - suite.Require().NoError(err) - } - } - - // query active gauges by lptoken denom with a page request of 5 should only return one gauge - res, err = suite.querier.ActiveGaugesPerDenom(sdk.WrapSDKContext(suite.Ctx), &types.ActiveGaugesPerDenomRequest{Denom: "lptoken", Pagination: &query.PageRequest{Limit: 5}}) - suite.Require().NoError(err) - suite.Require().Len(res.Data, 1) - - // query active gauges by pool denom with a page request of 5 should return 5 gauges - res, err = suite.querier.ActiveGaugesPerDenom(sdk.WrapSDKContext(suite.Ctx), &types.ActiveGaugesPerDenomRequest{Denom: "pool", Pagination: &query.PageRequest{Limit: 5}}) - suite.Require().NoError(err) - suite.Require().Len(res.Data, 5) - - // query active gauges by pool denom with a page request of 15 should return 10 gauges - res, err = suite.querier.ActiveGaugesPerDenom(sdk.WrapSDKContext(suite.Ctx), &types.ActiveGaugesPerDenomRequest{Denom: "pool", Pagination: &query.PageRequest{Limit: 15}}) - suite.Require().NoError(err) - suite.Require().Len(res.Data, 10) -} - -// TestGRPCUpcomingGauges tests querying upcoming gauges via gRPC returns the correct response. -func (suite *KeeperTestSuite) TestGRPCUpcomingGauges() { - // ensure initially querying upcoming gauges returns no gauges - res, err := suite.querier.UpcomingGauges(sdk.WrapSDKContext(suite.Ctx), &types.UpcomingGaugesRequest{}) - suite.Require().NoError(err) - suite.Require().Len(res.Data, 0) - - // create a gauge - gaugeID, _, coins, startTime := suite.SetupNewGauge(false, sdk.Coins{sdk.NewInt64Coin("stake", 10)}) - - // query upcoming gauges again, but this time expect the gauge created earlier in the response - res, err = suite.querier.UpcomingGauges(sdk.WrapSDKContext(suite.Ctx), &types.UpcomingGaugesRequest{}) - suite.Require().NoError(err) - suite.Require().Len(res.Data, 1) - expectedGauge := types.Gauge{ - Id: gaugeID, - IsPerpetual: false, - DistributeTo: &types.Gauge_Asset{Asset: &lockuptypes.QueryCondition{ - LockQueryType: lockuptypes.ByDuration, - Denom: "lptoken", - Duration: time.Second, - }}, - Coins: coins, - NumEpochsPaidOver: 2, - FilledEpochs: 0, - DistributedCoins: sdk.Coins{}, - StartTime: startTime, - } - suite.Require().Equal(res.Data[0].String(), expectedGauge.String()) - - // setup 20 more upcoming gauges - for i := 0; i < 20; i++ { - _, gauge, _, _ := suite.SetupNewGauge(false, sdk.Coins{sdk.NewInt64Coin("stake", 3)}) - suite.Ctx = suite.Ctx.WithBlockTime(startTime.Add(time.Second)) - - // move the first 9 created gauges to an active status - // 1 + (20 -9) = 12 upcoming gauges - if i < 9 { - err := suite.querier.MoveUpcomingGaugeToActiveGauge(suite.Ctx, *gauge) - suite.Require().NoError(err) - } - } - - // query upcoming gauges with a page request of 5 should return 5 gauges - res, err = suite.querier.UpcomingGauges(sdk.WrapSDKContext(suite.Ctx), &types.UpcomingGaugesRequest{Pagination: &query.PageRequest{Limit: 5}}) - suite.Require().NoError(err) - suite.Require().Len(res.Data, 5) - - // query upcoming gauges with a page request of 15 should return 12 gauges - res, err = suite.querier.UpcomingGauges(sdk.WrapSDKContext(suite.Ctx), &types.UpcomingGaugesRequest{Pagination: &query.PageRequest{Limit: 15}}) - suite.Require().NoError(err) - suite.Require().Len(res.Data, 12) -} - -// TestGRPCUpcomingGaugesPerDenom tests querying upcoming gauges by denom via gRPC returns the correct response. -func (suite *KeeperTestSuite) TestGRPCUpcomingGaugesPerDenom() { - // ensure initially querying upcoming gauges by denom returns no gauges - upcomingGaugeRequest := types.UpcomingGaugesPerDenomRequest{Denom: "lptoken", Pagination: nil} - res, err := suite.querier.UpcomingGaugesPerDenom(sdk.WrapSDKContext(suite.Ctx), &upcomingGaugeRequest) - suite.Require().NoError(err) - suite.Require().Len(res.UpcomingGauges, 0) - - // create a gauge, and check upcoming gauge is working - gaugeID, gauge, coins, startTime := suite.SetupNewGauge(false, sdk.Coins{sdk.NewInt64Coin("stake", 10)}) - - // query upcoming gauges by denom again, but this time expect the gauge created earlier in the response - res, err = suite.querier.UpcomingGaugesPerDenom(sdk.WrapSDKContext(suite.Ctx), &upcomingGaugeRequest) - suite.Require().NoError(err) - suite.Require().Len(res.UpcomingGauges, 1) - expectedGauge := types.Gauge{ - Id: gaugeID, - IsPerpetual: false, - DistributeTo: &types.Gauge_Asset{Asset: &lockuptypes.QueryCondition{ - LockQueryType: lockuptypes.ByDuration, - Denom: "lptoken", - Duration: time.Second, - }}, - Coins: coins, - NumEpochsPaidOver: 2, - FilledEpochs: 0, - DistributedCoins: sdk.Coins{}, - StartTime: startTime, - } - suite.Require().Equal(res.UpcomingGauges[0].String(), expectedGauge.String()) - - // move gauge from upcoming to active - // ensure the query no longer returns a response - suite.Ctx = suite.Ctx.WithBlockTime(startTime.Add(time.Second)) - err = suite.App.IncentivesKeeper.MoveUpcomingGaugeToActiveGauge(suite.Ctx, *gauge) - suite.Require().NoError(err) - res, err = suite.querier.UpcomingGaugesPerDenom(sdk.WrapSDKContext(suite.Ctx), &upcomingGaugeRequest) - suite.Require().NoError(err) - suite.Require().Len(res.UpcomingGauges, 0) - - // setup 20 more upcoming gauges with pool denom - for i := 0; i < 20; i++ { - _, gauge, _, _ := suite.SetupNewGaugeWithDenom(false, sdk.Coins{sdk.NewInt64Coin("stake", 3)}, "pool") - suite.Ctx = suite.Ctx.WithBlockTime(startTime.Add(time.Second)) - - // move the first 10 created gauges from upcoming to active - // this leaves 10 upcoming gauges - if i < 10 { - err := suite.querier.MoveUpcomingGaugeToActiveGauge(suite.Ctx, *gauge) - suite.Require().NoError(err) - } - } - - // query upcoming gauges by lptoken denom with a page request of 5 should return 0 gauges - res, err = suite.querier.UpcomingGaugesPerDenom(sdk.WrapSDKContext(suite.Ctx), &types.UpcomingGaugesPerDenomRequest{Denom: "lptoken", Pagination: &query.PageRequest{Limit: 5}}) - suite.Require().NoError(err) - suite.Require().Len(res.UpcomingGauges, 0) - - // query upcoming gauges by pool denom with a page request of 5 should return 5 gauges - res, err = suite.querier.UpcomingGaugesPerDenom(sdk.WrapSDKContext(suite.Ctx), &types.UpcomingGaugesPerDenomRequest{Denom: "pool", Pagination: &query.PageRequest{Limit: 5}}) - suite.Require().NoError(err) - suite.Require().Len(res.UpcomingGauges, 5) - - // query upcoming gauges by pool denom with a page request of 15 should return 10 gauges - res, err = suite.querier.UpcomingGaugesPerDenom(sdk.WrapSDKContext(suite.Ctx), &types.UpcomingGaugesPerDenomRequest{Denom: "pool", Pagination: &query.PageRequest{Limit: 15}}) - suite.Require().NoError(err) - suite.Require().Len(res.UpcomingGauges, 10) -} - -// TestGRPCToDistributeCoins tests querying coins that are going to be distributed via gRPC returns the correct response. -func (suite *KeeperTestSuite) TestGRPCToDistributeCoins() { - // ensure initially querying to distribute coins returns no coins - res, err := suite.querier.ModuleToDistributeCoins(sdk.WrapSDKContext(suite.Ctx), &types.ModuleToDistributeCoinsRequest{}) - suite.Require().NoError(err) - suite.Require().Equal(res.Coins, sdk.Coins{}) - - // create two locks with different durations - addr1 := sdk.AccAddress([]byte("addr1---------------")) - addr2 := sdk.AccAddress([]byte("addr2---------------")) - suite.LockTokens(addr1, sdk.Coins{sdk.NewInt64Coin("lptoken", 10)}, time.Second) - suite.LockTokens(addr2, sdk.Coins{sdk.NewInt64Coin("lptoken", 10)}, 2*time.Second) - - // setup a non perpetual gauge - gaugeID, _, coins, startTime := suite.SetupNewGauge(false, sdk.Coins{sdk.NewInt64Coin("stake", 10)}) - gauge, err := suite.querier.GetGaugeByID(suite.Ctx, gaugeID) - suite.Require().NoError(err) - suite.Require().NotNil(gauge) - gauges := []types.Gauge{*gauge} - - // check to distribute coins after gauge creation - // ensure this equals the coins within the previously created non perpetual gauge - res, err = suite.querier.ModuleToDistributeCoins(sdk.WrapSDKContext(suite.Ctx), &types.ModuleToDistributeCoinsRequest{}) - suite.Require().NoError(err) - suite.Require().Equal(res.Coins, coins) - - // distribute coins to stakers - distrCoins, err := suite.querier.DistributeOnEpochEnd(suite.Ctx, gauges) - suite.Require().NoError(err) - suite.Require().Equal(distrCoins, sdk.Coins{sdk.NewInt64Coin("stake", 4)}) - - // check gauge changes after distribution - // ensure the gauge's filled epochs have been increased by 1 - // ensure we have distributed 4 out of the 10 stake tokens - gauge, err = suite.querier.GetGaugeByID(suite.Ctx, gaugeID) - suite.Require().NoError(err) - suite.Require().NotNil(gauge) - suite.Require().Equal(gauge.FilledEpochs, uint64(1)) - suite.Require().Equal(gauge.DistributedCoins, sdk.Coins{sdk.NewInt64Coin("stake", 4)}) - gauges = []types.Gauge{*gauge} - - // move gauge from an upcoming to an active status - suite.Ctx = suite.Ctx.WithBlockTime(startTime) - err = suite.querier.MoveUpcomingGaugeToActiveGauge(suite.Ctx, *gauge) - suite.Require().NoError(err) - - // check that the to distribute coins is equal to the initial gauge coin balance minus what has been distributed already (10-4=6) - res, err = suite.querier.ModuleToDistributeCoins(sdk.WrapSDKContext(suite.Ctx), &types.ModuleToDistributeCoinsRequest{}) - suite.Require().NoError(err) - suite.Require().Equal(res.Coins, coins.Sub(distrCoins...)) - - // distribute second round to stakers - distrCoins, err = suite.querier.DistributeOnEpochEnd(suite.Ctx, gauges) - suite.Require().NoError(err) - suite.Require().Equal(sdk.Coins{sdk.NewInt64Coin("stake", 6)}, distrCoins) - - // now that all coins have been distributed (4 in first found 6 in the second round) - // to distribute coins should be null - res, err = suite.querier.ModuleToDistributeCoins(sdk.WrapSDKContext(suite.Ctx), &types.ModuleToDistributeCoinsRequest{}) - suite.Require().NoError(err) - suite.Require().Equal(res.Coins, sdk.Coins{}) -} - -// TestGRPCDistributedCoins tests querying coins that have been distributed via gRPC returns the correct response. -func (suite *KeeperTestSuite) TestGRPCDistributedCoins() { - // create two locks with different durations - addr1 := sdk.AccAddress([]byte("addr1---------------")) - addr2 := sdk.AccAddress([]byte("addr2---------------")) - suite.LockTokens(addr1, sdk.Coins{sdk.NewInt64Coin("lptoken", 10)}, time.Second) - suite.LockTokens(addr2, sdk.Coins{sdk.NewInt64Coin("lptoken", 10)}, 2*time.Second) - - // setup a non perpetual gauge - gaugeID, _, _, startTime := suite.SetupNewGauge(false, sdk.Coins{sdk.NewInt64Coin("stake", 10)}) - gauge, err := suite.querier.GetGaugeByID(suite.Ctx, gaugeID) - suite.Require().NoError(err) - suite.Require().NotNil(gauge) - gauges := []types.Gauge{*gauge} - - // move gauge from upcoming to active - suite.Ctx = suite.Ctx.WithBlockTime(startTime) - err = suite.querier.MoveUpcomingGaugeToActiveGauge(suite.Ctx, *gauge) - suite.Require().NoError(err) - - // distribute coins to stakers - distrCoins, err := suite.querier.DistributeOnEpochEnd(suite.Ctx, gauges) - suite.Require().NoError(err) - suite.Require().Equal(distrCoins, sdk.Coins{sdk.NewInt64Coin("stake", 4)}) - - // check gauge changes after distribution - // ensure the gauge's filled epochs have been increased by 1 - // ensure we have distributed 4 out of the 10 stake tokens - gauge, err = suite.querier.GetGaugeByID(suite.Ctx, gaugeID) - suite.Require().NoError(err) - suite.Require().NotNil(gauge) - suite.Require().Equal(gauge.FilledEpochs, uint64(1)) - suite.Require().Equal(gauge.DistributedCoins, sdk.Coins{sdk.NewInt64Coin("stake", 4)}) - gauges = []types.Gauge{*gauge} - - // distribute second round to stakers - distrCoins, err = suite.querier.DistributeOnEpochEnd(suite.Ctx, gauges) - suite.Require().NoError(err) - suite.Require().Equal(sdk.Coins{sdk.NewInt64Coin("stake", 6)}, distrCoins) -} diff --git a/x/dividends/keeper/hooks.go b/x/dividends/keeper/hooks.go index ee8d8b13..f110e3d5 100644 --- a/x/dividends/keeper/hooks.go +++ b/x/dividends/keeper/hooks.go @@ -1,37 +1,18 @@ package keeper import ( - epochstypes "github.com/osmosis-labs/osmosis/v15/x/epochs/types" - sdk "github.com/cosmos/cosmos-sdk/types" + epochstypes "github.com/dymensionxyz/dymension-rdk/x/epochs/types" ) -// BeforeEpochStart is the epoch start hook. -func (k Keeper) BeforeEpochStart(ctx sdk.Context, epochIdentifier string, epochNumber int64) error { +func (k Keeper) BeforeEpochStart(sdk.Context, epochstypes.EpochInfo) error { return nil } -// AfterEpochEnd is the epoch end hook. -func (k Keeper) AfterEpochEnd(ctx sdk.Context, epochIdentifier string, epochNumber int64) error { - params := k.GetParams(ctx) - if epochIdentifier == params.DistrEpochIdentifier { - // begin distribution if it's start time - gauges := k.GetUpcomingGauges(ctx) - for _, gauge := range gauges { - if !ctx.BlockTime().Before(gauge.StartTime) { - if err := k.moveUpcomingGaugeToActiveGauge(ctx, gauge); err != nil { - return err - } - } - } - - // if len(gauges) > 10 { - // ctx.EventManager().IncreaseCapacity(2e6) - // } - - // distribute due to epoch event - gauges = k.GetActiveGauges(ctx) - _, err := k.DistributeOnEpochEnd(ctx, gauges) +func (k Keeper) AfterEpochEnd(ctx sdk.Context, epochId epochstypes.EpochInfo) error { + params := k.MustGetParams(ctx) + if epochId.Identifier == params.DistrEpochIdentifier { + err := k.Allocate(ctx) if err != nil { return err } @@ -39,11 +20,8 @@ func (k Keeper) AfterEpochEnd(ctx sdk.Context, epochIdentifier string, epochNumb return nil } -// ___________________________________________________________________________________________________ - -// Hooks is the wrapper struct for the incentives keeper. type Hooks struct { - k Keeper + keeper Keeper } var _ epochstypes.EpochHooks = Hooks{} @@ -53,12 +31,16 @@ func (k Keeper) Hooks() Hooks { return Hooks{k} } -// BeforeEpochStart is the epoch start hook. -func (h Hooks) BeforeEpochStart(ctx sdk.Context, epochIdentifier string, epochNumber int64) error { - return h.k.BeforeEpochStart(ctx, epochIdentifier, epochNumber) +func (h Hooks) BeforeEpochStart(ctx sdk.Context, epochId epochstypes.EpochInfo) { + err := h.keeper.BeforeEpochStart(ctx, epochId) + if err != nil { + h.keeper.Logger(ctx).Error("Error in BeforeEpochStart", "error", err) + } } -// AfterEpochEnd is the epoch end hook. -func (h Hooks) AfterEpochEnd(ctx sdk.Context, epochIdentifier string, epochNumber int64) error { - return h.k.AfterEpochEnd(ctx, epochIdentifier, epochNumber) +func (h Hooks) AfterEpochEnd(ctx sdk.Context, epochId epochstypes.EpochInfo) { + err := h.keeper.AfterEpochEnd(ctx, epochId) + if err != nil { + h.keeper.Logger(ctx).Error("Error in AfterEpochEnd", "error", err) + } } diff --git a/x/dividends/keeper/keeper.go b/x/dividends/keeper/keeper.go index 977ca39f..8b27a24a 100644 --- a/x/dividends/keeper/keeper.go +++ b/x/dividends/keeper/keeper.go @@ -3,26 +3,80 @@ package keeper import ( "fmt" + "cosmossdk.io/collections" + "github.com/cosmos/cosmos-sdk/codec" storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/dymensionxyz/dymension-rdk/utils/collcompat" + "github.com/dymensionxyz/dymension-rdk/x/dividends/types" "github.com/tendermint/tendermint/libs/log" ) -// Keeper provides a way to manage incentives module storage. type Keeper struct { - storeKey storetypes.StoreKey + authority string // authority is the x/gov module account + + schema collections.Schema + params collections.Item[types.Params] + lastGaugeID collections.Sequence // GaugeID + gauges collections.Map[uint64, types.Gauge] // GaugeID -> Gauge + + stakingKeeper types.StakingKeeper + distrKeeper types.DistributionKeeper + bankKeeper types.BankKeeper } -// NewKeeper returns a new instance of the incentive module keeper struct. func NewKeeper( + cdc codec.BinaryCodec, storeKey storetypes.StoreKey, + stakingKeeper types.StakingKeeper, + distrKeeper types.DistributionKeeper, + bankKeeper types.BankKeeper, + authority string, ) *Keeper { - return &Keeper{ - storeKey: storeKey, + sb := collections.NewSchemaBuilder(collcompat.NewKVStoreService(storeKey)) + + k := &Keeper{ + authority: authority, + schema: collections.Schema{}, // set later + params: collections.NewItem( + sb, + types.ParamsKey, + "params", + collcompat.ProtoValue[types.Params](cdc), + ), + lastGaugeID: collections.NewSequence( + sb, + types.LastGaugeKey, + "last_gauge_id", + ), + gauges: collections.NewMap( + sb, + types.GaugesKey, + "gauges", + collections.Uint64Key, + collcompat.ProtoValue[types.Gauge](cdc), + ), + stakingKeeper: stakingKeeper, + distrKeeper: distrKeeper, + bankKeeper: bankKeeper, + } + + // SchemaBuilder CANNOT be used after Build is called, + // so we build it after all collections are initialized + schema, err := sb.Build() + if err != nil { + panic(err) } + k.schema = schema + + return k } // Logger returns a logger instance for the incentives module. func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) } + +func (k Keeper) Schema() collections.Schema { + return k.schema +} diff --git a/x/dividends/keeper/msg_server.go b/x/dividends/keeper/msg_server.go index 38cab403..52b65791 100644 --- a/x/dividends/keeper/msg_server.go +++ b/x/dividends/keeper/msg_server.go @@ -4,48 +4,31 @@ import ( "context" "fmt" - errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/osmosis-labs/osmosis/v15/osmoutils" - - "github.com/dymensionxyz/dymension/v3/x/incentives/types" + "github.com/dymensionxyz/dymension-rdk/x/dividends/types" ) -// msgServer provides a way to reference keeper pointer in the message server interface. type msgServer struct { - keeper *Keeper + keeper Keeper } -// NewMsgServerImpl returns an instance of MsgServer for the provided keeper. -func NewMsgServerImpl(keeper *Keeper) types.MsgServer { - return &msgServer{ - keeper: keeper, - } +func NewMsgServer(keeper Keeper) types.MsgServer { + return &msgServer{keeper: keeper} } var _ types.MsgServer = msgServer{} -// CreateGauge creates a gauge and sends coins to the gauge. -// Creation fee is charged from the address and sent to the txfees module to be burned. -// Emits create gauge event and returns the create gauge response. -func (server msgServer) CreateGauge(goCtx context.Context, msg *types.MsgCreateGauge) (*types.MsgCreateGaugeResponse, error) { +// CreateGauge creates a gauge. +func (s msgServer) CreateGauge(goCtx context.Context, msg *types.MsgCreateGauge) (*types.MsgCreateGaugeResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - owner, err := sdk.AccAddressFromBech32(msg.Owner) - if err != nil { - return nil, err - } - // Charge fess based on the number of coins to add - // Fee = CreateGaugeBaseFee + AddDenomFee * NumDenoms - params := server.keeper.GetParams(ctx) - fee := params.CreateGaugeBaseFee.Add(params.AddDenomFee.MulRaw(int64(len(msg.Coins)))) - if err = server.keeper.ChargeGaugesFee(ctx, owner, fee, msg.Coins); err != nil { - return nil, fmt.Errorf("charge gauge fee: %w", err) - } - gaugeID, err := server.keeper.CreateGauge(ctx, msg.IsPerpetual, owner, msg.Coins, msg.DistributeTo, msg.StartTime, msg.NumEpochsPaidOver) + // TODO: validate query and vesting conditions + + gauge := types.NewGauge(msg.Id, msg.Address, msg.QueryCondition, msg.VestingCondition) + + err := s.keeper.gauges.Set(ctx, gauge.Id, gauge) if err != nil { - return nil, fmt.Errorf("create gauge: %w", err) + return nil, fmt.Errorf("set gauge: %w", err) } ctx.EventManager().EmitEvents(sdk.Events{ @@ -57,65 +40,3 @@ func (server msgServer) CreateGauge(goCtx context.Context, msg *types.MsgCreateG return &types.MsgCreateGaugeResponse{}, nil } - -// AddToGauge adds coins to gauge. -// Emits add to gauge event and returns the add to gauge response. -func (server msgServer) AddToGauge(goCtx context.Context, msg *types.MsgAddToGauge) (*types.MsgAddToGaugeResponse, error) { - ctx := sdk.UnwrapSDKContext(goCtx) - owner, err := sdk.AccAddressFromBech32(msg.Owner) - if err != nil { - return nil, err - } - - gauge, err := server.keeper.GetGaugeByID(ctx, msg.GaugeId) - if err != nil { - return nil, err - } - - // Charge fess based on the number of coins to add - // Fee = AddToGaugeBaseFee + AddDenomFee * (NumAddedDenoms + NumGaugeDenoms) - params := server.keeper.GetParams(ctx) - fee := params.AddToGaugeBaseFee.Add(params.AddDenomFee.MulRaw(int64(len(msg.Rewards) + len(gauge.Coins)))) - if err = server.keeper.ChargeGaugesFee(ctx, owner, fee, msg.Rewards); err != nil { - return nil, fmt.Errorf("charge gauge fee: %w", err) - } - - err = server.keeper.AddToGaugeRewards(ctx, owner, msg.Rewards, gauge) - if err != nil { - return nil, fmt.Errorf("add to gauge rewards: %w", err) - } - - ctx.EventManager().EmitEvents(sdk.Events{ - sdk.NewEvent( - types.TypeEvtAddToGauge, - sdk.NewAttribute(types.AttributeGaugeID, osmoutils.Uint64ToString(msg.GaugeId)), - ), - }) - - return &types.MsgAddToGaugeResponse{}, nil -} - -// ChargeGaugesFee charges fee in the base denom on the address if the address has -// balance that is less than fee + amount of the coin from gaugeCoins that is of base denom. -// gaugeCoins might not have a coin of tx base denom. In that case, fee is only compared to balance. -// The fee is sent to the txfees module, to be burned. -func (k Keeper) ChargeGaugesFee(ctx sdk.Context, payer sdk.AccAddress, fee sdk.Int, gaugeCoins sdk.Coins) (err error) { - var feeDenom string - if k.tk == nil { - feeDenom, err = sdk.GetBaseDenom() - } else { - feeDenom, err = k.tk.GetBaseDenom(ctx) - } - if err != nil { - return err - } - - totalCost := gaugeCoins.AmountOf(feeDenom).Add(fee) - accountBalance := k.bk.GetBalance(ctx, payer, feeDenom).Amount - - if accountBalance.LT(totalCost) { - return errorsmod.Wrapf(sdkerrors.ErrInsufficientFunds, "account's balance is less than the total cost of the message. Balance: %s %s, Total Cost: %s", feeDenom, accountBalance, totalCost) - } - - return k.tk.ChargeFeesFromPayer(ctx, payer, sdk.NewCoin(feeDenom, fee), nil) -} diff --git a/x/dividends/keeper/params.go b/x/dividends/keeper/params.go deleted file mode 100644 index 2a19f8a4..00000000 --- a/x/dividends/keeper/params.go +++ /dev/null @@ -1,23 +0,0 @@ -package keeper - -import ( - "github.com/dymensionxyz/dymension/v3/x/incentives/types" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// GetParams returns all of the parameters in the incentive module. -func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) { - k.paramSpace.GetParamSet(ctx, ¶ms) - return params -} - -// SetParams sets all of the parameters in the incentive module. -func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { - k.paramSpace.SetParamSet(ctx, ¶ms) -} - -func (k Keeper) DistrEpochIdentifier(ctx sdk.Context) (res string) { - k.paramSpace.Get(ctx, types.KeyDistrEpochIdentifier, &res) - return -} diff --git a/x/dividends/keeper/storage.go b/x/dividends/keeper/storage.go new file mode 100644 index 00000000..7fc8b9ba --- /dev/null +++ b/x/dividends/keeper/storage.go @@ -0,0 +1,35 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/dymensionxyz/dymension-rdk/x/dividends/types" +) + +func (k Keeper) GetAllGauges(ctx sdk.Context) ([]types.Gauge, error) { + i, err := k.gauges.Iterate(ctx, nil) + if err != nil { + return nil, err + } + defer i.Close() + return i.Values() +} + +func (k Keeper) IterateGauges(ctx sdk.Context, fn func(gaugeId uint64, gauge types.Gauge) (stop bool, err error)) error { + return k.gauges.Walk(ctx, nil, fn) +} + +func (k Keeper) SetGauge(ctx sdk.Context, gauge types.Gauge) error { + return k.gauges.Set(ctx, gauge.Id, gauge) +} + +func (k Keeper) GetGauge(ctx sdk.Context, gaugeId uint64) (types.Gauge, error) { + return k.gauges.Get(ctx, gaugeId) +} + +func (k Keeper) MustGetParams(ctx sdk.Context) types.Params { + p, err := k.params.Get(ctx) + if err != nil { + panic(err) + } + return p +} diff --git a/x/dividends/types/expected_keepers.go b/x/dividends/types/expected_keepers.go new file mode 100644 index 00000000..aaca26f7 --- /dev/null +++ b/x/dividends/types/expected_keepers.go @@ -0,0 +1,24 @@ +package types + +import ( + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +type StakingKeeper interface { + GetLastTotalPower(ctx sdk.Context) math.Int + + // IterateBondedValidatorsByPower iterate through bonded validators by operator address, execute func for each validator + IterateBondedValidatorsByPower(sdk.Context, func(index int64, validator stakingtypes.ValidatorI) (stop bool)) +} + +type BankKeeper interface { + GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins +} + +type DistributionKeeper interface { + AllocateTokensToValidator(ctx sdk.Context, val stakingtypes.ValidatorI, tokens sdk.DecCoins) + FundCommunityPool(ctx sdk.Context, amount sdk.Coins, sender sdk.AccAddress) error +} diff --git a/x/dividends/types/gauge.go b/x/dividends/types/gauge.go new file mode 100644 index 00000000..8d33cb46 --- /dev/null +++ b/x/dividends/types/gauge.go @@ -0,0 +1,15 @@ +package types + +func NewGauge( + id uint64, + address string, + queryCondition *QueryCondition, + vestingCondition *VestingCondition, +) Gauge { + return Gauge{ + Id: id, + Address: address, + QueryCondition: queryCondition, + VestingCondition: vestingCondition, + } +} diff --git a/x/dividends/types/gauge.pb.go b/x/dividends/types/gauge.pb.go index ad7f2b24..70f7cdce 100644 --- a/x/dividends/types/gauge.pb.go +++ b/x/dividends/types/gauge.pb.go @@ -5,8 +5,7 @@ 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/cosmos/cosmos-sdk/types" _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" _ "github.com/gogo/protobuf/types" @@ -26,6 +25,34 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package +type VestingFrequency int32 + +const ( + VestingFrequency_VESTING_FREQUENCY_UNSPECIFIED VestingFrequency = 0 + VestingFrequency_VESTING_FREQUENCY_BLOCK VestingFrequency = 1 + VestingFrequency_VESTING_FREQUENCY_EPOCH VestingFrequency = 2 +) + +var VestingFrequency_name = map[int32]string{ + 0: "VESTING_FREQUENCY_UNSPECIFIED", + 1: "VESTING_FREQUENCY_BLOCK", + 2: "VESTING_FREQUENCY_EPOCH", +} + +var VestingFrequency_value = map[string]int32{ + "VESTING_FREQUENCY_UNSPECIFIED": 0, + "VESTING_FREQUENCY_BLOCK": 1, + "VESTING_FREQUENCY_EPOCH": 2, +} + +func (x VestingFrequency) String() string { + return proto.EnumName(VestingFrequency_name, int32(x)) +} + +func (VestingFrequency) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_904d8195b7413b1f, []int{0} +} + // Gauge is an object that stores and distributes yields to recipients who // satisfy certain conditions. type Gauge struct { @@ -35,8 +62,10 @@ type Gauge struct { Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` // query_condition is *where* the gauge rewards are distributed to QueryCondition *QueryCondition `protobuf:"bytes,3,opt,name=query_condition,json=queryCondition,proto3" json:"query_condition,omitempty"` - // vesting_condition is *when* the gauge rewards are distributed to + // vesting_condition is *how long* the gauge rewards are distributed to VestingCondition *VestingCondition `protobuf:"bytes,4,opt,name=vesting_condition,json=vestingCondition,proto3" json:"vesting_condition,omitempty"` + // vesting_condition is *how frequent* the gauge rewards are distributed to + VestingFrequency VestingFrequency `protobuf:"varint,5,opt,name=vesting_frequency,json=vestingFrequency,proto3,enum=rollapp.dividends.VestingFrequency" json:"vesting_frequency,omitempty"` } func (m *Gauge) Reset() { *m = Gauge{} } @@ -100,10 +129,16 @@ func (m *Gauge) GetVestingCondition() *VestingCondition { return nil } +func (m *Gauge) GetVestingFrequency() VestingFrequency { + if m != nil { + return m.VestingFrequency + } + return VestingFrequency_VESTING_FREQUENCY_UNSPECIFIED +} + type QueryCondition struct { // Types that are valid to be assigned to Condition: // *QueryCondition_Stakers - // *QueryCondition_Funds Condition isQueryCondition_Condition `protobuf_oneof:"condition"` } @@ -149,12 +184,8 @@ type isQueryCondition_Condition interface { type QueryCondition_Stakers struct { Stakers *QueryConditionStakers `protobuf:"bytes,1,opt,name=stakers,proto3,oneof" json:"stakers,omitempty"` } -type QueryCondition_Funds struct { - Funds *QueryConditionFunds `protobuf:"bytes,2,opt,name=funds,proto3,oneof" json:"funds,omitempty"` -} func (*QueryCondition_Stakers) isQueryCondition_Condition() {} -func (*QueryCondition_Funds) isQueryCondition_Condition() {} func (m *QueryCondition) GetCondition() isQueryCondition_Condition { if m != nil { @@ -170,24 +201,16 @@ func (m *QueryCondition) GetStakers() *QueryConditionStakers { return nil } -func (m *QueryCondition) GetFunds() *QueryConditionFunds { - if x, ok := m.GetCondition().(*QueryCondition_Funds); ok { - return x.Funds - } - return nil -} - // XXX_OneofWrappers is for the internal use of the proto package. func (*QueryCondition) XXX_OneofWrappers() []interface{} { return []interface{}{ (*QueryCondition_Stakers)(nil), - (*QueryCondition_Funds)(nil), } } type VestingCondition struct { // Types that are valid to be assigned to Condition: - // *VestingCondition_Immediate + // *VestingCondition_Perpetual // *VestingCondition_Epoch Condition isVestingCondition_Condition `protobuf_oneof:"condition"` } @@ -231,14 +254,14 @@ type isVestingCondition_Condition interface { Size() int } -type VestingCondition_Immediate struct { - Immediate *VestingConditionImmediate `protobuf:"bytes,1,opt,name=immediate,proto3,oneof" json:"immediate,omitempty"` +type VestingCondition_Perpetual struct { + Perpetual *VestingConditionPerpetual `protobuf:"bytes,1,opt,name=perpetual,proto3,oneof" json:"perpetual,omitempty"` } type VestingCondition_Epoch struct { - Epoch *VestingConditionEpoch `protobuf:"bytes,2,opt,name=epoch,proto3,oneof" json:"epoch,omitempty"` + Epoch *VestingConditionLimited `protobuf:"bytes,2,opt,name=epoch,proto3,oneof" json:"epoch,omitempty"` } -func (*VestingCondition_Immediate) isVestingCondition_Condition() {} +func (*VestingCondition_Perpetual) isVestingCondition_Condition() {} func (*VestingCondition_Epoch) isVestingCondition_Condition() {} func (m *VestingCondition) GetCondition() isVestingCondition_Condition { @@ -248,14 +271,14 @@ func (m *VestingCondition) GetCondition() isVestingCondition_Condition { return nil } -func (m *VestingCondition) GetImmediate() *VestingConditionImmediate { - if x, ok := m.GetCondition().(*VestingCondition_Immediate); ok { - return x.Immediate +func (m *VestingCondition) GetPerpetual() *VestingConditionPerpetual { + if x, ok := m.GetCondition().(*VestingCondition_Perpetual); ok { + return x.Perpetual } return nil } -func (m *VestingCondition) GetEpoch() *VestingConditionEpoch { +func (m *VestingCondition) GetEpoch() *VestingConditionLimited { if x, ok := m.GetCondition().(*VestingCondition_Epoch); ok { return x.Epoch } @@ -265,7 +288,7 @@ func (m *VestingCondition) GetEpoch() *VestingConditionEpoch { // XXX_OneofWrappers is for the internal use of the proto package. func (*VestingCondition) XXX_OneofWrappers() []interface{} { return []interface{}{ - (*VestingCondition_Immediate)(nil), + (*VestingCondition_Perpetual)(nil), (*VestingCondition_Epoch)(nil), } } @@ -307,72 +330,29 @@ func (m *QueryConditionStakers) XXX_DiscardUnknown() { var xxx_messageInfo_QueryConditionStakers proto.InternalMessageInfo -// QueryConditionFunds queries the users with funds above a certain threshold -type QueryConditionFunds struct { - Threshold github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,8,rep,name=threshold,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"threshold"` -} - -func (m *QueryConditionFunds) Reset() { *m = QueryConditionFunds{} } -func (m *QueryConditionFunds) String() string { return proto.CompactTextString(m) } -func (*QueryConditionFunds) ProtoMessage() {} -func (*QueryConditionFunds) Descriptor() ([]byte, []int) { - return fileDescriptor_904d8195b7413b1f, []int{4} -} -func (m *QueryConditionFunds) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryConditionFunds) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryConditionFunds.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 *QueryConditionFunds) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryConditionFunds.Merge(m, src) -} -func (m *QueryConditionFunds) XXX_Size() int { - return m.Size() -} -func (m *QueryConditionFunds) XXX_DiscardUnknown() { - xxx_messageInfo_QueryConditionFunds.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryConditionFunds proto.InternalMessageInfo - -func (m *QueryConditionFunds) GetThreshold() github_com_cosmos_cosmos_sdk_types.Coins { - if m != nil { - return m.Threshold - } - return nil -} - -// VestingConditionImmediate is a vesting condition that distributes rewards -// immediately. This gauge is perpetual by default. -// Non-perpetual gauges distribute their tokens equally per epoch while the +// VestingConditionPerpetual is a vesting condition that distributes rewards +// infinitely. Perpetual gauges distribute all their tokens at a single time +// and only distribute their tokens again once the gauge is refilled. +// +// Non-perpetual gauges distribute their tokens equally per period while the // gauge is in the active period. Perpetual gauges distribute all their tokens // at a single time and only distribute their tokens again once the gauge is -// refilled, Intended for use with incentives that get refilled daily. -type VestingConditionImmediate struct { +// refilled. +type VestingConditionPerpetual struct { } -func (m *VestingConditionImmediate) Reset() { *m = VestingConditionImmediate{} } -func (m *VestingConditionImmediate) String() string { return proto.CompactTextString(m) } -func (*VestingConditionImmediate) ProtoMessage() {} -func (*VestingConditionImmediate) Descriptor() ([]byte, []int) { - return fileDescriptor_904d8195b7413b1f, []int{5} +func (m *VestingConditionPerpetual) Reset() { *m = VestingConditionPerpetual{} } +func (m *VestingConditionPerpetual) String() string { return proto.CompactTextString(m) } +func (*VestingConditionPerpetual) ProtoMessage() {} +func (*VestingConditionPerpetual) Descriptor() ([]byte, []int) { + return fileDescriptor_904d8195b7413b1f, []int{4} } -func (m *VestingConditionImmediate) XXX_Unmarshal(b []byte) error { +func (m *VestingConditionPerpetual) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *VestingConditionImmediate) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *VestingConditionPerpetual) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_VestingConditionImmediate.Marshal(b, m, deterministic) + return xxx_messageInfo_VestingConditionPerpetual.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -382,41 +362,42 @@ func (m *VestingConditionImmediate) XXX_Marshal(b []byte, deterministic bool) ([ return b[:n], nil } } -func (m *VestingConditionImmediate) XXX_Merge(src proto.Message) { - xxx_messageInfo_VestingConditionImmediate.Merge(m, src) +func (m *VestingConditionPerpetual) XXX_Merge(src proto.Message) { + xxx_messageInfo_VestingConditionPerpetual.Merge(m, src) } -func (m *VestingConditionImmediate) XXX_Size() int { +func (m *VestingConditionPerpetual) XXX_Size() int { return m.Size() } -func (m *VestingConditionImmediate) XXX_DiscardUnknown() { - xxx_messageInfo_VestingConditionImmediate.DiscardUnknown(m) +func (m *VestingConditionPerpetual) XXX_DiscardUnknown() { + xxx_messageInfo_VestingConditionPerpetual.DiscardUnknown(m) } -var xxx_messageInfo_VestingConditionImmediate proto.InternalMessageInfo +var xxx_messageInfo_VestingConditionPerpetual proto.InternalMessageInfo -// VestingConditionEpoch is a vesting condition that distributes rewards over -// epochs -type VestingConditionEpoch struct { - // num_epochs_paid_over is the number of total epochs distribution will be +// VestingConditionLimited is a vesting condition that distributes rewards over +// the specified time. Non-perpetual gauges distribute their tokens equally per +// period while the gauge is in the active period. +type VestingConditionLimited struct { + // num_units is the number of total epochs/blocks distribution will be // completed over - NumEpochsPaidOver uint64 `protobuf:"varint,1,opt,name=num_epochs_paid_over,json=numEpochsPaidOver,proto3" json:"num_epochs_paid_over,omitempty"` - // filled_epochs is the number of epochs distribution has been completed on - // already - FilledEpochs uint64 `protobuf:"varint,2,opt,name=filled_epochs,json=filledEpochs,proto3" json:"filled_epochs,omitempty"` + NumUnits uint64 `protobuf:"varint,1,opt,name=num_units,json=numUnits,proto3" json:"num_units,omitempty"` + // filled_epochs is the number of epochs/blocks distribution has been + // completed on already + FilledUnits uint64 `protobuf:"varint,2,opt,name=filled_units,json=filledUnits,proto3" json:"filled_units,omitempty"` } -func (m *VestingConditionEpoch) Reset() { *m = VestingConditionEpoch{} } -func (m *VestingConditionEpoch) String() string { return proto.CompactTextString(m) } -func (*VestingConditionEpoch) ProtoMessage() {} -func (*VestingConditionEpoch) Descriptor() ([]byte, []int) { - return fileDescriptor_904d8195b7413b1f, []int{6} +func (m *VestingConditionLimited) Reset() { *m = VestingConditionLimited{} } +func (m *VestingConditionLimited) String() string { return proto.CompactTextString(m) } +func (*VestingConditionLimited) ProtoMessage() {} +func (*VestingConditionLimited) Descriptor() ([]byte, []int) { + return fileDescriptor_904d8195b7413b1f, []int{5} } -func (m *VestingConditionEpoch) XXX_Unmarshal(b []byte) error { +func (m *VestingConditionLimited) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *VestingConditionEpoch) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *VestingConditionLimited) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_VestingConditionEpoch.Marshal(b, m, deterministic) + return xxx_messageInfo_VestingConditionLimited.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -426,82 +407,81 @@ func (m *VestingConditionEpoch) XXX_Marshal(b []byte, deterministic bool) ([]byt return b[:n], nil } } -func (m *VestingConditionEpoch) XXX_Merge(src proto.Message) { - xxx_messageInfo_VestingConditionEpoch.Merge(m, src) +func (m *VestingConditionLimited) XXX_Merge(src proto.Message) { + xxx_messageInfo_VestingConditionLimited.Merge(m, src) } -func (m *VestingConditionEpoch) XXX_Size() int { +func (m *VestingConditionLimited) XXX_Size() int { return m.Size() } -func (m *VestingConditionEpoch) XXX_DiscardUnknown() { - xxx_messageInfo_VestingConditionEpoch.DiscardUnknown(m) +func (m *VestingConditionLimited) XXX_DiscardUnknown() { + xxx_messageInfo_VestingConditionLimited.DiscardUnknown(m) } -var xxx_messageInfo_VestingConditionEpoch proto.InternalMessageInfo +var xxx_messageInfo_VestingConditionLimited proto.InternalMessageInfo -func (m *VestingConditionEpoch) GetNumEpochsPaidOver() uint64 { +func (m *VestingConditionLimited) GetNumUnits() uint64 { if m != nil { - return m.NumEpochsPaidOver + return m.NumUnits } return 0 } -func (m *VestingConditionEpoch) GetFilledEpochs() uint64 { +func (m *VestingConditionLimited) GetFilledUnits() uint64 { if m != nil { - return m.FilledEpochs + return m.FilledUnits } return 0 } func init() { + proto.RegisterEnum("rollapp.dividends.VestingFrequency", VestingFrequency_name, VestingFrequency_value) proto.RegisterType((*Gauge)(nil), "rollapp.dividends.Gauge") proto.RegisterType((*QueryCondition)(nil), "rollapp.dividends.QueryCondition") proto.RegisterType((*VestingCondition)(nil), "rollapp.dividends.VestingCondition") proto.RegisterType((*QueryConditionStakers)(nil), "rollapp.dividends.QueryConditionStakers") - proto.RegisterType((*QueryConditionFunds)(nil), "rollapp.dividends.QueryConditionFunds") - proto.RegisterType((*VestingConditionImmediate)(nil), "rollapp.dividends.VestingConditionImmediate") - proto.RegisterType((*VestingConditionEpoch)(nil), "rollapp.dividends.VestingConditionEpoch") + proto.RegisterType((*VestingConditionPerpetual)(nil), "rollapp.dividends.VestingConditionPerpetual") + proto.RegisterType((*VestingConditionLimited)(nil), "rollapp.dividends.VestingConditionLimited") } func init() { proto.RegisterFile("dividends/gauge.proto", fileDescriptor_904d8195b7413b1f) } var fileDescriptor_904d8195b7413b1f = []byte{ - // 568 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0xcd, 0x6e, 0xd3, 0x4c, - 0x14, 0xb5, 0xd3, 0xe4, 0xeb, 0x97, 0x09, 0x84, 0x66, 0x68, 0x44, 0x5a, 0x24, 0x27, 0xb8, 0x12, - 0xf2, 0x82, 0x7a, 0x68, 0x58, 0xb0, 0x43, 0x28, 0xe5, 0x27, 0x20, 0x24, 0x5a, 0x23, 0xb1, 0x60, - 0x13, 0x4d, 0x32, 0x13, 0x67, 0x14, 0xdb, 0xe3, 0x7a, 0xc6, 0x56, 0xc3, 0x8a, 0x47, 0xe0, 0x1d, - 0xd8, 0xb1, 0xe1, 0x35, 0xba, 0xa3, 0x4b, 0x56, 0x80, 0x92, 0x17, 0x41, 0x1e, 0x3b, 0x4d, 0x13, - 0x82, 0xda, 0x95, 0x7d, 0xe7, 0x9e, 0x73, 0x7c, 0xce, 0xd5, 0x1d, 0x83, 0x3a, 0x61, 0x09, 0x23, - 0x34, 0x20, 0x02, 0xb9, 0x38, 0x76, 0xa9, 0x1d, 0x46, 0x5c, 0x72, 0x58, 0x8b, 0xb8, 0xe7, 0xe1, - 0x30, 0xb4, 0x2f, 0xda, 0xbb, 0xdb, 0x2e, 0x77, 0xb9, 0xea, 0xa2, 0xf4, 0x2d, 0x03, 0xee, 0x1a, - 0x2e, 0xe7, 0xae, 0x47, 0x91, 0xaa, 0xfa, 0xf1, 0x10, 0x91, 0x38, 0xc2, 0x92, 0xf1, 0x20, 0xef, - 0x37, 0x57, 0xfb, 0x92, 0xf9, 0x54, 0x48, 0xec, 0x87, 0x73, 0x81, 0x01, 0x17, 0x3e, 0x17, 0xa8, - 0x8f, 0x05, 0x45, 0xc9, 0x41, 0x9f, 0x4a, 0x7c, 0x80, 0x06, 0x9c, 0xe5, 0x02, 0xe6, 0x77, 0x1d, - 0x94, 0x5e, 0xa6, 0xce, 0x60, 0x15, 0x14, 0x18, 0x69, 0xe8, 0x2d, 0xdd, 0x2a, 0x3a, 0x05, 0x46, - 0x60, 0x03, 0x6c, 0x62, 0x42, 0x22, 0x2a, 0x44, 0xa3, 0xd0, 0xd2, 0xad, 0xb2, 0x33, 0x2f, 0xe1, - 0x6b, 0x70, 0xeb, 0x24, 0xa6, 0xd1, 0xa4, 0x37, 0xe0, 0x01, 0x61, 0xa9, 0x9b, 0xc6, 0x46, 0x4b, - 0xb7, 0x2a, 0xed, 0x7b, 0xf6, 0x5f, 0xb9, 0xec, 0xe3, 0x14, 0x79, 0x38, 0x07, 0x3a, 0xd5, 0x93, - 0xa5, 0x1a, 0x1e, 0x81, 0x5a, 0x42, 0x85, 0x64, 0x81, 0x7b, 0x49, 0xad, 0xa8, 0xd4, 0xf6, 0xd6, - 0xa8, 0xbd, 0xcf, 0xb0, 0x0b, 0xbd, 0xad, 0x64, 0xe5, 0xc4, 0xfc, 0xa2, 0x83, 0xea, 0xf2, 0x47, - 0xe1, 0x33, 0xb0, 0x29, 0x24, 0x1e, 0xd3, 0x48, 0xa8, 0x7c, 0x95, 0xb6, 0x75, 0xa5, 0xd1, 0x77, - 0x19, 0xbe, 0xab, 0x39, 0x73, 0x2a, 0x7c, 0x02, 0x4a, 0xc3, 0x38, 0x20, 0xd9, 0x38, 0x2a, 0xed, - 0xfb, 0x57, 0x6a, 0xbc, 0x48, 0xd1, 0x5d, 0xcd, 0xc9, 0x68, 0x9d, 0x0a, 0x28, 0x5f, 0x44, 0x34, - 0xbf, 0xe9, 0x60, 0x6b, 0x35, 0x0c, 0x7c, 0x03, 0xca, 0xcc, 0xf7, 0x29, 0x61, 0x58, 0xd2, 0xdc, - 0xe9, 0x83, 0x6b, 0x0c, 0xe1, 0xd5, 0x9c, 0xd3, 0xd5, 0x9c, 0x85, 0x00, 0x7c, 0x0a, 0x4a, 0x34, - 0xe4, 0x83, 0x51, 0xee, 0xd7, 0xba, 0x86, 0xd2, 0xf3, 0x14, 0x9f, 0x3a, 0x56, 0xc4, 0x65, 0xc7, - 0x77, 0x40, 0x7d, 0xed, 0x88, 0xcc, 0x4f, 0x3a, 0xb8, 0xbd, 0x26, 0x38, 0x64, 0xa0, 0x2c, 0x47, - 0x11, 0x15, 0x23, 0xee, 0x91, 0xc6, 0xff, 0xad, 0x0d, 0xab, 0xd2, 0xde, 0xb1, 0xb3, 0x75, 0xb4, - 0xd3, 0x75, 0xb4, 0xf3, 0x75, 0xb4, 0x0f, 0x39, 0x0b, 0x3a, 0x0f, 0xcf, 0x7e, 0x36, 0xb5, 0xaf, - 0xbf, 0x9a, 0x96, 0xcb, 0xe4, 0x28, 0xee, 0xdb, 0x03, 0xee, 0xa3, 0x7c, 0x77, 0xb3, 0xc7, 0xbe, - 0x20, 0x63, 0x24, 0x27, 0x21, 0x15, 0x8a, 0x20, 0x9c, 0x85, 0xba, 0x79, 0x17, 0xec, 0xfc, 0x73, - 0x28, 0xa6, 0x0f, 0xea, 0x6b, 0x73, 0x42, 0x04, 0xb6, 0x83, 0xd8, 0xef, 0xa9, 0xac, 0xa2, 0x17, - 0x62, 0x46, 0x7a, 0x3c, 0xa1, 0x51, 0x7e, 0x07, 0x6a, 0x41, 0xec, 0x2b, 0x9c, 0x38, 0xc2, 0x8c, - 0xbc, 0x4d, 0x68, 0x04, 0xf7, 0xc0, 0xcd, 0x21, 0xf3, 0x3c, 0x4a, 0x72, 0x8e, 0x9a, 0x6c, 0xd1, - 0xb9, 0x91, 0x1d, 0x66, 0xe0, 0xce, 0xf1, 0xd9, 0xd4, 0xd0, 0xcf, 0xa7, 0x86, 0xfe, 0x7b, 0x6a, - 0xe8, 0x9f, 0x67, 0x86, 0x76, 0x3e, 0x33, 0xb4, 0x1f, 0x33, 0x43, 0xfb, 0xf0, 0xf8, 0x52, 0x34, - 0x32, 0xf1, 0x69, 0x20, 0x18, 0x0f, 0x4e, 0x27, 0x1f, 0x17, 0xc5, 0x7e, 0x44, 0xc6, 0xe8, 0x14, - 0x2d, 0x7e, 0x1a, 0x2a, 0x6f, 0xff, 0x3f, 0x75, 0x57, 0x1f, 0xfd, 0x09, 0x00, 0x00, 0xff, 0xff, - 0xbe, 0x1b, 0x4d, 0xfc, 0x4e, 0x04, 0x00, 0x00, + // 552 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x94, 0xc1, 0x72, 0xd2, 0x40, + 0x18, 0xc7, 0x93, 0x58, 0xac, 0x2c, 0x0e, 0xd2, 0x1d, 0x3b, 0x60, 0x19, 0x23, 0xe0, 0x85, 0xe9, + 0x28, 0x99, 0xe2, 0xc1, 0x3b, 0x34, 0x14, 0x94, 0xa1, 0x10, 0xa4, 0x33, 0xf5, 0xc2, 0x84, 0xec, + 0x92, 0xee, 0x34, 0xc9, 0x86, 0xec, 0x86, 0x29, 0x3e, 0x85, 0xaf, 0xe0, 0x23, 0xf8, 0x16, 0x1e, + 0x7b, 0xf4, 0xe8, 0xc0, 0x8b, 0x38, 0x84, 0x24, 0x14, 0x4a, 0xb5, 0xb7, 0x7c, 0xfb, 0xff, 0xef, + 0x6f, 0xbf, 0xff, 0xb7, 0x49, 0xc0, 0x21, 0x22, 0x53, 0x82, 0xb0, 0x83, 0x98, 0x62, 0xea, 0xbe, + 0x89, 0x2b, 0xae, 0x47, 0x39, 0x85, 0x07, 0x1e, 0xb5, 0x2c, 0xdd, 0x75, 0x2b, 0xb1, 0x7c, 0xf4, + 0xd2, 0xa4, 0x26, 0x0d, 0x54, 0x65, 0xf9, 0xb4, 0x32, 0x1e, 0xc9, 0x26, 0xa5, 0xa6, 0x85, 0x95, + 0xa0, 0x1a, 0xf9, 0x63, 0x05, 0xf9, 0x9e, 0xce, 0x09, 0x75, 0x42, 0xfd, 0xcd, 0xb6, 0xce, 0x89, + 0x8d, 0x19, 0xd7, 0x6d, 0x37, 0x02, 0x18, 0x94, 0xd9, 0x94, 0x29, 0x23, 0x9d, 0x61, 0x65, 0x7a, + 0x32, 0xc2, 0x5c, 0x3f, 0x51, 0x0c, 0x4a, 0x42, 0x40, 0xe9, 0x87, 0x04, 0x12, 0x67, 0xcb, 0xce, + 0x60, 0x1a, 0x48, 0x04, 0xe5, 0xc4, 0x82, 0x58, 0xde, 0xd3, 0x24, 0x82, 0x60, 0x0e, 0xec, 0xeb, + 0x08, 0x79, 0x98, 0xb1, 0x9c, 0x54, 0x10, 0xcb, 0x49, 0x2d, 0x2a, 0xe1, 0x27, 0xf0, 0x62, 0xe2, + 0x63, 0x6f, 0x36, 0x34, 0xa8, 0x83, 0xc8, 0xb2, 0x9b, 0xdc, 0x93, 0x82, 0x58, 0x4e, 0x55, 0x8b, + 0x95, 0x7b, 0xb9, 0x2a, 0xbd, 0xa5, 0xb3, 0x1e, 0x19, 0xb5, 0xf4, 0x64, 0xa3, 0x86, 0x5d, 0x70, + 0x30, 0xc5, 0x8c, 0x13, 0xc7, 0xbc, 0x43, 0xdb, 0x0b, 0x68, 0x6f, 0x77, 0xd0, 0x2e, 0x56, 0xde, + 0x35, 0x2f, 0x33, 0xdd, 0x5a, 0xb9, 0x4b, 0x1c, 0x7b, 0x78, 0xe2, 0x63, 0xc7, 0x98, 0xe5, 0x12, + 0x05, 0xb1, 0x9c, 0xfe, 0x17, 0xb1, 0x11, 0x59, 0x63, 0x62, 0xbc, 0x52, 0x32, 0x40, 0x7a, 0x33, + 0x05, 0x3c, 0x05, 0xfb, 0x8c, 0xeb, 0xd7, 0xd8, 0x63, 0xc1, 0xc0, 0x52, 0xd5, 0xf2, 0x7f, 0x93, + 0xf7, 0x57, 0xfe, 0xa6, 0xa0, 0x45, 0x5b, 0x6b, 0x29, 0x90, 0x8c, 0x33, 0x97, 0x7e, 0x8a, 0x20, + 0xb3, 0x9d, 0x0e, 0xb6, 0x41, 0xd2, 0xc5, 0x9e, 0x8b, 0xb9, 0xaf, 0x5b, 0xe1, 0x49, 0xef, 0x1e, + 0x31, 0x95, 0x6e, 0xb4, 0xa7, 0x29, 0x68, 0x6b, 0x00, 0xac, 0x81, 0x04, 0x76, 0xa9, 0x71, 0x15, + 0xdc, 0x67, 0xaa, 0x7a, 0xfc, 0x08, 0x52, 0x9b, 0xd8, 0x84, 0x63, 0xd4, 0x14, 0xb4, 0xd5, 0xd6, + 0xcd, 0x9e, 0xb3, 0xe0, 0x70, 0x67, 0xc8, 0x52, 0x1e, 0xbc, 0x7a, 0xb0, 0xa7, 0xd2, 0x25, 0xc8, + 0x3e, 0x70, 0x0c, 0xcc, 0x83, 0xa4, 0xe3, 0xdb, 0x43, 0xdf, 0x21, 0x9c, 0x85, 0xaf, 0xe2, 0x33, + 0xc7, 0xb7, 0x07, 0xcb, 0x1a, 0x16, 0xc1, 0xf3, 0x31, 0xb1, 0x2c, 0x8c, 0x42, 0x5d, 0x0a, 0xf4, + 0xd4, 0x6a, 0x2d, 0xb0, 0x1c, 0xd3, 0x78, 0x86, 0xf1, 0xed, 0xc1, 0x22, 0x78, 0x7d, 0xa1, 0xf6, + 0xbf, 0xb4, 0x3a, 0x67, 0xc3, 0x86, 0xa6, 0xf6, 0x06, 0x6a, 0xa7, 0x7e, 0x39, 0x1c, 0x74, 0xfa, + 0x5d, 0xb5, 0xde, 0x6a, 0xb4, 0xd4, 0xd3, 0x8c, 0x00, 0xf3, 0x20, 0x7b, 0xdf, 0x52, 0x6b, 0x9f, + 0xd7, 0x3f, 0x67, 0xc4, 0xdd, 0xa2, 0xda, 0x3d, 0xaf, 0x37, 0x33, 0x52, 0xad, 0xf7, 0x6b, 0x2e, + 0x8b, 0xb7, 0x73, 0x59, 0xfc, 0x33, 0x97, 0xc5, 0xef, 0x0b, 0x59, 0xb8, 0x5d, 0xc8, 0xc2, 0xef, + 0x85, 0x2c, 0x7c, 0xfd, 0x68, 0x12, 0x7e, 0xe5, 0x8f, 0x2a, 0x06, 0xb5, 0x15, 0x34, 0xb3, 0xb1, + 0xc3, 0x08, 0x75, 0x6e, 0x66, 0xdf, 0xd6, 0xc5, 0x7b, 0x0f, 0x5d, 0x2b, 0x37, 0xca, 0xfa, 0x0f, + 0xc1, 0x67, 0x2e, 0x66, 0xa3, 0xa7, 0xc1, 0x87, 0xf9, 0xe1, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x0d, 0x79, 0x88, 0x25, 0x3b, 0x04, 0x00, 0x00, } func (m *Gauge) Marshal() (dAtA []byte, err error) { @@ -524,6 +504,11 @@ func (m *Gauge) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.VestingFrequency != 0 { + i = encodeVarintGauge(dAtA, i, uint64(m.VestingFrequency)) + i-- + dAtA[i] = 0x28 + } if m.VestingCondition != nil { { size, err := m.VestingCondition.MarshalToSizedBuffer(dAtA[:i]) @@ -616,27 +601,6 @@ func (m *QueryCondition_Stakers) MarshalToSizedBuffer(dAtA []byte) (int, error) } return len(dAtA) - i, nil } -func (m *QueryCondition_Funds) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryCondition_Funds) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - if m.Funds != nil { - { - size, err := m.Funds.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGauge(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - return len(dAtA) - i, nil -} func (m *VestingCondition) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -669,16 +633,16 @@ func (m *VestingCondition) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *VestingCondition_Immediate) MarshalTo(dAtA []byte) (int, error) { +func (m *VestingCondition_Perpetual) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *VestingCondition_Immediate) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *VestingCondition_Perpetual) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) - if m.Immediate != nil { + if m.Perpetual != nil { { - size, err := m.Immediate.MarshalToSizedBuffer(dAtA[:i]) + size, err := m.Perpetual.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -734,44 +698,7 @@ func (m *QueryConditionStakers) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *QueryConditionFunds) 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 *QueryConditionFunds) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryConditionFunds) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Threshold) > 0 { - for iNdEx := len(m.Threshold) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Threshold[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGauge(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x42 - } - } - return len(dAtA) - i, nil -} - -func (m *VestingConditionImmediate) Marshal() (dAtA []byte, err error) { +func (m *VestingConditionPerpetual) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -781,12 +708,12 @@ func (m *VestingConditionImmediate) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *VestingConditionImmediate) MarshalTo(dAtA []byte) (int, error) { +func (m *VestingConditionPerpetual) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *VestingConditionImmediate) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *VestingConditionPerpetual) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -794,7 +721,7 @@ func (m *VestingConditionImmediate) MarshalToSizedBuffer(dAtA []byte) (int, erro return len(dAtA) - i, nil } -func (m *VestingConditionEpoch) Marshal() (dAtA []byte, err error) { +func (m *VestingConditionLimited) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -804,23 +731,23 @@ func (m *VestingConditionEpoch) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *VestingConditionEpoch) MarshalTo(dAtA []byte) (int, error) { +func (m *VestingConditionLimited) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *VestingConditionEpoch) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *VestingConditionLimited) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if m.FilledEpochs != 0 { - i = encodeVarintGauge(dAtA, i, uint64(m.FilledEpochs)) + if m.FilledUnits != 0 { + i = encodeVarintGauge(dAtA, i, uint64(m.FilledUnits)) i-- dAtA[i] = 0x10 } - if m.NumEpochsPaidOver != 0 { - i = encodeVarintGauge(dAtA, i, uint64(m.NumEpochsPaidOver)) + if m.NumUnits != 0 { + i = encodeVarintGauge(dAtA, i, uint64(m.NumUnits)) i-- dAtA[i] = 0x8 } @@ -859,6 +786,9 @@ func (m *Gauge) Size() (n int) { l = m.VestingCondition.Size() n += 1 + l + sovGauge(uint64(l)) } + if m.VestingFrequency != 0 { + n += 1 + sovGauge(uint64(m.VestingFrequency)) + } return n } @@ -886,18 +816,6 @@ func (m *QueryCondition_Stakers) Size() (n int) { } return n } -func (m *QueryCondition_Funds) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Funds != nil { - l = m.Funds.Size() - n += 1 + l + sovGauge(uint64(l)) - } - return n -} func (m *VestingCondition) Size() (n int) { if m == nil { return 0 @@ -910,14 +828,14 @@ func (m *VestingCondition) Size() (n int) { return n } -func (m *VestingCondition_Immediate) Size() (n int) { +func (m *VestingCondition_Perpetual) Size() (n int) { if m == nil { return 0 } var l int _ = l - if m.Immediate != nil { - l = m.Immediate.Size() + if m.Perpetual != nil { + l = m.Perpetual.Size() n += 1 + l + sovGauge(uint64(l)) } return n @@ -943,22 +861,7 @@ func (m *QueryConditionStakers) Size() (n int) { return n } -func (m *QueryConditionFunds) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if len(m.Threshold) > 0 { - for _, e := range m.Threshold { - l = e.Size() - n += 1 + l + sovGauge(uint64(l)) - } - } - return n -} - -func (m *VestingConditionImmediate) Size() (n int) { +func (m *VestingConditionPerpetual) Size() (n int) { if m == nil { return 0 } @@ -967,17 +870,17 @@ func (m *VestingConditionImmediate) Size() (n int) { return n } -func (m *VestingConditionEpoch) Size() (n int) { +func (m *VestingConditionLimited) Size() (n int) { if m == nil { return 0 } var l int _ = l - if m.NumEpochsPaidOver != 0 { - n += 1 + sovGauge(uint64(m.NumEpochsPaidOver)) + if m.NumUnits != 0 { + n += 1 + sovGauge(uint64(m.NumUnits)) } - if m.FilledEpochs != 0 { - n += 1 + sovGauge(uint64(m.FilledEpochs)) + if m.FilledUnits != 0 { + n += 1 + sovGauge(uint64(m.FilledUnits)) } return n } @@ -1140,6 +1043,25 @@ func (m *Gauge) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field VestingFrequency", wireType) + } + m.VestingFrequency = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGauge + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.VestingFrequency |= VestingFrequency(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipGauge(dAtA[iNdEx:]) @@ -1225,41 +1147,6 @@ func (m *QueryCondition) Unmarshal(dAtA []byte) error { } m.Condition = &QueryCondition_Stakers{v} iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Funds", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGauge - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthGauge - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGauge - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - v := &QueryConditionFunds{} - if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - m.Condition = &QueryCondition_Funds{v} - iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGauge(dAtA[iNdEx:]) @@ -1312,7 +1199,7 @@ func (m *VestingCondition) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Immediate", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Perpetual", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1339,11 +1226,11 @@ func (m *VestingCondition) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - v := &VestingConditionImmediate{} + v := &VestingConditionPerpetual{} if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } - m.Condition = &VestingCondition_Immediate{v} + m.Condition = &VestingCondition_Perpetual{v} iNdEx = postIndex case 2: if wireType != 2 { @@ -1374,7 +1261,7 @@ func (m *VestingCondition) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - v := &VestingConditionEpoch{} + v := &VestingConditionLimited{} if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -1451,91 +1338,7 @@ func (m *QueryConditionStakers) Unmarshal(dAtA []byte) error { } return nil } -func (m *QueryConditionFunds) 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 ErrIntOverflowGauge - } - 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: QueryConditionFunds: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryConditionFunds: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 8: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Threshold", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGauge - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthGauge - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGauge - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Threshold = append(m.Threshold, types.Coin{}) - if err := m.Threshold[len(m.Threshold)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipGauge(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthGauge - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *VestingConditionImmediate) Unmarshal(dAtA []byte) error { +func (m *VestingConditionPerpetual) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1558,10 +1361,10 @@ func (m *VestingConditionImmediate) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: VestingConditionImmediate: wiretype end group for non-group") + return fmt.Errorf("proto: VestingConditionPerpetual: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: VestingConditionImmediate: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: VestingConditionPerpetual: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { default: @@ -1585,7 +1388,7 @@ func (m *VestingConditionImmediate) Unmarshal(dAtA []byte) error { } return nil } -func (m *VestingConditionEpoch) Unmarshal(dAtA []byte) error { +func (m *VestingConditionLimited) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1608,17 +1411,17 @@ func (m *VestingConditionEpoch) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: VestingConditionEpoch: wiretype end group for non-group") + return fmt.Errorf("proto: VestingConditionLimited: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: VestingConditionEpoch: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: VestingConditionLimited: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field NumEpochsPaidOver", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field NumUnits", wireType) } - m.NumEpochsPaidOver = 0 + m.NumUnits = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGauge @@ -1628,16 +1431,16 @@ func (m *VestingConditionEpoch) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.NumEpochsPaidOver |= uint64(b&0x7F) << shift + m.NumUnits |= uint64(b&0x7F) << shift if b < 0x80 { break } } case 2: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field FilledEpochs", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field FilledUnits", wireType) } - m.FilledEpochs = 0 + m.FilledUnits = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGauge @@ -1647,7 +1450,7 @@ func (m *VestingConditionEpoch) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.FilledEpochs |= uint64(b&0x7F) << shift + m.FilledUnits |= uint64(b&0x7F) << shift if b < 0x80 { break } diff --git a/x/dividends/types/keys.go b/x/dividends/types/keys.go index 8eef0bcf..b9783439 100644 --- a/x/dividends/types/keys.go +++ b/x/dividends/types/keys.go @@ -1,6 +1,8 @@ package types -var ( +import "cosmossdk.io/collections" + +const ( // ModuleName defines the module name. ModuleName = "dividends" @@ -9,13 +11,16 @@ var ( // RouterKey is the message route for slashing. RouterKey = ModuleName +) - // QuerierRoute defines the module's query routing key. - QuerierRoute = ModuleName - - // KeyLastGaugeID defines key for setting last gauge ID. - KeyLastGaugeID = []byte{0x01} +const ( + ParamsByte = iota // Module params: Params + LastGaugeByte // GaugeID sequence + GaugesByte // Gauges: GaugeID -> Gauge +) - // KeyPrefixGauges defines prefix key for storing reference key for all gauges. - KeyPrefixGauges = []byte{0x02} +var ( + ParamsKey = collections.NewPrefix(ParamsByte) + LastGaugeKey = collections.NewPrefix(LastGaugeByte) + GaugesKey = collections.NewPrefix(GaugesByte) ) diff --git a/x/dividends/types/tx.pb.go b/x/dividends/types/tx.pb.go index 9c147ed6..42537855 100644 --- a/x/dividends/types/tx.pb.go +++ b/x/dividends/types/tx.pb.go @@ -38,8 +38,10 @@ type MsgCreateGauge struct { Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` // query_condition is *where* the gauge rewards are distributed to QueryCondition *QueryCondition `protobuf:"bytes,3,opt,name=query_condition,json=queryCondition,proto3" json:"query_condition,omitempty"` - // vesting_condition is *when* the gauge rewards are distributed to + // vesting_condition is *how long* the gauge rewards are distributed to VestingCondition *VestingCondition `protobuf:"bytes,4,opt,name=vesting_condition,json=vestingCondition,proto3" json:"vesting_condition,omitempty"` + // vesting_condition is *how frequent* the gauge rewards are distributed to + VestingFrequency VestingFrequency `protobuf:"varint,5,opt,name=vesting_frequency,json=vestingFrequency,proto3,enum=rollapp.dividends.VestingFrequency" json:"vesting_frequency,omitempty"` } func (m *MsgCreateGauge) Reset() { *m = MsgCreateGauge{} } @@ -103,6 +105,13 @@ func (m *MsgCreateGauge) GetVestingCondition() *VestingCondition { return nil } +func (m *MsgCreateGauge) GetVestingFrequency() VestingFrequency { + if m != nil { + return m.VestingFrequency + } + return VestingFrequency_VESTING_FREQUENCY_UNSPECIFIED +} + type MsgCreateGaugeResponse struct { } @@ -147,30 +156,31 @@ func init() { func init() { proto.RegisterFile("dividends/tx.proto", fileDescriptor_957086822ec1c0b6) } var fileDescriptor_957086822ec1c0b6 = []byte{ - // 357 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x92, 0xb1, 0x6f, 0xe2, 0x30, - 0x14, 0xc6, 0x31, 0xa0, 0x3b, 0x9d, 0x91, 0xb8, 0x23, 0xba, 0x3b, 0x45, 0x0c, 0x39, 0x8e, 0x2e, - 0x74, 0x68, 0x2c, 0xe8, 0xd0, 0xbd, 0x0c, 0x95, 0x2a, 0x21, 0x95, 0x0c, 0x1d, 0xda, 0xa1, 0x4a, - 0xe2, 0x57, 0xd7, 0x2a, 0xf1, 0x0b, 0xb1, 0x13, 0x91, 0xfe, 0x15, 0xfd, 0xb3, 0x3a, 0x32, 0x32, - 0x56, 0xf0, 0x8f, 0x54, 0x04, 0x28, 0xd0, 0x22, 0x75, 0xf3, 0xf7, 0xbe, 0x9f, 0xbe, 0xe7, 0x4f, - 0x36, 0xb5, 0xb8, 0xcc, 0x24, 0x07, 0xc5, 0x35, 0x33, 0x13, 0x37, 0x4e, 0xd0, 0xa0, 0xd5, 0x48, - 0x70, 0x34, 0xf2, 0xe3, 0xd8, 0x7d, 0xf7, 0x9a, 0xbf, 0x05, 0x0a, 0x2c, 0x5c, 0xb6, 0x3c, 0xad, - 0xc0, 0xe6, 0x3f, 0x81, 0x28, 0x46, 0xc0, 0x0a, 0x15, 0xa4, 0xf7, 0xcc, 0xc8, 0x08, 0xb4, 0xf1, - 0xa3, 0x78, 0x0d, 0x38, 0x21, 0xea, 0x08, 0x35, 0x0b, 0x7c, 0x0d, 0x2c, 0xeb, 0x06, 0x60, 0xfc, - 0x2e, 0x0b, 0x51, 0xaa, 0xb5, 0xff, 0x67, 0xbb, 0x5d, 0xf8, 0xa9, 0x80, 0xd5, 0xb8, 0x3d, 0x23, - 0xb4, 0x3e, 0xd0, 0xa2, 0x9f, 0x80, 0x6f, 0xe0, 0x62, 0x69, 0x58, 0x75, 0x5a, 0x96, 0xdc, 0x26, - 0x2d, 0xd2, 0xa9, 0x7a, 0x65, 0xc9, 0x2d, 0x9b, 0x7e, 0xf7, 0x39, 0x4f, 0x40, 0x6b, 0xbb, 0xdc, - 0x22, 0x9d, 0x1f, 0xde, 0x46, 0x5a, 0x97, 0xf4, 0xe7, 0x38, 0x85, 0x24, 0xbf, 0x0b, 0x51, 0x71, - 0x69, 0x24, 0x2a, 0xbb, 0xd2, 0x22, 0x9d, 0x5a, 0xef, 0xbf, 0xfb, 0xa9, 0x97, 0x3b, 0x5c, 0x92, - 0xfd, 0x0d, 0xe8, 0xd5, 0xc7, 0x7b, 0xda, 0xba, 0xa2, 0x8d, 0x0c, 0xb4, 0x91, 0x4a, 0xec, 0xa4, - 0x55, 0x8b, 0xb4, 0xa3, 0x03, 0x69, 0xd7, 0x2b, 0x76, 0x9b, 0xf7, 0x2b, 0xfb, 0x30, 0x69, 0xdb, - 0xf4, 0xef, 0x7e, 0x33, 0x0f, 0x74, 0x8c, 0x4a, 0x43, 0x2f, 0xa0, 0x95, 0x81, 0x16, 0xd6, 0x2d, - 0xad, 0xed, 0xf6, 0x3e, 0x74, 0xe9, 0xfd, 0x80, 0xe6, 0xf1, 0x97, 0xc8, 0x66, 0xc7, 0xf9, 0xf0, - 0x65, 0xee, 0x90, 0xe9, 0xdc, 0x21, 0xaf, 0x73, 0x87, 0x3c, 0x2f, 0x9c, 0xd2, 0x74, 0xe1, 0x94, - 0x66, 0x0b, 0xa7, 0x74, 0x73, 0x26, 0xa4, 0x79, 0x48, 0x03, 0x37, 0xc4, 0x88, 0xf1, 0x3c, 0x02, - 0xa5, 0x25, 0xaa, 0x49, 0xfe, 0xb4, 0x15, 0x27, 0x09, 0x7f, 0x64, 0x13, 0xb6, 0xf3, 0x5f, 0xf2, - 0x18, 0x74, 0xf0, 0xad, 0x78, 0xb2, 0xd3, 0xb7, 0x00, 0x00, 0x00, 0xff, 0xff, 0x86, 0xcb, 0x72, - 0xf4, 0x49, 0x02, 0x00, 0x00, + // 382 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x92, 0xc1, 0x8e, 0xd2, 0x40, + 0x18, 0xc7, 0x99, 0x82, 0x1a, 0x87, 0xa4, 0x4a, 0xa3, 0xa6, 0xe1, 0x50, 0x2b, 0x5e, 0xea, 0xc1, + 0x4e, 0xc0, 0x83, 0x77, 0x49, 0x34, 0x31, 0x21, 0x91, 0x1e, 0x3c, 0xe8, 0xc1, 0xb4, 0x9d, 0x8f, + 0x71, 0x22, 0x9d, 0x29, 0x9d, 0x69, 0x43, 0x7d, 0x8a, 0x7d, 0x8e, 0x7d, 0x92, 0x3d, 0x72, 0xdc, + 0xe3, 0x06, 0x5e, 0x64, 0x43, 0xa1, 0x50, 0x76, 0xc9, 0xee, 0xad, 0xff, 0xef, 0xff, 0xcb, 0x6f, + 0xd2, 0x2f, 0x1f, 0xb6, 0x28, 0x2f, 0x38, 0x05, 0x41, 0x15, 0xd1, 0x4b, 0x3f, 0xcd, 0xa4, 0x96, + 0x56, 0x2f, 0x93, 0xf3, 0x79, 0x98, 0xa6, 0xfe, 0xa1, 0xeb, 0xbf, 0x62, 0x92, 0xc9, 0xaa, 0x25, + 0xdb, 0xaf, 0x1d, 0xd8, 0x7f, 0xcb, 0xa4, 0x64, 0x73, 0x20, 0x55, 0x8a, 0xf2, 0x19, 0xd1, 0x3c, + 0x01, 0xa5, 0xc3, 0x24, 0xdd, 0x03, 0x4e, 0x2c, 0x55, 0x22, 0x15, 0x89, 0x42, 0x05, 0xa4, 0x18, + 0x46, 0xa0, 0xc3, 0x21, 0x89, 0x25, 0x17, 0xfb, 0xfe, 0xf5, 0xf1, 0x75, 0x16, 0xe6, 0x0c, 0x76, + 0xe3, 0xc1, 0xa5, 0x81, 0xcd, 0x89, 0x62, 0xe3, 0x0c, 0x42, 0x0d, 0xdf, 0xb6, 0x85, 0x65, 0x62, + 0x83, 0x53, 0x1b, 0xb9, 0xc8, 0xeb, 0x04, 0x06, 0xa7, 0x96, 0x8d, 0x9f, 0x85, 0x94, 0x66, 0xa0, + 0x94, 0x6d, 0xb8, 0xc8, 0x7b, 0x1e, 0xd4, 0xd1, 0xfa, 0x8e, 0x5f, 0x2c, 0x72, 0xc8, 0xca, 0x3f, + 0xb1, 0x14, 0x94, 0x6b, 0x2e, 0x85, 0xdd, 0x76, 0x91, 0xd7, 0x1d, 0xbd, 0xf3, 0xef, 0xfd, 0x97, + 0x3f, 0xdd, 0x92, 0xe3, 0x1a, 0x0c, 0xcc, 0xc5, 0x49, 0xb6, 0x7e, 0xe0, 0x5e, 0x01, 0x4a, 0x73, + 0xc1, 0x1a, 0xb6, 0x4e, 0x65, 0x7b, 0x7f, 0xc6, 0xf6, 0x73, 0xc7, 0x1e, 0x7d, 0x2f, 0x8b, 0x3b, + 0x93, 0xa6, 0x71, 0x96, 0xc1, 0x22, 0x07, 0x11, 0x97, 0xf6, 0x13, 0x17, 0x79, 0xe6, 0x43, 0xc6, + 0xaf, 0x35, 0x7a, 0x30, 0x1e, 0x26, 0x03, 0x1b, 0xbf, 0x39, 0xdd, 0x55, 0x00, 0x2a, 0x95, 0x42, + 0xc1, 0x28, 0xc2, 0xed, 0x89, 0x62, 0xd6, 0x6f, 0xdc, 0x6d, 0x6e, 0xf2, 0xdc, 0x1a, 0x4e, 0x05, + 0xfd, 0x0f, 0x8f, 0x22, 0xf5, 0x1b, 0x5f, 0xa6, 0x57, 0x6b, 0x07, 0xad, 0xd6, 0x0e, 0xba, 0x59, + 0x3b, 0xe8, 0x62, 0xe3, 0xb4, 0x56, 0x1b, 0xa7, 0x75, 0xbd, 0x71, 0x5a, 0xbf, 0x3e, 0x33, 0xae, + 0xff, 0xe6, 0x91, 0x1f, 0xcb, 0x84, 0xd0, 0x32, 0x01, 0xa1, 0xb8, 0x14, 0xcb, 0xf2, 0xff, 0x31, + 0x7c, 0xcc, 0xe8, 0x3f, 0xb2, 0x24, 0x8d, 0x0b, 0x2c, 0x53, 0x50, 0xd1, 0xd3, 0xea, 0x08, 0x3e, + 0xdd, 0x06, 0x00, 0x00, 0xff, 0xff, 0x0f, 0x02, 0x00, 0xd7, 0x9b, 0x02, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -273,6 +283,11 @@ func (m *MsgCreateGauge) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.VestingFrequency != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.VestingFrequency)) + i-- + dAtA[i] = 0x28 + } if m.VestingCondition != nil { { size, err := m.VestingCondition.MarshalToSizedBuffer(dAtA[:i]) @@ -367,6 +382,9 @@ func (m *MsgCreateGauge) Size() (n int) { l = m.VestingCondition.Size() n += 1 + l + sovTx(uint64(l)) } + if m.VestingFrequency != 0 { + n += 1 + sovTx(uint64(m.VestingFrequency)) + } return n } @@ -537,6 +555,25 @@ func (m *MsgCreateGauge) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field VestingFrequency", wireType) + } + m.VestingFrequency = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.VestingFrequency |= VestingFrequency(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) diff --git a/x/dividends/types/types.go b/x/dividends/types/types.go new file mode 100644 index 00000000..ab1254f4 --- /dev/null +++ b/x/dividends/types/types.go @@ -0,0 +1 @@ +package types