From 6812b457bcaa41b4137552e1936b74a68e176361 Mon Sep 17 00:00:00 2001 From: stackman27 Date: Tue, 15 Aug 2023 19:35:18 +0000 Subject: [PATCH 1/7] (v18: feat) Volume-Split, setup gauges to split evenly --- proto/osmosis/incentives/gauge.proto | 8 + proto/osmosis/lockup/lock.proto | 1 + x/incentives/keeper/distribute.go | 48 +++- x/incentives/keeper/distribute_test.go | 251 ++++++++++++++++-- x/incentives/keeper/gauge.go | 106 ++++++++ x/incentives/keeper/gauge_test.go | 140 ++++++++++ x/incentives/keeper/hooks.go | 8 +- x/incentives/keeper/keeper_test.go | 1 - x/incentives/keeper/store.go | 42 +++ x/incentives/keeper/store_test.go | 49 +++- x/incentives/types/gauge.pb.go | 343 ++++++++++++++++++++++--- x/incentives/types/keys.go | 7 + x/lockup/types/lock.pb.go | 86 ++++--- 13 files changed, 991 insertions(+), 99 deletions(-) diff --git a/proto/osmosis/incentives/gauge.proto b/proto/osmosis/incentives/gauge.proto index 7571090e1dc..f18beaea1ca 100644 --- a/proto/osmosis/incentives/gauge.proto +++ b/proto/osmosis/incentives/gauge.proto @@ -50,6 +50,14 @@ message Gauge { ]; } +// Gauge is an object that stores GroupGaugeId as well as internalGaugeIds. We +// linked these two together so that we can distribute tokens from groupGauge to +// internalGauges. +message GroupGauge { + uint64 group_gauge_id = 1; + repeated uint64 internal_ids = 2; +} + message LockableDurationsInfo { // List of incentivised durations that gauges will pay out to repeated google.protobuf.Duration lockable_durations = 1 [ diff --git a/proto/osmosis/lockup/lock.proto b/proto/osmosis/lockup/lock.proto index 5d39efb93c3..9c4624ab9a1 100644 --- a/proto/osmosis/lockup/lock.proto +++ b/proto/osmosis/lockup/lock.proto @@ -57,6 +57,7 @@ enum LockQueryType { ByDuration = 0; ByTime = 1; NoLock = 2; + ByGroup = 3; } // QueryCondition is a struct used for querying locks upon different conditions. diff --git a/x/incentives/keeper/distribute.go b/x/incentives/keeper/distribute.go index d99e4b28cda..19daa376757 100644 --- a/x/incentives/keeper/distribute.go +++ b/x/incentives/keeper/distribute.go @@ -266,6 +266,46 @@ func (k Keeper) distributeSyntheticInternal( return k.distributeInternal(ctx, gauge, sortedAndTrimmedQualifiedLocks, distrInfo) } +// AllocateAcrossGauges gets all the active groupGauges and distributes tokens evenly based on the internalGauges set for that +// groupGauge. After each iteration we update the groupGauge by modifying filledEpoch and distributed coins. +// TODO: Replace even eplit by volume split once its implemented. +func (k Keeper) AllocateAcrossGauges(ctx sdk.Context) error { + currTime := ctx.BlockTime() + + groupGauges, err := k.GetAllGroupGauges(ctx) + if err != nil { + return err + } + + for _, groupGauge := range groupGauges { + gauge, err := k.GetGaugeByID(ctx, groupGauge.GroupGaugeId) + if err != nil { + return err + } + + // only allow distribution if the GroupGauge is Active + if currTime.After(gauge.StartTime) || currTime.Equal(gauge.StartTime) && (gauge.IsPerpetual || gauge.FilledEpochs < gauge.NumEpochsPaidOver) { + // TODO: replace the calculation below by volume split. + remainCoins := gauge.Coins.Sub(gauge.DistributedCoins) + amountToDistributeThisEpoch := remainCoins[0].Amount.Quo(sdk.NewInt(int64(gauge.NumEpochsPaidOver - (gauge.FilledEpochs)))) + amountToDistributePerInternalGauge := amountToDistributeThisEpoch.Quo(sdk.NewInt(int64(len(groupGauge.InternalIds)))) + + for _, internalGaugeId := range groupGauge.InternalIds { + err = k.AddToGaugeRewardsFromGauge(ctx, groupGauge.GroupGaugeId, sdk.NewCoins(sdk.NewCoin(remainCoins[0].Denom, amountToDistributePerInternalGauge)), internalGaugeId) + if err != nil { + return err + } + } + + // we distribute tokens from groupGauge to internal gauge therefore update groupGauge fields + // updates filledEpoch and distributedCoins + k.updateGaugePostDistribute(ctx, *gauge, sdk.NewCoins(sdk.NewCoin(gauge.Coins[0].Denom, amountToDistributeThisEpoch))) + } + } + + return nil +} + // distributeInternal runs the distribution logic for a gauge, and adds the sends to // the distrInfo struct. It also updates the gauge for the distribution. // It handles any kind of gauges: @@ -285,6 +325,7 @@ func (k Keeper) distributeInternal( totalDistrCoins := sdk.NewCoins() remainCoins := gauge.Coins.Sub(gauge.DistributedCoins) + // if its a perpetual gauge, we set remaining epochs to 1. // otherwise is is a non perpetual gauge and we determine how many epoch payouts are left remainEpochs := uint64(1) @@ -329,7 +370,6 @@ func (k Keeper) distributeInternal( // for ex: 10000uosmo to be distributed over 1day epoch will be 1000 tokens ÷ 86,400 seconds ≈ 0.01157 tokens per second (truncated) // Note: reason why we do millisecond conversion is because floats are non-deterministic. emissionRate := sdk.NewDecFromInt(remainAmountPerEpoch).QuoTruncate(sdk.NewDec(currentEpoch.Duration.Milliseconds()).QuoInt(sdk.NewInt(1000))) - ctx.Logger().Debug("distributeInternal, CreateIncentiveRecord NoLock gauge", "module", types.ModuleName, "gaugeId", gauge.Id, "poolId", pool.GetId(), "remainCoinPerEpoch", remainCoinPerEpoch, "height", ctx.BlockHeight()) _, err := k.clk.CreateIncentive(ctx, pool.GetId(), @@ -346,7 +386,6 @@ func (k Keeper) distributeInternal( if err != nil { return nil, err } - totalDistrCoins = totalDistrCoins.Add(remainCoinPerEpoch) } } else { @@ -441,7 +480,10 @@ func (k Keeper) Distribute(ctx sdk.Context, gauges []types.Gauge) (sdk.Coins, er ctx.Logger().Debug("distributeSyntheticInternal, gauge id %d, %d", "module", types.ModuleName, "gaugeId", gauge.Id, "height", ctx.BlockHeight()) gaugeDistributedCoins, err = k.distributeSyntheticInternal(ctx, gauge, filteredLocks, &distrInfo) } else { - gaugeDistributedCoins, err = k.distributeInternal(ctx, gauge, filteredLocks, &distrInfo) + // Donot distribue if LockQueryType = Group, because if we distribute here we will be double distributing. + if gauge.DistributeTo.LockQueryType != lockuptypes.ByGroup { + gaugeDistributedCoins, err = k.distributeInternal(ctx, gauge, filteredLocks, &distrInfo) + } } if err != nil { return nil, err diff --git a/x/incentives/keeper/distribute_test.go b/x/incentives/keeper/distribute_test.go index 667e86a497e..fe3b29671b0 100644 --- a/x/incentives/keeper/distribute_test.go +++ b/x/incentives/keeper/distribute_test.go @@ -883,30 +883,31 @@ func (s *KeeperTestSuite) TestGetPoolFromGaugeId() { // TestFunctionalInternalExternalCLGauge is a functional test that covers more complex scenarios relating to distributing incentives through gauges // at the end of each epoch. // -// // Testing strategy: // 1. Initialize variables. // 2. Setup CL pool and gauge (gauge automatically gets created at the end of CL pool creation). // 3. Create external no-lock gauges for CL pools // 4. Create Distribution records to incentivize internal CL no-lock gauges // 5. let epoch 1 pass -// - we only distribute external incentive in epoch 1. -// - Check that incentive record has been correctly created and gauge has been correctly updated. -// - all perpetual gauges must finish distributing records -// - ClPool1 will recieve full 1Musdc, 1Meth in this epoch. -// - ClPool2 will recieve 500kusdc, 500keth in this epoch. -// - ClPool3 will recieve full 1Musdc, 1Meth in this epoch whereas +// - we only distribute external incentive in epoch 1. +// - Check that incentive record has been correctly created and gauge has been correctly updated. +// - all perpetual gauges must finish distributing records +// - ClPool1 will recieve full 1Musdc, 1Meth in this epoch. +// - ClPool2 will recieve 500kusdc, 500keth in this epoch. +// - ClPool3 will recieve full 1Musdc, 1Meth in this epoch whereas +// // 6. Remove distribution records for internal incentives using HandleReplacePoolIncentivesProposal // 7. let epoch 2 pass -// - We distribute internal incentive in epoch 2. -// - check only external non-perpetual gauges with 2 epochs distributed -// - check gauge has been correctly updated -// - ClPool1 will already have 1Musdc, 1Meth (from epoch1) as external incentive. Will recieve 750Kstake as internal incentive. -// - ClPool2 will already have 500kusdc, 500keth (from epoch1) as external incentive. Will recieve 500kusdc, 500keth (from epoch 2) as external incentive and 750Kstake as internal incentive. -// - ClPool3 will already have 1M, 1M (from epoch1) as external incentive. This pool will not recieve any internal incentive. +// - We distribute internal incentive in epoch 2. +// - check only external non-perpetual gauges with 2 epochs distributed +// - check gauge has been correctly updated +// - ClPool1 will already have 1Musdc, 1Meth (from epoch1) as external incentive. Will recieve 750Kstake as internal incentive. +// - ClPool2 will already have 500kusdc, 500keth (from epoch1) as external incentive. Will recieve 500kusdc, 500keth (from epoch 2) as external incentive and 750Kstake as internal incentive. +// - ClPool3 will already have 1M, 1M (from epoch1) as external incentive. This pool will not recieve any internal incentive. +// // 8. let epoch 3 pass -// - nothing distributes as non-perpetual gauges with 2 epochs have ended and perpetual gauges have not been reloaded -// - nothing should change in terms of incentive records +// - nothing distributes as non-perpetual gauges with 2 epochs have ended and perpetual gauges have not been reloaded +// - nothing should change in terms of incentive records func (s *KeeperTestSuite) TestFunctionalInternalExternalCLGauge() { // 1. Initialize variables s.SetupTest() @@ -1131,3 +1132,223 @@ func (s *KeeperTestSuite) IncentivizeInternalGauge(poolIds []uint64, epochDurati ) s.Require().NoError(err) } +func (s *KeeperTestSuite) TestAllocateAcrossGauges() { + s.SetupTest() + expectedInternalGaugeCoins := sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(33_333_333))) + s.FundAcc(s.TestAccs[1], sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100_000_000)))) // 1,000 osmo + clPool := s.PrepareConcentratedPool() // gaugeid = 1 + + // create 3 internal Gauge + var internalGauges []uint64 + for i := 0; i <= 2; i++ { + internalGauge := s.CreateNoLockExternalGauges(clPool.GetId(), sdk.NewCoins(), s.TestAccs[1], uint64(1)) // gauge id = 2,3,4 + internalGauges = append(internalGauges, internalGauge) + } + + // create group gauge + groupGauge, err := s.App.IncentivesKeeper.CreateGroupGauge(s.Ctx, sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100_000_000))), uint64(1), s.TestAccs[1], internalGauges) // gauge id = 3 + s.Require().NoError(err) + + // Call AllocateAcrossGauges + // Allocate 100 osmo across 3 internal gauges evenly + s.App.IncentivesKeeper.AllocateAcrossGauges(s.Ctx) + + groupGaugePostAllocate, err := s.App.IncentivesKeeper.GetGaugeByID(s.Ctx, groupGauge) + s.Require().NoError(err) + + s.Require().Equal(groupGaugePostAllocate.Coins.Sub(groupGaugePostAllocate.DistributedCoins), sdk.Coins(nil)) + + for _, gauge := range internalGauges { + internalGauge, err := s.App.IncentivesKeeper.GetGaugeByID(s.Ctx, gauge) + s.Require().NoError(err) + + s.Require().Equal(internalGauge.Coins.Sub(internalGauge.DistributedCoins), expectedInternalGaugeCoins) + } + +} + +/* +Test Structure +Step 1: +Create 3 internal-gauges that'll we'll add to split incentives +Create 1 regular no-lock perp gauge to make sure it's flow is not affected + +Step 2: +Create Group Gauge with 100_000_000uosmo paid over 3 epoch, equally split between 3 internal gauges. +It also links internal-gauge with groupGauge Will look something like this: {groupGaugeId, [internalGaugeId1, internalGaugeId2, internalGaugeId3]} + +Step 3: +Let epoch 1 pass we expect: + + internalGauge1 to recieve 11_111_111uosmo, internalGauge2 to recieve 11_111_111uosmo, internalGauge3 to recieve 11_111_111uosmo + decrement GroupGauge coins from 100_000_000 - 33_333_333 = 66_666_667 + We also expect, regular gauge incentive to be distributed. + Hence, total 3 incentiveRecord for CL pools (2 from internal-gauges, 1 from regular gauge) & 1 GAMM lock incentive. + +Step 4: +Let epoch 2 pass, we expect: + + internalGauge1 to recieve 11_111_111uosmo, internalGauge2 to recieve 11_111_111uosmo, internalGauge3 to recieve 11_111_111uosmo + incentiveGauge1, incentiveGauge2, incentiveGauge3 should be empty + decrement GroupGauge coins from 66_666_667 - 33_333_333 = 33_333_334 + Hence, total 5 incentiveRecord for CL pools + +Step 5: +Let epoch 3 pass, we expect: + + internalGauge1 to recieve 11_111_111uosmo, internalGauge2 to recieve 11_111_111uosmo, internalGauge3 to recieve 11_111_111uosmo + incentiveGauge1, incentiveGauge2, incentiveGauge3 should be empty + decrement GroupGauge coins from 33_333_334 - 33_333_333 = 1 + Hence, total 7 incentiveRecord for CL pools +*/ +func (s *KeeperTestSuite) TestCreateGroupGaugeAndDistribute() { + var ( + epochInfo = s.App.IncentivesKeeper.GetEpochInfo(s.Ctx) + + expectedCoinsDistributed = sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(11_111_111))) + expectedCoinsDistributedEpoch2 = sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(11_111_111*2))) + expectedCoinsDistributedEpoch3 = sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(11_111_111*3))) + + expectedCoinsDistributedDecCoins = osmoutils.ConvertCoinsToDecCoins(expectedCoinsDistributed) + + emissionRateForPoolClPool = sdk.NewDecFromInt(sdk.NewInt(11_111_111)).QuoTruncate(sdk.NewDec(epochInfo.Duration.Milliseconds()).QuoInt(sdk.NewInt(1000))) + + expectedCoinsDistributedRegularGauge = osmoutils.ConvertCoinsToDecCoins(sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100)))) + newEmissionRateForClPool = sdk.NewDecFromInt(sdk.NewInt(100)).QuoTruncate(sdk.NewDec(epochInfo.Duration.Milliseconds()).QuoInt(sdk.NewInt(1000))) + + groupGaugeCoinAfterEpoch1 = sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(66_666_667))) + groupGaugeCoinAfterEpoch2 = sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(33_333_334))) + ) + + s.FundAcc(s.TestAccs[1], sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(1_000_000_000)))) // 1,000 osmo + + // Step 1 + clPool := s.PrepareConcentratedPool() // we already create a gauge here + internalGauge1 := s.CreateNoLockExternalGauges(clPool.GetId(), sdk.Coins{}, s.TestAccs[1], uint64(1)) // gauge id = 2 + internalGauge2 := s.CreateNoLockExternalGauges(clPool.GetId(), sdk.Coins{}, s.TestAccs[1], uint64(1)) // gauge id = 3 + internalGauge3, err := s.App.IncentivesKeeper.CreateGauge(s.Ctx, true, s.TestAccs[1], sdk.Coins{}, // gauge id = 4 + lockuptypes.QueryCondition{ + LockQueryType: lockuptypes.ByDuration, + Denom: "stake", // this denom is just for test, is subject to change + Duration: time.Hour * 7, // 7 hr is the max in test suite, will be 2weeks in mainnet + }, + s.Ctx.BlockTime(), + 1, + 0, + ) + s.Require().NoError(err) + + // Regular gauge no group gauge + _ = s.CreateNoLockExternalGauges(clPool.GetId(), sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100))), s.TestAccs[1], uint64(1)) // gauge id = 5 + + // Step 2 + // create GroupGauge + groupGaugeId, err := s.App.IncentivesKeeper.CreateGroupGauge(s.Ctx, sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100_000_000))), uint64(3), s.TestAccs[1], []uint64{internalGauge1, internalGauge2, internalGauge3}) // gauge id = 6 + s.Require().NoError(err) + + groupGauges, err := s.App.IncentivesKeeper.GetAllGroupGauges(s.Ctx) + s.Require().NoError(err) + + s.Require().NotEmpty(groupGauges) + + // Step 3 + //let epoch 1 pass + // ******************** EPOCH 1 ********************* + s.Ctx = s.Ctx.WithBlockTime(s.Ctx.BlockTime().Add(epochInfo.Duration)) + s.App.EpochsKeeper.AfterEpochEnd(s.Ctx, epochInfo.GetIdentifier(), 1) + + // Validate that group gauge coins went down by 33_333_333uosmo + groupGauge, err := s.App.IncentivesKeeper.GetGaugeByID(s.Ctx, groupGaugeId) + s.Require().NoError(err) + + s.Require().Equal(groupGauge.Coins.Sub(groupGauge.DistributedCoins), groupGaugeCoinAfterEpoch1) + + s.ValidateDistributedGauge(internalGauge1, 1, expectedCoinsDistributed) + s.ValidateDistributedGauge(internalGauge2, 1, expectedCoinsDistributed) + + // Validate that we created incentive record after distributing gaugeId 2,3,5 + clPoolIncentiveRecordsAtEpoch1, err := s.App.ConcentratedLiquidityKeeper.GetAllIncentiveRecordsForPool(s.Ctx, clPool.GetId()) + s.Require().NoError(err) + + s.Require().Equal(3, len(clPoolIncentiveRecordsAtEpoch1)) + + for i := 0; i < len(clPoolIncentiveRecordsAtEpoch1); i++ { + if i == 2 { + s.ValidateIncentiveRecord(clPool.GetId(), expectedCoinsDistributedRegularGauge[0], newEmissionRateForClPool, clPoolIncentiveRecordsAtEpoch1[i]) + } else { + s.ValidateIncentiveRecord(clPool.GetId(), expectedCoinsDistributedDecCoins[0], emissionRateForPoolClPool, clPoolIncentiveRecordsAtEpoch1[i]) + } + + } + // Step 4 + //let epoch 2 pass + // ******************** EPOCH 2 ********************* + s.Ctx = s.Ctx.WithBlockTime(s.Ctx.BlockTime().Add(epochInfo.Duration)) + s.App.EpochsKeeper.AfterEpochEnd(s.Ctx, epochInfo.GetIdentifier(), 2) + + // Validate that group gauge coins went down by 33_333_333uosmo + groupGauge, err = s.App.IncentivesKeeper.GetGaugeByID(s.Ctx, groupGaugeId) + s.Require().NoError(err) + + s.Require().Equal(groupGauge.Coins.Sub(groupGauge.DistributedCoins), groupGaugeCoinAfterEpoch2) + + s.ValidateDistributedGauge(internalGauge1, 2, expectedCoinsDistributedEpoch2) + s.ValidateDistributedGauge(internalGauge2, 2, expectedCoinsDistributedEpoch2) + + // Validate that we created incentive record after distributing gaugeId 2,3,5 + clPoolIncentiveRecordsAtEpoch2, err := s.App.ConcentratedLiquidityKeeper.GetAllIncentiveRecordsForPool(s.Ctx, clPool.GetId()) + s.Require().NoError(err) + + s.Require().Equal(5, len(clPoolIncentiveRecordsAtEpoch2)) + + for i := 0; i < len(clPoolIncentiveRecordsAtEpoch2); i++ { + if i == 2 { + s.ValidateIncentiveRecord(clPool.GetId(), expectedCoinsDistributedRegularGauge[0], newEmissionRateForClPool, clPoolIncentiveRecordsAtEpoch2[i]) + } else { + s.ValidateIncentiveRecord(clPool.GetId(), expectedCoinsDistributedDecCoins[0], emissionRateForPoolClPool, clPoolIncentiveRecordsAtEpoch2[i]) + } + + } + + // Step 4 + //let epoch 3 pass + // ******************** EPOCH 3 ********************* + s.Ctx = s.Ctx.WithBlockTime(s.Ctx.BlockTime().Add(epochInfo.Duration)) + s.App.EpochsKeeper.AfterEpochEnd(s.Ctx, epochInfo.GetIdentifier(), 3) + + // Validate that group gauge coins went down by 33_333_333uosmo + groupGauge, err = s.App.IncentivesKeeper.GetGaugeByID(s.Ctx, groupGaugeId) + s.Require().NoError(err) + + s.Require().Equal(groupGauge.Coins.Sub(groupGauge.DistributedCoins), sdk.Coins(nil)) + + s.ValidateDistributedGauge(internalGauge1, 3, expectedCoinsDistributedEpoch3) + s.ValidateDistributedGauge(internalGauge2, 3, expectedCoinsDistributedEpoch3) + + // Validate that we created incentive record after distributing gaugeId 2,3,5 + clPoolIncentiveRecordsAtEpoch3, err := s.App.ConcentratedLiquidityKeeper.GetAllIncentiveRecordsForPool(s.Ctx, clPool.GetId()) + s.Require().NoError(err) + + s.Require().Equal(7, len(clPoolIncentiveRecordsAtEpoch3)) + + for i := 0; i < len(clPoolIncentiveRecordsAtEpoch3); i++ { + if i == 2 { + s.ValidateIncentiveRecord(clPool.GetId(), expectedCoinsDistributedRegularGauge[0], newEmissionRateForClPool, clPoolIncentiveRecordsAtEpoch3[i]) + } else { + s.ValidateIncentiveRecord(clPool.GetId(), expectedCoinsDistributedDecCoins[0], emissionRateForPoolClPool, clPoolIncentiveRecordsAtEpoch3[i]) + } + + } + + // Step 5 + // let epoch 4 pass + // There should not be any distribution since all the tokens have been distributed + // ******************** EPOCH 4 ********************* + s.Ctx = s.Ctx.WithBlockTime(s.Ctx.BlockTime().Add(epochInfo.Duration)) + s.App.EpochsKeeper.AfterEpochEnd(s.Ctx, epochInfo.GetIdentifier(), 4) + + clPoolIncentiveRecordsAtEpoch4, err := s.App.ConcentratedLiquidityKeeper.GetAllIncentiveRecordsForPool(s.Ctx, clPool.GetId()) + s.Require().NoError(err) + + s.Require().Equal(7, len(clPoolIncentiveRecordsAtEpoch4)) +} diff --git a/x/incentives/keeper/gauge.go b/x/incentives/keeper/gauge.go index e9601ec9e3e..7de5acd3ae4 100644 --- a/x/incentives/keeper/gauge.go +++ b/x/incentives/keeper/gauge.go @@ -208,6 +208,111 @@ func (k Keeper) CreateGauge(ctx sdk.Context, isPerpetual bool, owner sdk.AccAddr return gauge.Id, nil } +// CreateGroupGauge creates a new gauge, that allocates rewards dynamically across its internal gauges based on the given splitting policy. +// Note: we should expect that the internal gauges consist of the gauges that are automatically created for each pool upon pool creation, as even non-perpetual +// external incentives would likely want to route through these. +func (k Keeper) CreateGroupGauge(ctx sdk.Context, coins sdk.Coins, numEpochPaidOver uint64, owner sdk.AccAddress, internalGaugeIds []uint64) (uint64, error) { + isPerp := false + if numEpochPaidOver == 1 { + isPerp = true + } + + // check that all the internalGaugeIds exist + if _, err := k.GetGaugeFromIDs(ctx, internalGaugeIds); err != nil { + return 0, fmt.Errorf("Invalid internalGaugeIds, please make sure all the internalGauge have been created.") + } + + nextGaugeId := k.GetLastGaugeID(ctx) + 1 + + gauge := types.Gauge{ + Id: nextGaugeId, + IsPerpetual: isPerp, + DistributeTo: lockuptypes.QueryCondition{ + LockQueryType: lockuptypes.ByGroup, + }, + Coins: coins, + StartTime: ctx.BlockTime(), + NumEpochsPaidOver: numEpochPaidOver, + } + + if err := k.bk.SendCoinsFromAccountToModule(ctx, owner, types.ModuleName, gauge.Coins); err != nil { + return 0, err + } + + if err := k.setGauge(ctx, &gauge); err != nil { + return 0, err + } + + newGroupGauge := types.GroupGauge{ + GroupGaugeId: nextGaugeId, + InternalIds: internalGaugeIds, + } + + k.SetGroupGauge(ctx, newGroupGauge) + k.SetLastGaugeID(ctx, gauge.Id) + + combinedKeys := combineKeys(types.KeyPrefixUpcomingGauges, getTimeKey(gauge.StartTime)) + activeOrUpcomingGauge := true + + if err := k.CreateGaugeRefKeys(ctx, &gauge, combinedKeys, activeOrUpcomingGauge); err != nil { + return 0, err + } + k.hooks.AfterCreateGauge(ctx, gauge.Id) + + return nextGaugeId, nil +} + +// AddToGaugeRewardsFromGauge transfer coins from groupGaugeId to InternalGaugeId. +// Prior to calling this function, we make sure that the internalGaugeId is linked with the associated groupGaugeId. +// Note: we donot have to bankSend for this gauge transfer because all the available incentive has already been bank sent +// when we create Group Gauge. Now we are just allocating funds from groupGauge to internalGauge. +func (k Keeper) AddToGaugeRewardsFromGauge(ctx sdk.Context, groupGaugeId uint64, coins sdk.Coins, internalGaugeId uint64) error { + // check if the internalGaugeId is present in groupGauge + groupGaugeObj, err := k.GetGroupGaugeById(ctx, groupGaugeId) + if err != nil { + return err + } + found := false + for _, val := range groupGaugeObj.InternalIds { + if val == internalGaugeId { + found = true + break + } + } + + if !found { + return fmt.Errorf("InternalGaugeId %d is not present in groupGauge: %v", internalGaugeId, groupGaugeObj.InternalIds) + } + + groupGauge, err := k.GetGaugeByID(ctx, groupGaugeId) + if err != nil { + return err + } + + internalGauge, err := k.GetGaugeByID(ctx, internalGaugeId) + if err != nil { + return err + } + + if internalGauge.IsFinishedGauge(ctx.BlockTime()) { + return errors.New("gauge is already completed") + } + + // check if there is sufficient funds in groupGauge to make the transfer + remainingCoins := groupGauge.Coins.Sub(groupGauge.DistributedCoins) + if remainingCoins.IsAllLT(coins) { + return fmt.Errorf("group gauge id: %d doesnot have enough tokens to transfer", groupGaugeId) + } + + internalGauge.Coins = internalGauge.Coins.Add(coins...) + err = k.setGauge(ctx, internalGauge) + if err != nil { + return err + } + + return nil +} + // AddToGaugeRewards adds coins to gauge. func (k Keeper) AddToGaugeRewards(ctx sdk.Context, owner sdk.AccAddress, coins sdk.Coins, gaugeID uint64) error { gauge, err := k.GetGaugeByID(ctx, gaugeID) @@ -230,6 +335,7 @@ func (k Keeper) AddToGaugeRewards(ctx sdk.Context, owner sdk.AccAddress, coins s if err != nil { return err } + k.hooks.AfterAddToGauge(ctx, gauge.Id) return nil } diff --git a/x/incentives/keeper/gauge_test.go b/x/incentives/keeper/gauge_test.go index 7243dc98122..c048990f1d3 100644 --- a/x/incentives/keeper/gauge_test.go +++ b/x/incentives/keeper/gauge_test.go @@ -582,3 +582,143 @@ func (s *KeeperTestSuite) TestCreateGauge_NoLockGauges() { }) } } + +func (s *KeeperTestSuite) TestCreateGroupGauge() { + coinsToAdd := sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100_000_000))) + tests := []struct { + name string + coins sdk.Coins + numEpochPaidOver uint64 + internalGaugeIds []uint64 + expectErr bool + }{ + { + name: "Happy case: created valid gauge", + coins: coinsToAdd, + numEpochPaidOver: 1, + internalGaugeIds: []uint64{2, 3, 4}, + expectErr: false, + }, + + { + name: "Error: Invalid InternalGauge Id", + coins: coinsToAdd, + numEpochPaidOver: 1, + internalGaugeIds: []uint64{2, 3, 4, 5}, + expectErr: true, + }, + { + name: "Error: owner doesnot have enough funds", + coins: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(200_000_000))), + numEpochPaidOver: 1, + internalGaugeIds: []uint64{2, 3, 4}, + expectErr: true, + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + s.SetupTest() + s.FundAcc(s.TestAccs[1], sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100_000_000)))) // 1,000 osmo + clPool := s.PrepareConcentratedPool() // gaugeid = 1 + + // create 3 internal Gauge + for i := 0; i <= 2; i++ { + s.CreateNoLockExternalGauges(clPool.GetId(), sdk.NewCoins(), s.TestAccs[1], uint64(1)) // gauge id = 2,3,4 + } + + groupGaugeId, err := s.App.IncentivesKeeper.CreateGroupGauge(s.Ctx, tc.coins, tc.numEpochPaidOver, s.TestAccs[1], tc.internalGaugeIds) // gauge id = 5 + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + + // check that the gauge has been create with right value + groupGauge, err := s.App.IncentivesKeeper.GetGaugeByID(s.Ctx, groupGaugeId) + s.Require().NoError(err) + + s.Require().Equal(groupGauge.Coins, tc.coins) + s.Require().Equal(groupGauge.NumEpochsPaidOver, tc.numEpochPaidOver) + s.Require().Equal(groupGauge.IsPerpetual, true) + s.Require().Equal(groupGauge.DistributeTo.LockQueryType, lockuptypes.ByGroup) + + // check that GroupGauge has been added to state + groupGaugeObj, err := s.App.IncentivesKeeper.GetGroupGaugeById(s.Ctx, groupGaugeId) + s.Require().NoError(err) + + s.Require().Equal(groupGaugeObj.InternalIds, tc.internalGaugeIds) + } + + }) + } +} + +func (s *KeeperTestSuite) TestAddToGaugeRewardsFromGauge() { + coinsToTransfer := sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100_000_000))) + tests := []struct { + name string + groupGaugeId uint64 + internalGaugeId uint64 + coinsToTransfer sdk.Coins + expectErr bool + }{ + { + name: "Happy case: Valid gaugeId with valid Internal GaugeId", + groupGaugeId: 3, + internalGaugeId: 2, + coinsToTransfer: coinsToTransfer, + expectErr: false, + }, + { + name: "Error: InternalGauge is not present in groupGauge", + groupGaugeId: 3, + internalGaugeId: 1, + coinsToTransfer: coinsToTransfer, + expectErr: true, + }, + { + name: "Error: Not enough tokens to transfer", + groupGaugeId: 3, + internalGaugeId: 2, + coinsToTransfer: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(200_000_000))), + expectErr: true, + }, + { + name: "Error: GroupGaugeId doesnot exist", + groupGaugeId: 5, + internalGaugeId: 2, + coinsToTransfer: coinsToTransfer, + expectErr: true, + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + s.SetupTest() + s.FundAcc(s.TestAccs[1], sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100_000_000)))) // 1,000 osmo + clPool := s.PrepareConcentratedPool() // gaugeid = 1 + + // create internal Gauge + internalGauge1 := s.CreateNoLockExternalGauges(clPool.GetId(), sdk.NewCoins(), s.TestAccs[1], uint64(1)) // gauge id = 2 + + // create group gauge + _, err := s.App.IncentivesKeeper.CreateGroupGauge(s.Ctx, sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100_000_000))), uint64(1), s.TestAccs[1], []uint64{internalGauge1}) // gauge id = 3 + s.Require().NoError(err) + + err = s.App.IncentivesKeeper.AddToGaugeRewardsFromGauge(s.Ctx, tc.groupGaugeId, tc.coinsToTransfer, tc.internalGaugeId) + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + + // check that the coins have been transferred + gauge, err := s.App.IncentivesKeeper.GetGaugeByID(s.Ctx, tc.groupGaugeId) + s.Require().NoError(err) + + s.Require().Equal(gauge.Coins, tc.coinsToTransfer) + + } + }) + } + +} diff --git a/x/incentives/keeper/hooks.go b/x/incentives/keeper/hooks.go index 7454824c295..0ef2bf1aa1a 100644 --- a/x/incentives/keeper/hooks.go +++ b/x/incentives/keeper/hooks.go @@ -18,6 +18,7 @@ func (k Keeper) BeforeEpochStart(ctx sdk.Context, epochIdentifier string, epochN // 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) @@ -34,6 +35,11 @@ func (k Keeper) AfterEpochEnd(ctx sdk.Context, epochIdentifier string, epochNumb ctx.EventManager().IncreaseCapacity(2e6) } + err := k.AllocateAcrossGauges(ctx) + if err != nil { + return err + } + // distribute due to epoch event gauges = k.GetActiveGauges(ctx) // only distribute to active gauges that are for native denoms @@ -48,7 +54,7 @@ func (k Keeper) AfterEpochEnd(ctx sdk.Context, epochIdentifier string, epochNumb } ctx.Logger().Info("AfterEpochEnd: distributing to gauges", "module", types.ModuleName, "numGauges", len(distrGauges), "height", ctx.BlockHeight()) - _, err := k.Distribute(ctx, distrGauges) + _, err = k.Distribute(ctx, distrGauges) if err != nil { return err } diff --git a/x/incentives/keeper/keeper_test.go b/x/incentives/keeper/keeper_test.go index 90fe6b6d12e..095474fce45 100644 --- a/x/incentives/keeper/keeper_test.go +++ b/x/incentives/keeper/keeper_test.go @@ -38,7 +38,6 @@ func (s *KeeperTestSuite) ValidateDistributedGauge(gaugeID uint64, expectedFille gauge, err := s.App.IncentivesKeeper.GetGaugeByID(s.Ctx, gaugeID) s.Require().NoError(err) s.Require().Equal(expectedFilledEpoch, gauge.FilledEpochs) - // Check that distributed coins is not updated s.Require().Equal(expectedDistributions, gauge.DistributedCoins) } diff --git a/x/incentives/keeper/store.go b/x/incentives/keeper/store.go index f789bbc1741..e458f6e00c5 100644 --- a/x/incentives/keeper/store.go +++ b/x/incentives/keeper/store.go @@ -2,8 +2,12 @@ package keeper import ( "encoding/json" + "errors" "fmt" + "github.com/gogo/protobuf/proto" + + "github.com/osmosis-labs/osmosis/osmoutils" "github.com/osmosis-labs/osmosis/v17/x/incentives/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -101,3 +105,41 @@ func (k Keeper) deleteGaugeIDForDenom(ctx sdk.Context, ID uint64, denom string) func (k Keeper) addGaugeIDForDenom(ctx sdk.Context, ID uint64, denom string) error { return k.addGaugeRefByKey(ctx, gaugeDenomStoreKey(denom), ID) } + +// SetGroupGauge sets groupGroup for a specific key. +// TODO: explore if we can store this better, this has GroupGaugeId in key and value +func (k Keeper) SetGroupGauge(ctx sdk.Context, groupGauge types.GroupGauge) { + store := ctx.KVStore(k.storeKey) + osmoutils.MustSet(store, types.KeyGroupGaugeForId(groupGauge.GroupGaugeId), &groupGauge) +} + +// GetAllGroupGauges gets all the groupGauges that is in state. +func (k Keeper) GetAllGroupGauges(ctx sdk.Context) ([]types.GroupGauge, error) { + return osmoutils.GatherValuesFromStorePrefix(ctx.KVStore(k.storeKey), types.KeyPrefix(types.GroupGaugePrefix), k.ParseGroupGaugeFromBz) +} + +func (k Keeper) ParseGroupGaugeFromBz(bz []byte) (groupGauge types.GroupGauge, err error) { + if len(bz) == 0 { + return types.GroupGauge{}, errors.New("group gauge not found") + } + err = proto.Unmarshal(bz, &groupGauge) + + return groupGauge, err +} + +// GetGroupGaugeById gets groupGauge struct for a given groupGaugeId. +func (k Keeper) GetGroupGaugeById(ctx sdk.Context, groupGaugeId uint64) (types.GroupGauge, error) { + store := ctx.KVStore(k.storeKey) + key := types.KeyGroupGaugeForId(groupGaugeId) + bz := store.Get(key) + if bz == nil { + return types.GroupGauge{}, nil + } + + var getGroupGauge types.GroupGauge + if err := proto.Unmarshal(bz, &getGroupGauge); err != nil { + return types.GroupGauge{}, nil + } + + return getGroupGauge, nil +} diff --git a/x/incentives/keeper/store_test.go b/x/incentives/keeper/store_test.go index be630ae0a73..b0c2cde73c4 100644 --- a/x/incentives/keeper/store_test.go +++ b/x/incentives/keeper/store_test.go @@ -1,6 +1,11 @@ package keeper_test -import "github.com/stretchr/testify/suite" +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/suite" + + "github.com/osmosis-labs/osmosis/v17/x/incentives/types" +) var _ = suite.TestingSuite(nil) @@ -33,3 +38,45 @@ func (s *KeeperTestSuite) TestGaugeReferencesManagement() { gaugeRefs3 := s.App.IncentivesKeeper.GetGaugeRefs(s.Ctx, key2) s.Require().Equal(len(gaugeRefs3), 2) } + +func (s *KeeperTestSuite) TestGetGroupGaugeById() { + tests := map[string]struct { + groupGaugeId uint64 + expectedRecord types.GroupGauge + }{ + "Valid record": { + groupGaugeId: uint64(5), + expectedRecord: types.GroupGauge{ + GroupGaugeId: uint64(5), + InternalIds: []uint64{2, 3, 4}, + }, + }, + + "InValid record": { + groupGaugeId: uint64(6), + expectedRecord: types.GroupGauge{}, + }, + } + + for name, test := range tests { + s.Run(name, func() { + s.FundAcc(s.TestAccs[1], sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100_000_000)))) // 1,000 osmo + clPool := s.PrepareConcentratedPool() // gaugeid = 1 + + // create 3 internal Gauge + var internalGauges []uint64 + for i := 0; i <= 2; i++ { + internalGauge := s.CreateNoLockExternalGauges(clPool.GetId(), sdk.NewCoins(), s.TestAccs[1], uint64(1)) // gauge id = 2,3,4 + internalGauges = append(internalGauges, internalGauge) + } + + _, err := s.App.IncentivesKeeper.CreateGroupGauge(s.Ctx, sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100_000_000))), 1, s.TestAccs[1], internalGauges) // gauge id = 5 + s.Require().NoError(err) + + record, err := s.App.IncentivesKeeper.GetGroupGaugeById(s.Ctx, test.groupGaugeId) + s.Require().NoError(err) + + s.Require().Equal(test.expectedRecord, record) + }) + } +} diff --git a/x/incentives/types/gauge.pb.go b/x/incentives/types/gauge.pb.go index c99d323c235..9a307b98c0a 100644 --- a/x/incentives/types/gauge.pb.go +++ b/x/incentives/types/gauge.pb.go @@ -149,6 +149,61 @@ func (m *Gauge) GetDistributedCoins() github_com_cosmos_cosmos_sdk_types.Coins { return nil } +// Gauge is an object that stores GroupGaugeId as well as internalGaugeIds. We +// linked these two together so that we can distribute tokens from groupGauge to +// internalGauges. +type GroupGauge struct { + GroupGaugeId uint64 `protobuf:"varint,1,opt,name=group_gauge_id,json=groupGaugeId,proto3" json:"group_gauge_id,omitempty"` + InternalIds []uint64 `protobuf:"varint,2,rep,packed,name=internal_ids,json=internalIds,proto3" json:"internal_ids,omitempty"` +} + +func (m *GroupGauge) Reset() { *m = GroupGauge{} } +func (m *GroupGauge) String() string { return proto.CompactTextString(m) } +func (*GroupGauge) ProtoMessage() {} +func (*GroupGauge) Descriptor() ([]byte, []int) { + return fileDescriptor_c0304e2bb0159901, []int{1} +} +func (m *GroupGauge) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GroupGauge) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GroupGauge.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 *GroupGauge) XXX_Merge(src proto.Message) { + xxx_messageInfo_GroupGauge.Merge(m, src) +} +func (m *GroupGauge) XXX_Size() int { + return m.Size() +} +func (m *GroupGauge) XXX_DiscardUnknown() { + xxx_messageInfo_GroupGauge.DiscardUnknown(m) +} + +var xxx_messageInfo_GroupGauge proto.InternalMessageInfo + +func (m *GroupGauge) GetGroupGaugeId() uint64 { + if m != nil { + return m.GroupGaugeId + } + return 0 +} + +func (m *GroupGauge) GetInternalIds() []uint64 { + if m != nil { + return m.InternalIds + } + return nil +} + type LockableDurationsInfo struct { // List of incentivised durations that gauges will pay out to LockableDurations []time.Duration `protobuf:"bytes,1,rep,name=lockable_durations,json=lockableDurations,proto3,stdduration" json:"lockable_durations" yaml:"lockable_durations"` @@ -158,7 +213,7 @@ func (m *LockableDurationsInfo) Reset() { *m = LockableDurationsInfo{} } func (m *LockableDurationsInfo) String() string { return proto.CompactTextString(m) } func (*LockableDurationsInfo) ProtoMessage() {} func (*LockableDurationsInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_c0304e2bb0159901, []int{1} + return fileDescriptor_c0304e2bb0159901, []int{2} } func (m *LockableDurationsInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -196,48 +251,52 @@ func (m *LockableDurationsInfo) GetLockableDurations() []time.Duration { func init() { proto.RegisterType((*Gauge)(nil), "osmosis.incentives.Gauge") + proto.RegisterType((*GroupGauge)(nil), "osmosis.incentives.GroupGauge") proto.RegisterType((*LockableDurationsInfo)(nil), "osmosis.incentives.LockableDurationsInfo") } func init() { proto.RegisterFile("osmosis/incentives/gauge.proto", fileDescriptor_c0304e2bb0159901) } var fileDescriptor_c0304e2bb0159901 = []byte{ - // 546 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x93, 0xcf, 0x6e, 0xd3, 0x30, - 0x1c, 0xc7, 0x9b, 0xad, 0x1d, 0xc3, 0xed, 0x10, 0xb5, 0x86, 0x94, 0x56, 0x22, 0x2d, 0x45, 0x48, - 0xbd, 0xcc, 0xa6, 0x43, 0x02, 0x89, 0x63, 0x07, 0x42, 0x93, 0x90, 0x28, 0xd5, 0x0e, 0x88, 0x4b, - 0xe4, 0x24, 0x6e, 0x66, 0x35, 0xc9, 0x2f, 0x8a, 0x9d, 0x6a, 0x7d, 0x03, 0x8e, 0x13, 0x27, 0x9e, - 0x81, 0x27, 0xd9, 0x71, 0x47, 0x4e, 0x1b, 0x6a, 0xdf, 0x80, 0x27, 0x40, 0xb1, 0x13, 0xb5, 0x2a, - 0x57, 0x4e, 0x8e, 0x7f, 0xdf, 0xdf, 0xbf, 0xef, 0x47, 0x0e, 0x72, 0x40, 0xc6, 0x20, 0x85, 0xa4, - 0x22, 0xf1, 0x79, 0xa2, 0xc4, 0x82, 0x4b, 0x1a, 0xb2, 0x3c, 0xe4, 0x24, 0xcd, 0x40, 0x01, 0xc6, - 0xa5, 0x4e, 0x36, 0x7a, 0xf7, 0x38, 0x84, 0x10, 0xb4, 0x4c, 0x8b, 0x2f, 0x93, 0xd9, 0x75, 0x42, - 0x80, 0x30, 0xe2, 0x54, 0xdf, 0xbc, 0x7c, 0x46, 0x83, 0x3c, 0x63, 0x4a, 0x40, 0x52, 0xea, 0xbd, - 0x5d, 0x5d, 0x89, 0x98, 0x4b, 0xc5, 0xe2, 0xb4, 0x6a, 0xe0, 0xeb, 0x59, 0xd4, 0x63, 0x92, 0xd3, - 0xc5, 0xc8, 0xe3, 0x8a, 0x8d, 0xa8, 0x0f, 0xa2, 0x6a, 0xd0, 0xa9, 0x56, 0x8d, 0xc0, 0x9f, 0xe7, - 0xa9, 0x3e, 0x8c, 0x34, 0xf8, 0x5e, 0x47, 0x8d, 0x0f, 0xc5, 0xd6, 0xf8, 0x11, 0xda, 0x13, 0x81, - 0x6d, 0xf5, 0xad, 0x61, 0x7d, 0xba, 0x27, 0x02, 0xfc, 0x0c, 0xb5, 0x84, 0x74, 0x53, 0x9e, 0xa5, - 0x5c, 0xe5, 0x2c, 0xb2, 0xf7, 0xfa, 0xd6, 0xf0, 0x70, 0xda, 0x14, 0x72, 0x52, 0x85, 0xf0, 0x39, - 0x3a, 0x0a, 0x84, 0x54, 0x99, 0xf0, 0x72, 0xc5, 0x5d, 0x05, 0xf6, 0x7e, 0xdf, 0x1a, 0x36, 0x4f, - 0x1d, 0x52, 0x59, 0x37, 0xf3, 0xc8, 0xe7, 0x9c, 0x67, 0xcb, 0x33, 0x48, 0x02, 0x51, 0xb8, 0x1a, - 0xd7, 0x6f, 0xee, 0x7a, 0xb5, 0x69, 0x6b, 0x53, 0x7a, 0x01, 0x98, 0xa1, 0x46, 0xb1, 0xb0, 0xb4, - 0xeb, 0xfd, 0xfd, 0x61, 0xf3, 0xb4, 0x43, 0x8c, 0x25, 0x52, 0x58, 0x22, 0xa5, 0x25, 0x72, 0x06, - 0x22, 0x19, 0xbf, 0x2c, 0xaa, 0x7f, 0xde, 0xf7, 0x86, 0xa1, 0x50, 0x97, 0xb9, 0x47, 0x7c, 0x88, - 0x69, 0xe9, 0xdf, 0x1c, 0x27, 0x32, 0x98, 0x53, 0xb5, 0x4c, 0xb9, 0xd4, 0x05, 0x72, 0x6a, 0x3a, - 0xe3, 0x2f, 0x08, 0x49, 0xc5, 0x32, 0xe5, 0x16, 0xf8, 0xec, 0x86, 0x5e, 0xb5, 0x4b, 0x0c, 0x5b, - 0x52, 0xb1, 0x25, 0x17, 0x15, 0xdb, 0xf1, 0xd3, 0x62, 0xd0, 0x9f, 0xbb, 0x5e, 0x7b, 0xc9, 0xe2, - 0xe8, 0xed, 0x60, 0x53, 0x3b, 0xb8, 0xbe, 0xef, 0x59, 0xd3, 0x87, 0x3a, 0x50, 0xa4, 0x63, 0x8a, - 0x8e, 0x93, 0x3c, 0x76, 0x79, 0x0a, 0xfe, 0xa5, 0x74, 0x53, 0x26, 0x02, 0x17, 0x16, 0x3c, 0xb3, - 0x0f, 0x34, 0xcc, 0x76, 0x92, 0xc7, 0xef, 0xb5, 0x34, 0x61, 0x22, 0xf8, 0xb4, 0xe0, 0x19, 0x7e, - 0x8e, 0x8e, 0x66, 0x22, 0x8a, 0x78, 0x50, 0xd6, 0xd8, 0x0f, 0x74, 0x66, 0xcb, 0x04, 0x4d, 0x32, - 0xbe, 0x42, 0xed, 0x0d, 0xa2, 0xc0, 0x35, 0x78, 0x0e, 0xff, 0x3f, 0x9e, 0xc7, 0x5b, 0x53, 0x74, - 0x64, 0xf0, 0xcd, 0x42, 0x4f, 0x3e, 0x82, 0x3f, 0x67, 0x5e, 0xc4, 0xdf, 0x95, 0x6f, 0x51, 0x9e, - 0x27, 0x33, 0xc0, 0x80, 0x70, 0x54, 0x0a, 0x6e, 0xf5, 0x4a, 0xa5, 0x6d, 0x95, 0x4b, 0xed, 0xb2, - 0xac, 0x6a, 0xc7, 0x2f, 0x4a, 0x94, 0x1d, 0x83, 0xf2, 0xdf, 0x16, 0x83, 0x1f, 0x05, 0xd2, 0x76, - 0xb4, 0x3b, 0x74, 0x3c, 0xb9, 0x59, 0x39, 0xd6, 0xed, 0xca, 0xb1, 0x7e, 0xaf, 0x1c, 0xeb, 0x7a, - 0xed, 0xd4, 0x6e, 0xd7, 0x4e, 0xed, 0xd7, 0xda, 0xa9, 0x7d, 0x7d, 0xbd, 0x65, 0xb0, 0x7c, 0x6f, - 0x27, 0x11, 0xf3, 0x64, 0x75, 0xa1, 0x8b, 0xd1, 0x1b, 0x7a, 0xb5, 0xfd, 0x77, 0x6a, 0xd3, 0xde, - 0x81, 0x5e, 0xef, 0xd5, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x2c, 0xc2, 0x67, 0xb9, 0xc0, 0x03, - 0x00, 0x00, + // 593 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x53, 0xcf, 0x6e, 0xd3, 0x30, + 0x1c, 0x6e, 0xba, 0x6e, 0x0c, 0xb7, 0x9b, 0xa8, 0x35, 0xa4, 0x6c, 0x12, 0x69, 0x09, 0x20, 0xe5, + 0x32, 0x9b, 0x0d, 0x09, 0x24, 0x8e, 0x1d, 0x68, 0xaa, 0x84, 0xc4, 0x88, 0x86, 0x84, 0xb8, 0x44, + 0x4e, 0xec, 0x65, 0xd6, 0x92, 0x38, 0x8a, 0x9d, 0x6a, 0x7d, 0x03, 0x8e, 0x13, 0x27, 0x9e, 0x81, + 0x27, 0xd9, 0x71, 0x47, 0x4e, 0x1b, 0x6a, 0xdf, 0x80, 0x27, 0x40, 0xb1, 0x93, 0xb5, 0x2a, 0x57, + 0x4e, 0xa9, 0x7f, 0xdf, 0xef, 0xdf, 0xf7, 0xfd, 0xbe, 0x02, 0x47, 0xc8, 0x54, 0x48, 0x2e, 0x31, + 0xcf, 0x22, 0x96, 0x29, 0x3e, 0x61, 0x12, 0xc7, 0xa4, 0x8c, 0x19, 0xca, 0x0b, 0xa1, 0x04, 0x84, + 0x35, 0x8e, 0x16, 0xf8, 0xde, 0x4e, 0x2c, 0x62, 0xa1, 0x61, 0x5c, 0xfd, 0x32, 0x99, 0x7b, 0x4e, + 0x2c, 0x44, 0x9c, 0x30, 0xac, 0x5f, 0x61, 0x79, 0x86, 0x69, 0x59, 0x10, 0xc5, 0x45, 0x56, 0xe3, + 0x83, 0x55, 0x5c, 0xf1, 0x94, 0x49, 0x45, 0xd2, 0xbc, 0x69, 0x10, 0xe9, 0x59, 0x38, 0x24, 0x92, + 0xe1, 0xc9, 0x41, 0xc8, 0x14, 0x39, 0xc0, 0x91, 0xe0, 0x4d, 0x83, 0xdd, 0x66, 0xd5, 0x44, 0x44, + 0x17, 0x65, 0xae, 0x3f, 0x06, 0x72, 0xbf, 0x77, 0xc0, 0xfa, 0x71, 0xb5, 0x35, 0xdc, 0x06, 0x6d, + 0x4e, 0x6d, 0x6b, 0x68, 0x79, 0x1d, 0xbf, 0xcd, 0x29, 0x7c, 0x0a, 0x7a, 0x5c, 0x06, 0x39, 0x2b, + 0x72, 0xa6, 0x4a, 0x92, 0xd8, 0xed, 0xa1, 0xe5, 0x6d, 0xfa, 0x5d, 0x2e, 0x4f, 0x9a, 0x10, 0x1c, + 0x83, 0x2d, 0xca, 0xa5, 0x2a, 0x78, 0x58, 0x2a, 0x16, 0x28, 0x61, 0xaf, 0x0d, 0x2d, 0xaf, 0x7b, + 0xe8, 0xa0, 0x86, 0xba, 0x99, 0x87, 0x3e, 0x95, 0xac, 0x98, 0x1e, 0x89, 0x8c, 0xf2, 0x8a, 0xd5, + 0xa8, 0x73, 0x7d, 0x3b, 0x68, 0xf9, 0xbd, 0x45, 0xe9, 0xa9, 0x80, 0x04, 0xac, 0x57, 0x0b, 0x4b, + 0xbb, 0x33, 0x5c, 0xf3, 0xba, 0x87, 0xbb, 0xc8, 0x50, 0x42, 0x15, 0x25, 0x54, 0x53, 0x42, 0x47, + 0x82, 0x67, 0xa3, 0x97, 0x55, 0xf5, 0xcf, 0xbb, 0x81, 0x17, 0x73, 0x75, 0x5e, 0x86, 0x28, 0x12, + 0x29, 0xae, 0xf9, 0x9b, 0xcf, 0xbe, 0xa4, 0x17, 0x58, 0x4d, 0x73, 0x26, 0x75, 0x81, 0xf4, 0x4d, + 0x67, 0xf8, 0x05, 0x00, 0xa9, 0x48, 0xa1, 0x82, 0x4a, 0x3e, 0x7b, 0x5d, 0xaf, 0xba, 0x87, 0x8c, + 0xb6, 0xa8, 0xd1, 0x16, 0x9d, 0x36, 0xda, 0x8e, 0x9e, 0x54, 0x83, 0xfe, 0xdc, 0x0e, 0xfa, 0x53, + 0x92, 0x26, 0x6f, 0xdd, 0x45, 0xad, 0x7b, 0x75, 0x37, 0xb0, 0xfc, 0x87, 0x3a, 0x50, 0xa5, 0x43, + 0x0c, 0x76, 0xb2, 0x32, 0x0d, 0x58, 0x2e, 0xa2, 0x73, 0x19, 0xe4, 0x84, 0xd3, 0x40, 0x4c, 0x58, + 0x61, 0x6f, 0x68, 0x31, 0xfb, 0x59, 0x99, 0xbe, 0xd7, 0xd0, 0x09, 0xe1, 0xf4, 0xe3, 0x84, 0x15, + 0xf0, 0x19, 0xd8, 0x3a, 0xe3, 0x49, 0xc2, 0x68, 0x5d, 0x63, 0x3f, 0xd0, 0x99, 0x3d, 0x13, 0x34, + 0xc9, 0xf0, 0x12, 0xf4, 0x17, 0x12, 0xd1, 0xc0, 0xc8, 0xb3, 0xf9, 0xff, 0xe5, 0x79, 0xb4, 0x34, + 0x45, 0x47, 0xdc, 0xcf, 0x00, 0x1c, 0x17, 0xa2, 0xcc, 0x8d, 0x31, 0x9e, 0x83, 0xed, 0xb8, 0x7a, + 0x05, 0xda, 0xdd, 0xc1, 0xbd, 0x49, 0x7a, 0xf1, 0x7d, 0xce, 0xd8, 0xd8, 0x25, 0x53, 0xac, 0xc8, + 0x48, 0x12, 0x70, 0x2a, 0xed, 0xf6, 0x70, 0xcd, 0xeb, 0xf8, 0xdd, 0x26, 0x36, 0xa6, 0xd2, 0xfd, + 0x66, 0x81, 0xc7, 0x1f, 0x44, 0x74, 0x41, 0xc2, 0x84, 0xbd, 0xab, 0x2d, 0x2e, 0xc7, 0xd9, 0x99, + 0x80, 0x02, 0xc0, 0xa4, 0x06, 0x82, 0xc6, 0xfc, 0xd2, 0xb6, 0x6a, 0xae, 0xab, 0x27, 0x6a, 0x6a, + 0x47, 0x2f, 0xea, 0x0b, 0xed, 0x9a, 0x0b, 0xfd, 0xdb, 0xc2, 0xfd, 0x51, 0x5d, 0xaa, 0x9f, 0xac, + 0x0e, 0x1d, 0x9d, 0x5c, 0xcf, 0x1c, 0xeb, 0x66, 0xe6, 0x58, 0xbf, 0x67, 0x8e, 0x75, 0x35, 0x77, + 0x5a, 0x37, 0x73, 0xa7, 0xf5, 0x6b, 0xee, 0xb4, 0xbe, 0xbe, 0x5e, 0xd2, 0xad, 0xb6, 0xf1, 0x7e, + 0x42, 0x42, 0xd9, 0x3c, 0xf0, 0xe4, 0xe0, 0x0d, 0xbe, 0x5c, 0xfe, 0xd3, 0x6b, 0x2d, 0xc3, 0x0d, + 0xbd, 0xde, 0xab, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x24, 0x31, 0x6f, 0xa8, 0x17, 0x04, 0x00, + 0x00, } func (m *Gauge) Marshal() (dAtA []byte, err error) { @@ -334,6 +393,52 @@ func (m *Gauge) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *GroupGauge) 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 *GroupGauge) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GroupGauge) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.InternalIds) > 0 { + dAtA4 := make([]byte, len(m.InternalIds)*10) + var j3 int + for _, num := range m.InternalIds { + for num >= 1<<7 { + dAtA4[j3] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j3++ + } + dAtA4[j3] = uint8(num) + j3++ + } + i -= j3 + copy(dAtA[i:], dAtA4[:j3]) + i = encodeVarintGauge(dAtA, i, uint64(j3)) + i-- + dAtA[i] = 0x12 + } + if m.GroupGaugeId != 0 { + i = encodeVarintGauge(dAtA, i, uint64(m.GroupGaugeId)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + func (m *LockableDurationsInfo) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -417,6 +522,25 @@ func (m *Gauge) Size() (n int) { return n } +func (m *GroupGauge) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.GroupGaugeId != 0 { + n += 1 + sovGauge(uint64(m.GroupGaugeId)) + } + if len(m.InternalIds) > 0 { + l = 0 + for _, e := range m.InternalIds { + l += sovGauge(uint64(e)) + } + n += 1 + sovGauge(uint64(l)) + l + } + return n +} + func (m *LockableDurationsInfo) Size() (n int) { if m == nil { return 0 @@ -699,6 +823,151 @@ func (m *Gauge) Unmarshal(dAtA []byte) error { } return nil } +func (m *GroupGauge) 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: GroupGauge: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GroupGauge: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field GroupGaugeId", wireType) + } + m.GroupGaugeId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGauge + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.GroupGaugeId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType == 0 { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGauge + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.InternalIds = append(m.InternalIds, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGauge + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return ErrInvalidLengthGauge + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return ErrInvalidLengthGauge + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + var count int + for _, integer := range dAtA[iNdEx:postIndex] { + if integer < 128 { + count++ + } + } + elementCount = count + if elementCount != 0 && len(m.InternalIds) == 0 { + m.InternalIds = make([]uint64, 0, elementCount) + } + for iNdEx < postIndex { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGauge + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.InternalIds = append(m.InternalIds, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field InternalIds", wireType) + } + 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 *LockableDurationsInfo) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/x/incentives/types/keys.go b/x/incentives/types/keys.go index c3bbf64d5e9..5654687c900 100644 --- a/x/incentives/types/keys.go +++ b/x/incentives/types/keys.go @@ -50,6 +50,8 @@ var ( NoLockInternalPrefix = "no-lock/i/" NoLockExternalPrefix = "no-lock/e/" + + GroupGaugePrefix = "group_gauge" ) func KeyPrefix(p string) []byte { @@ -65,3 +67,8 @@ func NoLockExternalGaugeDenom(poolId uint64) string { func NoLockInternalGaugeDenom(poolId uint64) string { return fmt.Sprintf("%s%d", NoLockInternalPrefix, poolId) } + +// KeyGroupGaugeForId returns key for a given groupGaugeId. +func KeyGroupGaugeForId(groupGaugeId uint64) []byte { + return []byte(fmt.Sprintf("%s%s%d%s", "group_gauge", "|", groupGaugeId, "|")) +} diff --git a/x/lockup/types/lock.pb.go b/x/lockup/types/lock.pb.go index a6dd473677d..81ec7791b87 100644 --- a/x/lockup/types/lock.pb.go +++ b/x/lockup/types/lock.pb.go @@ -37,18 +37,21 @@ const ( ByDuration LockQueryType = 0 ByTime LockQueryType = 1 NoLock LockQueryType = 2 + ByGroup LockQueryType = 3 ) var LockQueryType_name = map[int32]string{ 0: "ByDuration", 1: "ByTime", 2: "NoLock", + 3: "ByGroup", } var LockQueryType_value = map[string]int32{ "ByDuration": 0, "ByTime": 1, "NoLock": 2, + "ByGroup": 3, } func (x LockQueryType) String() string { @@ -331,48 +334,49 @@ func init() { func init() { proto.RegisterFile("osmosis/lockup/lock.proto", fileDescriptor_7e9d7527a237b489) } var fileDescriptor_7e9d7527a237b489 = []byte{ - // 649 bytes of a gzipped FileDescriptorProto + // 659 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x54, 0x3f, 0x6f, 0xd3, 0x40, - 0x1c, 0x8d, 0xf3, 0xa7, 0xb4, 0x57, 0x9a, 0x46, 0xa7, 0x22, 0xd2, 0x00, 0x76, 0xe4, 0x01, 0x45, - 0xa8, 0xb5, 0x49, 0x19, 0x90, 0x90, 0x18, 0x70, 0xc3, 0x50, 0xa9, 0x42, 0x60, 0x2a, 0x86, 0x2e, - 0x96, 0xed, 0x3b, 0xdc, 0x53, 0x6d, 0x9f, 0xf1, 0xd9, 0x2d, 0xfe, 0x06, 0x8c, 0x1d, 0x41, 0x62, - 0x63, 0xe3, 0x5b, 0xb0, 0x75, 0xec, 0xc8, 0x94, 0xa2, 0x76, 0x63, 0xec, 0x27, 0x40, 0x77, 0x67, - 0x27, 0x69, 0x51, 0xa5, 0x0e, 0x30, 0xd9, 0x77, 0xef, 0xf7, 0x7b, 0xf7, 0xf3, 0x7b, 0xef, 0x0c, - 0x56, 0x29, 0x8b, 0x28, 0x23, 0xcc, 0x0c, 0xa9, 0xbf, 0x9f, 0x27, 0xe2, 0x61, 0x24, 0x29, 0xcd, - 0x28, 0x6c, 0x97, 0x90, 0x21, 0xa1, 0xde, 0x4a, 0x40, 0x03, 0x2a, 0x20, 0x93, 0xbf, 0xc9, 0xaa, - 0x9e, 0x1a, 0x50, 0x1a, 0x84, 0xd8, 0x14, 0x2b, 0x2f, 0x7f, 0x6f, 0xa2, 0x3c, 0x75, 0x33, 0x42, - 0xe3, 0x12, 0xd7, 0xae, 0xe2, 0x19, 0x89, 0x30, 0xcb, 0xdc, 0x28, 0xa9, 0x08, 0x7c, 0x71, 0x8e, - 0xe9, 0xb9, 0x0c, 0x9b, 0x07, 0x43, 0x0f, 0x67, 0xee, 0xd0, 0xf4, 0x29, 0x29, 0x09, 0xf4, 0x1f, - 0x0d, 0x00, 0x5e, 0xe3, 0x94, 0x50, 0xb4, 0x4d, 0xfd, 0x7d, 0xd8, 0x06, 0xf5, 0xad, 0x51, 0x57, - 0xe9, 0x2b, 0x83, 0xa6, 0x5d, 0xdf, 0x1a, 0xc1, 0x87, 0xa0, 0x45, 0x0f, 0x63, 0x9c, 0x76, 0xeb, - 0x7d, 0x65, 0xb0, 0x60, 0x75, 0x2e, 0xc6, 0xda, 0xed, 0xc2, 0x8d, 0xc2, 0x67, 0xba, 0xd8, 0xd6, - 0x6d, 0x09, 0xc3, 0x3d, 0x30, 0x5f, 0x4d, 0xd6, 0x6d, 0xf4, 0x95, 0xc1, 0xe2, 0xc6, 0xaa, 0x21, - 0x47, 0x33, 0xaa, 0xd1, 0x8c, 0x51, 0x59, 0x60, 0x0d, 0x8f, 0xc7, 0x5a, 0xed, 0xf7, 0x58, 0x83, - 0x55, 0xcb, 0x1a, 0x8d, 0x48, 0x86, 0xa3, 0x24, 0x2b, 0x2e, 0xc6, 0xda, 0xb2, 0xe4, 0xaf, 0x30, - 0xfd, 0xf3, 0xa9, 0xa6, 0xd8, 0x13, 0x76, 0x68, 0x83, 0x79, 0x1c, 0x23, 0x87, 0x7f, 0x67, 0xb7, - 0x29, 0x4e, 0xea, 0xfd, 0x75, 0xd2, 0x4e, 0x25, 0x82, 0x75, 0x8f, 0x1f, 0x35, 0x25, 0xad, 0x3a, - 0xf5, 0x23, 0x4e, 0x7a, 0x0b, 0xc7, 0x88, 0x97, 0x42, 0x17, 0xb4, 0xb8, 0x24, 0xac, 0xdb, 0xea, - 0x37, 0xc4, 0xe8, 0x52, 0x34, 0x83, 0x8b, 0x66, 0x94, 0xa2, 0x19, 0x9b, 0x94, 0xc4, 0xd6, 0x63, - 0xce, 0xf7, 0xfd, 0x54, 0x1b, 0x04, 0x24, 0xdb, 0xcb, 0x3d, 0xc3, 0xa7, 0x91, 0x59, 0x2a, 0x2c, - 0x1f, 0xeb, 0x0c, 0xed, 0x9b, 0x59, 0x91, 0x60, 0x26, 0x1a, 0x98, 0x2d, 0x99, 0xe1, 0x2e, 0xb8, - 0x9b, 0xe2, 0x43, 0x37, 0x45, 0x4e, 0x8a, 0x7d, 0x4c, 0x0e, 0x70, 0xea, 0xb8, 0x08, 0xa5, 0x98, - 0xb1, 0xee, 0x9c, 0x90, 0x56, 0xbf, 0x18, 0x6b, 0xaa, 0x9c, 0xf2, 0x9a, 0x42, 0xdd, 0xbe, 0x23, - 0x11, 0xbb, 0x04, 0x5e, 0x94, 0xfb, 0x5f, 0xea, 0xa0, 0xfd, 0x26, 0xc7, 0x69, 0xb1, 0x49, 0x63, - 0x44, 0x84, 0x4a, 0x2f, 0xc1, 0x32, 0xcf, 0x95, 0xf3, 0x81, 0x6f, 0x3b, 0x7c, 0x1e, 0x61, 0x6a, - 0x7b, 0xe3, 0x81, 0x71, 0x39, 0x77, 0x06, 0xb7, 0x5d, 0x34, 0xef, 0x14, 0x09, 0xb6, 0x97, 0xc2, - 0xd9, 0x25, 0x5c, 0x01, 0x2d, 0x84, 0x63, 0x1a, 0x49, 0xfb, 0x6d, 0xb9, 0xe0, 0x16, 0xdc, 0xdc, - 0xec, 0x2b, 0x0e, 0x5c, 0x67, 0xeb, 0x3b, 0xb0, 0x30, 0x89, 0xee, 0x0d, 0x7c, 0xbd, 0x5f, 0xb2, - 0x76, 0x24, 0xeb, 0xa4, 0x55, 0x1a, 0x3b, 0xa5, 0xd2, 0xbf, 0xd6, 0xc1, 0xd2, 0xdb, 0x22, 0xce, - 0xf6, 0x70, 0x46, 0x7c, 0x11, 0xf1, 0x35, 0x00, 0xf3, 0x18, 0xe1, 0x34, 0x2c, 0x48, 0x1c, 0x38, - 0x42, 0x25, 0x82, 0xca, 0xc8, 0x77, 0xa6, 0x08, 0xaf, 0xdd, 0x42, 0x50, 0x03, 0x8b, 0x8c, 0xb7, - 0x3b, 0xb3, 0x3a, 0x00, 0xb1, 0x35, 0xaa, 0xc4, 0x98, 0xe4, 0xb1, 0xf1, 0x8f, 0xf2, 0x38, 0x7b, - 0x9b, 0x9a, 0xff, 0xf3, 0x36, 0x3d, 0x7a, 0x0e, 0x96, 0x2e, 0x05, 0x00, 0xb6, 0x01, 0xb0, 0x8a, - 0x8a, 0xbb, 0x53, 0x83, 0x00, 0xcc, 0x59, 0x05, 0x1f, 0xaa, 0xa3, 0xf0, 0xf7, 0x57, 0x94, 0x97, - 0x77, 0xea, 0xbd, 0xe6, 0xa7, 0x6f, 0x6a, 0xcd, 0xda, 0x3e, 0x3e, 0x53, 0x95, 0x93, 0x33, 0x55, - 0xf9, 0x75, 0xa6, 0x2a, 0x47, 0xe7, 0x6a, 0xed, 0xe4, 0x5c, 0xad, 0xfd, 0x3c, 0x57, 0x6b, 0xbb, - 0x1b, 0x33, 0x17, 0xa4, 0x4c, 0xdc, 0x7a, 0xe8, 0x7a, 0xac, 0x5a, 0x98, 0x07, 0xc3, 0xa7, 0xe6, - 0xc7, 0xea, 0xbf, 0x28, 0x2e, 0x8c, 0x37, 0x27, 0x3e, 0xee, 0xc9, 0x9f, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x9a, 0x18, 0xcb, 0x36, 0x05, 0x00, 0x00, + 0x1c, 0x8d, 0xf3, 0xa7, 0x7f, 0xae, 0x34, 0xb5, 0x4e, 0x45, 0xa4, 0x01, 0xec, 0xc8, 0x03, 0x8a, + 0x50, 0x6b, 0x93, 0x32, 0x20, 0xb1, 0xe1, 0x06, 0xa1, 0xa2, 0x0a, 0x81, 0xa9, 0x18, 0xba, 0x58, + 0x8e, 0xef, 0x48, 0x4f, 0x8d, 0x7d, 0xe6, 0xce, 0x6e, 0xf1, 0x37, 0x60, 0xec, 0x08, 0x12, 0x1b, + 0x1b, 0xdf, 0x82, 0xad, 0x63, 0x47, 0xa6, 0x14, 0xb5, 0x1b, 0x63, 0x3f, 0x01, 0xba, 0x3b, 0x3b, + 0x4d, 0x8b, 0x2a, 0x75, 0x80, 0xc9, 0xbe, 0x7b, 0xbf, 0xdf, 0xbb, 0x9f, 0xdf, 0x7b, 0x67, 0xb0, + 0x42, 0x79, 0x44, 0x39, 0xe1, 0xce, 0x88, 0x86, 0x7b, 0x59, 0x22, 0x1f, 0x76, 0xc2, 0x68, 0x4a, + 0x61, 0xb3, 0x80, 0x6c, 0x05, 0xb5, 0x97, 0x87, 0x74, 0x48, 0x25, 0xe4, 0x88, 0x37, 0x55, 0xd5, + 0x36, 0x86, 0x94, 0x0e, 0x47, 0xd8, 0x91, 0xab, 0x41, 0xf6, 0xde, 0x41, 0x19, 0x0b, 0x52, 0x42, + 0xe3, 0x02, 0x37, 0xaf, 0xe2, 0x29, 0x89, 0x30, 0x4f, 0x83, 0x28, 0x29, 0x09, 0x42, 0x79, 0x8e, + 0x33, 0x08, 0x38, 0x76, 0xf6, 0x7b, 0x03, 0x9c, 0x06, 0x3d, 0x27, 0xa4, 0xa4, 0x20, 0xb0, 0x7e, + 0xd4, 0x00, 0x78, 0x8d, 0x19, 0xa1, 0x68, 0x8b, 0x86, 0x7b, 0xb0, 0x09, 0xaa, 0x9b, 0xfd, 0x96, + 0xd6, 0xd1, 0xba, 0x75, 0xaf, 0xba, 0xd9, 0x87, 0x0f, 0x40, 0x83, 0x1e, 0xc4, 0x98, 0xb5, 0xaa, + 0x1d, 0xad, 0x3b, 0xef, 0xea, 0xe7, 0x63, 0xf3, 0x56, 0x1e, 0x44, 0xa3, 0xa7, 0x96, 0xdc, 0xb6, + 0x3c, 0x05, 0xc3, 0x5d, 0x30, 0x57, 0x4e, 0xd6, 0xaa, 0x75, 0xb4, 0xee, 0xc2, 0xfa, 0x8a, 0xad, + 0x46, 0xb3, 0xcb, 0xd1, 0xec, 0x7e, 0x51, 0xe0, 0xf6, 0x8e, 0xc6, 0x66, 0xe5, 0xf7, 0xd8, 0x84, + 0x65, 0xcb, 0x2a, 0x8d, 0x48, 0x8a, 0xa3, 0x24, 0xcd, 0xcf, 0xc7, 0xe6, 0x92, 0xe2, 0x2f, 0x31, + 0xeb, 0xf3, 0x89, 0xa9, 0x79, 0x13, 0x76, 0xe8, 0x81, 0x39, 0x1c, 0x23, 0x5f, 0x7c, 0x67, 0xab, + 0x2e, 0x4f, 0x6a, 0xff, 0x75, 0xd2, 0x76, 0x29, 0x82, 0x7b, 0x57, 0x1c, 0x75, 0x41, 0x5a, 0x76, + 0x5a, 0x87, 0x82, 0x74, 0x16, 0xc7, 0x48, 0x94, 0xc2, 0x00, 0x34, 0x84, 0x24, 0xbc, 0xd5, 0xe8, + 0xd4, 0xe4, 0xe8, 0x4a, 0x34, 0x5b, 0x88, 0x66, 0x17, 0xa2, 0xd9, 0x1b, 0x94, 0xc4, 0xee, 0x23, + 0xc1, 0xf7, 0xfd, 0xc4, 0xec, 0x0e, 0x49, 0xba, 0x9b, 0x0d, 0xec, 0x90, 0x46, 0x4e, 0xa1, 0xb0, + 0x7a, 0xac, 0x71, 0xb4, 0xe7, 0xa4, 0x79, 0x82, 0xb9, 0x6c, 0xe0, 0x9e, 0x62, 0x86, 0x3b, 0xe0, + 0x0e, 0xc3, 0x07, 0x01, 0x43, 0x3e, 0xc3, 0x21, 0x26, 0xfb, 0x98, 0xf9, 0x01, 0x42, 0x0c, 0x73, + 0xde, 0x9a, 0x91, 0xd2, 0x5a, 0xe7, 0x63, 0xd3, 0x50, 0x53, 0x5e, 0x53, 0x68, 0x79, 0xb7, 0x15, + 0xe2, 0x15, 0xc0, 0xb3, 0x62, 0xff, 0x4b, 0x15, 0x34, 0xdf, 0x64, 0x98, 0xe5, 0x1b, 0x34, 0x46, + 0x44, 0xaa, 0xf4, 0x1c, 0x2c, 0x89, 0x5c, 0xf9, 0x1f, 0xc4, 0xb6, 0x2f, 0xe6, 0x91, 0xa6, 0x36, + 0xd7, 0xef, 0xdb, 0x97, 0x73, 0x67, 0x0b, 0xdb, 0x65, 0xf3, 0x76, 0x9e, 0x60, 0x6f, 0x71, 0x34, + 0xbd, 0x84, 0xcb, 0xa0, 0x81, 0x70, 0x4c, 0x23, 0x65, 0xbf, 0xa7, 0x16, 0xc2, 0x82, 0x9b, 0x9b, + 0x7d, 0xc5, 0x81, 0xeb, 0x6c, 0x7d, 0x07, 0xe6, 0x27, 0xd1, 0xbd, 0x81, 0xaf, 0xf7, 0x0a, 0x56, + 0x5d, 0xb1, 0x4e, 0x5a, 0x95, 0xb1, 0x17, 0x54, 0xd6, 0xd7, 0x2a, 0x58, 0x7c, 0x9b, 0xc7, 0xe9, + 0x2e, 0x4e, 0x49, 0x28, 0x23, 0xbe, 0x0a, 0x60, 0x16, 0x23, 0xcc, 0x46, 0x39, 0x89, 0x87, 0xbe, + 0x54, 0x89, 0xa0, 0x22, 0xf2, 0xfa, 0x05, 0x22, 0x6a, 0x37, 0x11, 0x34, 0xc1, 0x02, 0x17, 0xed, + 0xfe, 0xb4, 0x0e, 0x40, 0x6e, 0xf5, 0x4b, 0x31, 0x26, 0x79, 0xac, 0xfd, 0xa3, 0x3c, 0x4e, 0xdf, + 0xa6, 0xfa, 0xff, 0xbc, 0x4d, 0x0f, 0x5f, 0x82, 0xc5, 0x4b, 0x01, 0x80, 0x4d, 0x00, 0xdc, 0xbc, + 0xe4, 0xd6, 0x2b, 0x10, 0x80, 0x19, 0x37, 0x17, 0x43, 0xe9, 0x9a, 0x78, 0x7f, 0x45, 0x45, 0xb9, + 0x5e, 0x85, 0x0b, 0x60, 0xd6, 0xcd, 0x5f, 0x30, 0x9a, 0x25, 0x7a, 0xad, 0x5d, 0xff, 0xf4, 0xcd, + 0xa8, 0xb8, 0x5b, 0x47, 0xa7, 0x86, 0x76, 0x7c, 0x6a, 0x68, 0xbf, 0x4e, 0x0d, 0xed, 0xf0, 0xcc, + 0xa8, 0x1c, 0x9f, 0x19, 0x95, 0x9f, 0x67, 0x46, 0x65, 0x67, 0x7d, 0xea, 0xb6, 0x14, 0xf1, 0x5b, + 0x1b, 0x05, 0x03, 0x5e, 0x2e, 0x9c, 0xfd, 0xde, 0x13, 0xe7, 0x63, 0xf9, 0x93, 0x94, 0xb7, 0x67, + 0x30, 0x23, 0xbf, 0xf4, 0xf1, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc9, 0x87, 0x80, 0xb1, 0x43, + 0x05, 0x00, 0x00, } func (m *PeriodLock) Marshal() (dAtA []byte, err error) { From 57a4b1a90dbb67871fd2b46be4f546ce57256151 Mon Sep 17 00:00:00 2001 From: devbot-wizard <141283918+devbot-wizard@users.noreply.github.com> Date: Wed, 16 Aug 2023 19:29:21 +0000 Subject: [PATCH 2/7] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d82a2341046..60153e2fef1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -91,6 +91,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * [#5948](https://github.com/osmosis-labs/osmosis/pull/5948) Parameterizing Pool Type Information in Protorev * [#6001](https://github.com/osmosis-labs/osmosis/pull/6001) feat: improve set-env CLI cmd * [#6012](https://github.com/osmosis-labs/osmosis/pull/6012) chore: add autocomplete to makefile +* [#6085](https://github.com/osmosis-labs/osmosis/pull/6085) (v18: feat) Volume-Split, setup gauges to split evenly ### Minor improvements & Bug Fixes From 7b330baa6f424cf0184eedaa59f70964930d76a4 Mon Sep 17 00:00:00 2001 From: stackman27 Date: Thu, 17 Aug 2023 20:18:58 +0000 Subject: [PATCH 3/7] halfway done refactoring test --- proto/osmosis/incentives/gauge.proto | 10 + x/incentives/keeper/distribute.go | 43 +++- x/incentives/keeper/distribute_test.go | 307 ++++++++++--------------- x/incentives/keeper/gauge.go | 23 +- x/incentives/keeper/gauge_test.go | 21 +- x/incentives/keeper/keeper_test.go | 10 +- x/incentives/types/gauge.pb.go | 152 ++++++++---- 7 files changed, 317 insertions(+), 249 deletions(-) diff --git a/proto/osmosis/incentives/gauge.proto b/proto/osmosis/incentives/gauge.proto index f18beaea1ca..2706d8f345c 100644 --- a/proto/osmosis/incentives/gauge.proto +++ b/proto/osmosis/incentives/gauge.proto @@ -50,12 +50,22 @@ message Gauge { ]; } +// SplittingPolicy determines the way we want to split incentives in groupGauges +enum SplittingPolicy { + option (gogoproto.goproto_enum_prefix) = false; + + Volume = 0; + Liquidity = 1; + Evenly = 2; +} + // Gauge is an object that stores GroupGaugeId as well as internalGaugeIds. We // linked these two together so that we can distribute tokens from groupGauge to // internalGauges. message GroupGauge { uint64 group_gauge_id = 1; repeated uint64 internal_ids = 2; + SplittingPolicy splitting_policy = 3; } message LockableDurationsInfo { diff --git a/x/incentives/keeper/distribute.go b/x/incentives/keeper/distribute.go index 19daa376757..c4f910c7a59 100644 --- a/x/incentives/keeper/distribute.go +++ b/x/incentives/keeper/distribute.go @@ -268,7 +268,7 @@ func (k Keeper) distributeSyntheticInternal( // AllocateAcrossGauges gets all the active groupGauges and distributes tokens evenly based on the internalGauges set for that // groupGauge. After each iteration we update the groupGauge by modifying filledEpoch and distributed coins. -// TODO: Replace even eplit by volume split once its implemented. +// TODO: Replace even split by volume split once its implemented. func (k Keeper) AllocateAcrossGauges(ctx sdk.Context) error { currTime := ctx.BlockTime() @@ -284,14 +284,14 @@ func (k Keeper) AllocateAcrossGauges(ctx sdk.Context) error { } // only allow distribution if the GroupGauge is Active - if currTime.After(gauge.StartTime) || currTime.Equal(gauge.StartTime) && (gauge.IsPerpetual || gauge.FilledEpochs < gauge.NumEpochsPaidOver) { - // TODO: replace the calculation below by volume split. - remainCoins := gauge.Coins.Sub(gauge.DistributedCoins) - amountToDistributeThisEpoch := remainCoins[0].Amount.Quo(sdk.NewInt(int64(gauge.NumEpochsPaidOver - (gauge.FilledEpochs)))) - amountToDistributePerInternalGauge := amountToDistributeThisEpoch.Quo(sdk.NewInt(int64(len(groupGauge.InternalIds)))) + if !currTime.Before(gauge.StartTime) && (gauge.IsPerpetual || gauge.FilledEpochs < gauge.NumEpochsPaidOver) { + coinsToDistributePerInternalGauge, coinsToDistributeThisEpoch := k.CalcSplitPolicyCoins(ctx, groupGauge.SplittingPolicy, gauge, groupGauge) + if coinsToDistributePerInternalGauge == nil || coinsToDistributeThisEpoch == nil { + return fmt.Errorf("GroupGauge id %d doesnot have enought coins to distribute.", groupGauge.GroupGaugeId) + } for _, internalGaugeId := range groupGauge.InternalIds { - err = k.AddToGaugeRewardsFromGauge(ctx, groupGauge.GroupGaugeId, sdk.NewCoins(sdk.NewCoin(remainCoins[0].Denom, amountToDistributePerInternalGauge)), internalGaugeId) + err = k.AddToGaugeRewardsFromGauge(ctx, groupGauge.GroupGaugeId, coinsToDistributePerInternalGauge, internalGaugeId) if err != nil { return err } @@ -299,13 +299,34 @@ func (k Keeper) AllocateAcrossGauges(ctx sdk.Context) error { // we distribute tokens from groupGauge to internal gauge therefore update groupGauge fields // updates filledEpoch and distributedCoins - k.updateGaugePostDistribute(ctx, *gauge, sdk.NewCoins(sdk.NewCoin(gauge.Coins[0].Denom, amountToDistributeThisEpoch))) + k.updateGaugePostDistribute(ctx, *gauge, coinsToDistributeThisEpoch) } } return nil } +// CalcSplitPolicyCoins calculates tokens to split given a policy and groupGauge. +func (k Keeper) CalcSplitPolicyCoins(ctx sdk.Context, policy types.SplittingPolicy, groupGauge *types.Gauge, groupGaugeObj types.GroupGauge) (sdk.Coins, sdk.Coins) { + // TODO: add volume split policy + if policy == types.Evenly { + remainCoins := groupGauge.Coins.Sub(groupGauge.DistributedCoins) + + var coinsDistPerInternalGauge, coinsDistThisEpoch sdk.Coins + for _, coin := range remainCoins { + amountToDistributeThisEpoch := coin.Amount.Quo(sdk.NewIntFromUint64(groupGauge.NumEpochsPaidOver - groupGauge.FilledEpochs)) + amountToDistributePerInternalGauge := amountToDistributeThisEpoch.Quo(sdk.NewInt(int64(len(groupGaugeObj.InternalIds)))) + + coinsDistThisEpoch = coinsDistThisEpoch.Add(sdk.NewCoin(coin.Denom, amountToDistributeThisEpoch)) + coinsDistPerInternalGauge = coinsDistPerInternalGauge.Add(sdk.NewCoin(coin.Denom, amountToDistributePerInternalGauge)) + } + + return coinsDistPerInternalGauge, coinsDistThisEpoch + } + + return nil, nil +} + // distributeInternal runs the distribution logic for a gauge, and adds the sends to // the distrInfo struct. It also updates the gauge for the distribution. // It handles any kind of gauges: @@ -481,9 +502,11 @@ func (k Keeper) Distribute(ctx sdk.Context, gauges []types.Gauge) (sdk.Coins, er gaugeDistributedCoins, err = k.distributeSyntheticInternal(ctx, gauge, filteredLocks, &distrInfo) } else { // Donot distribue if LockQueryType = Group, because if we distribute here we will be double distributing. - if gauge.DistributeTo.LockQueryType != lockuptypes.ByGroup { - gaugeDistributedCoins, err = k.distributeInternal(ctx, gauge, filteredLocks, &distrInfo) + if gauge.DistributeTo.LockQueryType == lockuptypes.ByGroup { + continue } + + gaugeDistributedCoins, err = k.distributeInternal(ctx, gauge, filteredLocks, &distrInfo) } if err != nil { return nil, err diff --git a/x/incentives/keeper/distribute_test.go b/x/incentives/keeper/distribute_test.go index fe3b29671b0..9ac2ca0a8c3 100644 --- a/x/incentives/keeper/distribute_test.go +++ b/x/incentives/keeper/distribute_test.go @@ -1,13 +1,13 @@ package keeper_test import ( + "fmt" "strings" "time" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/suite" - osmoutils "github.com/osmosis-labs/osmosis/osmoutils" appParams "github.com/osmosis-labs/osmosis/v17/app/params" "github.com/osmosis-labs/osmosis/v17/x/incentives/types" incentivetypes "github.com/osmosis-labs/osmosis/v17/x/incentives/types" @@ -923,14 +923,6 @@ func (s *KeeperTestSuite) TestFunctionalInternalExternalCLGauge() { internalGaugeCoins = sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(defaultInternalGaugeValue))) // distributed full sum at epoch externalGaugeCoins = sdk.NewCoins(sdk.NewCoin("eth", sdk.NewInt(defaultExternalGaugeValue)), sdk.NewCoin("usdc", sdk.NewInt(defaultExternalGaugeValue))) // distributed full sum at epoch halfOfExternalGaugeCoins = sdk.NewCoins(sdk.NewCoin("eth", sdk.NewInt(defaultExternalGaugeValue/numEpochsPaidOverGaugeTwo)), sdk.NewCoin("usdc", sdk.NewInt(defaultExternalGaugeValue/numEpochsPaidOverGaugeTwo))) // distributed at each epoch for non-perp gauge with numEpoch = 2 - - internalGaugeDecCoins = osmoutils.ConvertCoinsToDecCoins(internalGaugeCoins) - externalGaugeDecCoins = osmoutils.ConvertCoinsToDecCoins(externalGaugeCoins) - halfOfExternalGaugeDecCoins = osmoutils.ConvertCoinsToDecCoins(halfOfExternalGaugeCoins) - - emissionRateForPool1 = sdk.NewDecFromInt(sdk.NewInt(defaultExternalGaugeValue)).QuoTruncate(sdk.NewDec(epochInfo.Duration.Milliseconds()).QuoInt(sdk.NewInt(1000))) - emissionRateForPool2 = sdk.NewDecFromInt(sdk.NewInt(defaultExternalGaugeValue / 2)).QuoTruncate(sdk.NewDec(epochInfo.Duration.Milliseconds()).QuoInt(sdk.NewInt(1000))) - emissionRateForInternalTokens = sdk.NewDecFromInt(sdk.NewInt(defaultInternalGaugeValue)).QuoTruncate(sdk.NewDec(epochInfo.Duration.Milliseconds()).QuoInt(sdk.NewInt(1000))) ) s.FundAcc(s.TestAccs[1], requiredBalances) @@ -997,17 +989,17 @@ func (s *KeeperTestSuite) TestFunctionalInternalExternalCLGauge() { s.Require().Equal(2, len(clPool2IncentiveRecordsAtEpoch1)) s.Require().Equal(2, len(clPool3IncentiveRecordsAtEpoch1)) - s.ValidateIncentiveRecord(clPoolId1.GetId(), externalGaugeDecCoins[0], emissionRateForPool1, clPool1IncentiveRecordsAtEpoch1[0]) - s.ValidateIncentiveRecord(clPoolId1.GetId(), externalGaugeDecCoins[1], emissionRateForPool1, clPool1IncentiveRecordsAtEpoch1[1]) + s.ValidateIncentiveRecord(clPoolId1.GetId(), externalGaugeCoins[0], clPool1IncentiveRecordsAtEpoch1[0]) + s.ValidateIncentiveRecord(clPoolId1.GetId(), externalGaugeCoins[1], clPool1IncentiveRecordsAtEpoch1[1]) // Note: ClPool2 will recieve 500kusdc, 500keth in this epoch. - s.ValidateIncentiveRecord(clPoolId2.GetId(), halfOfExternalGaugeDecCoins[0], emissionRateForPool2, clPool2IncentiveRecordsAtEpoch1[0]) - s.ValidateIncentiveRecord(clPoolId2.GetId(), halfOfExternalGaugeDecCoins[1], emissionRateForPool2, clPool2IncentiveRecordsAtEpoch1[1]) + s.ValidateIncentiveRecord(clPoolId2.GetId(), halfOfExternalGaugeCoins[0], clPool2IncentiveRecordsAtEpoch1[0]) + s.ValidateIncentiveRecord(clPoolId2.GetId(), halfOfExternalGaugeCoins[1], clPool2IncentiveRecordsAtEpoch1[1]) // Note: ClPool3 will recieve full 1Musdc, 1Meth in this epoch. // Note: emission rate is the same as CLPool1 because we are distributed same amount over 1 epoch. - s.ValidateIncentiveRecord(clPoolId3.GetId(), externalGaugeDecCoins[0], emissionRateForPool1, clPool3IncentiveRecordsAtEpoch1[0]) - s.ValidateIncentiveRecord(clPoolId3.GetId(), externalGaugeDecCoins[1], emissionRateForPool1, clPool3IncentiveRecordsAtEpoch1[1]) + s.ValidateIncentiveRecord(clPoolId3.GetId(), externalGaugeCoins[0], clPool3IncentiveRecordsAtEpoch1[0]) + s.ValidateIncentiveRecord(clPoolId3.GetId(), externalGaugeCoins[1], clPool3IncentiveRecordsAtEpoch1[1]) // 6. Remove distribution records for internal incentives using HandleReplacePoolIncentivesProposal s.IncentivizeInternalGauge([]uint64{clPoolId1.GetId(), clPoolId2.GetId()}, epochInfo.Duration, true) @@ -1043,16 +1035,16 @@ func (s *KeeperTestSuite) TestFunctionalInternalExternalCLGauge() { s.Require().Equal(2, len(clPool3IncentiveRecordsAtEpoch2)) // Note: ClPool1 will recieve 1Musdc, 1Meth (from epoch1) as external incentive, 750Kstake as internal incentive. - s.ValidateIncentiveRecord(clPoolId1.GetId(), externalGaugeDecCoins[0], emissionRateForPool1, clPool1IncentiveRecordsAtEpoch2[0]) - s.ValidateIncentiveRecord(clPoolId1.GetId(), externalGaugeDecCoins[1], emissionRateForPool1, clPool1IncentiveRecordsAtEpoch2[1]) - s.ValidateIncentiveRecord(clPoolId1.GetId(), internalGaugeDecCoins[0], emissionRateForInternalTokens, clPool1IncentiveRecordsAtEpoch2[2]) + s.ValidateIncentiveRecord(clPoolId1.GetId(), externalGaugeCoins[0], clPool1IncentiveRecordsAtEpoch2[0]) + s.ValidateIncentiveRecord(clPoolId1.GetId(), externalGaugeCoins[1], clPool1IncentiveRecordsAtEpoch2[1]) + s.ValidateIncentiveRecord(clPoolId1.GetId(), internalGaugeCoins[0], clPool1IncentiveRecordsAtEpoch2[2]) // Note: ClPool2 will recieve 500kusdc, 500keth (from epoch1) as external incentive, 500kusdc, 500keth (from epoch 2) as external incentive and 750Kstake as internal incentive. - s.ValidateIncentiveRecord(clPoolId2.GetId(), halfOfExternalGaugeDecCoins[1], emissionRateForPool2, clPool2IncentiveRecordsAtEpoch2[0]) // new record - s.ValidateIncentiveRecord(clPoolId2.GetId(), halfOfExternalGaugeDecCoins[0], emissionRateForPool2, clPool2IncentiveRecordsAtEpoch2[1]) // new record - s.ValidateIncentiveRecord(clPoolId2.GetId(), halfOfExternalGaugeDecCoins[1], emissionRateForPool2, clPool2IncentiveRecordsAtEpoch2[2]) // new record - s.ValidateIncentiveRecord(clPoolId2.GetId(), internalGaugeDecCoins[0], emissionRateForInternalTokens, clPool2IncentiveRecordsAtEpoch2[3]) // old record - s.ValidateIncentiveRecord(clPoolId2.GetId(), halfOfExternalGaugeDecCoins[0], emissionRateForPool2, clPool2IncentiveRecordsAtEpoch2[4]) // old record + s.ValidateIncentiveRecord(clPoolId2.GetId(), halfOfExternalGaugeCoins[1], clPool2IncentiveRecordsAtEpoch2[0]) // new record + s.ValidateIncentiveRecord(clPoolId2.GetId(), halfOfExternalGaugeCoins[0], clPool2IncentiveRecordsAtEpoch2[1]) // new record + s.ValidateIncentiveRecord(clPoolId2.GetId(), halfOfExternalGaugeCoins[1], clPool2IncentiveRecordsAtEpoch2[2]) // new record + s.ValidateIncentiveRecord(clPoolId2.GetId(), internalGaugeCoins[0], clPool2IncentiveRecordsAtEpoch2[3]) // old record + s.ValidateIncentiveRecord(clPoolId2.GetId(), halfOfExternalGaugeCoins[0], clPool2IncentiveRecordsAtEpoch2[4]) // old record // all incentive for ClPoolId3 have already been distributed in epoch1. There is nothing left to distribute. s.Require().Equal(clPool3IncentiveRecordsAtEpoch1, clPool3IncentiveRecordsAtEpoch2) @@ -1083,13 +1075,8 @@ func (s *KeeperTestSuite) TestFunctionalInternalExternalCLGauge() { } func (s *KeeperTestSuite) CreateNoLockExternalGauges(clPoolId uint64, externalGaugeCoins sdk.Coins, gaugeCreator sdk.AccAddress, numEpochsPaidOver uint64) uint64 { - isPerp := false - if numEpochsPaidOver == uint64(1) { - isPerp = true - } - // Create 1 external no-lock gauge perpetual over 1 epochs MsgCreateGauge - clPoolExternalGaugeId, err := s.App.IncentivesKeeper.CreateGauge(s.Ctx, isPerp, gaugeCreator, externalGaugeCoins, + clPoolExternalGaugeId, err := s.App.IncentivesKeeper.CreateGauge(s.Ctx, numEpochsPaidOver == 1, gaugeCreator, externalGaugeCoins, lockuptypes.QueryCondition{ LockQueryType: lockuptypes.NoLock, }, @@ -1167,188 +1154,136 @@ func (s *KeeperTestSuite) TestAllocateAcrossGauges() { } -/* -Test Structure -Step 1: -Create 3 internal-gauges that'll we'll add to split incentives -Create 1 regular no-lock perp gauge to make sure it's flow is not affected - -Step 2: -Create Group Gauge with 100_000_000uosmo paid over 3 epoch, equally split between 3 internal gauges. -It also links internal-gauge with groupGauge Will look something like this: {groupGaugeId, [internalGaugeId1, internalGaugeId2, internalGaugeId3]} +func (s *KeeperTestSuite) SetupGroupGauge(clPoolId uint64, lockOwner sdk.AccAddress, numOfNoLockGauges uint64, numOfLockGauges uint64) []uint64 { + var internalGauges []uint64 -Step 3: -Let epoch 1 pass we expect: + // create Internal Gauges + for i := uint64(1); i <= numOfNoLockGauges; i++ { + clNoLockGaugeId := s.CreateNoLockExternalGauges(clPoolId, sdk.NewCoins(), s.TestAccs[1], uint64(1)) // gauge id = 2,3,4 + internalGauges = append(internalGauges, clNoLockGaugeId) + } - internalGauge1 to recieve 11_111_111uosmo, internalGauge2 to recieve 11_111_111uosmo, internalGauge3 to recieve 11_111_111uosmo - decrement GroupGauge coins from 100_000_000 - 33_333_333 = 66_666_667 - We also expect, regular gauge incentive to be distributed. - Hence, total 3 incentiveRecord for CL pools (2 from internal-gauges, 1 from regular gauge) & 1 GAMM lock incentive. + for i := uint64(1); i <= numOfLockGauges; i++ { + // setup lock + s.LockTokens(lockOwner, sdk.Coins{sdk.NewInt64Coin("lptoken", 10)}, time.Hour*7) -Step 4: -Let epoch 2 pass, we expect: + // create gauge + gaugeID, _, _, _ := s.SetupNewGauge(true, sdk.NewCoins()) - internalGauge1 to recieve 11_111_111uosmo, internalGauge2 to recieve 11_111_111uosmo, internalGauge3 to recieve 11_111_111uosmo - incentiveGauge1, incentiveGauge2, incentiveGauge3 should be empty - decrement GroupGauge coins from 66_666_667 - 33_333_333 = 33_333_334 - Hence, total 5 incentiveRecord for CL pools + internalGauges = append(internalGauges, gaugeID) + } -Step 5: -Let epoch 3 pass, we expect: + return internalGauges +} - internalGauge1 to recieve 11_111_111uosmo, internalGauge2 to recieve 11_111_111uosmo, internalGauge3 to recieve 11_111_111uosmo - incentiveGauge1, incentiveGauge2, incentiveGauge3 should be empty - decrement GroupGauge coins from 33_333_334 - 33_333_333 = 1 - Hence, total 7 incentiveRecord for CL pools -*/ func (s *KeeperTestSuite) TestCreateGroupGaugeAndDistribute() { - var ( - epochInfo = s.App.IncentivesKeeper.GetEpochInfo(s.Ctx) - - expectedCoinsDistributed = sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(11_111_111))) - expectedCoinsDistributedEpoch2 = sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(11_111_111*2))) - expectedCoinsDistributedEpoch3 = sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(11_111_111*3))) - - expectedCoinsDistributedDecCoins = osmoutils.ConvertCoinsToDecCoins(expectedCoinsDistributed) - - emissionRateForPoolClPool = sdk.NewDecFromInt(sdk.NewInt(11_111_111)).QuoTruncate(sdk.NewDec(epochInfo.Duration.Milliseconds()).QuoInt(sdk.NewInt(1000))) - - expectedCoinsDistributedRegularGauge = osmoutils.ConvertCoinsToDecCoins(sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100)))) - newEmissionRateForClPool = sdk.NewDecFromInt(sdk.NewInt(100)).QuoTruncate(sdk.NewDec(epochInfo.Duration.Milliseconds()).QuoInt(sdk.NewInt(1000))) - - groupGaugeCoinAfterEpoch1 = sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(66_666_667))) - groupGaugeCoinAfterEpoch2 = sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(33_333_334))) - ) - - s.FundAcc(s.TestAccs[1], sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(1_000_000_000)))) // 1,000 osmo + type GroupGaugeCreationFields struct { + coins sdk.Coins + numEpochPaidOver uint64 + owner sdk.AccAddress + internalGaugeIds []uint64 + } - // Step 1 - clPool := s.PrepareConcentratedPool() // we already create a gauge here - internalGauge1 := s.CreateNoLockExternalGauges(clPool.GetId(), sdk.Coins{}, s.TestAccs[1], uint64(1)) // gauge id = 2 - internalGauge2 := s.CreateNoLockExternalGauges(clPool.GetId(), sdk.Coins{}, s.TestAccs[1], uint64(1)) // gauge id = 3 - internalGauge3, err := s.App.IncentivesKeeper.CreateGauge(s.Ctx, true, s.TestAccs[1], sdk.Coins{}, // gauge id = 4 - lockuptypes.QueryCondition{ - LockQueryType: lockuptypes.ByDuration, - Denom: "stake", // this denom is just for test, is subject to change - Duration: time.Hour * 7, // 7 hr is the max in test suite, will be 2weeks in mainnet + tests := []struct { + name string + createGauge GroupGaugeCreationFields + expectedDistibutionCoinsPerInternalGauge sdk.Coins + expectedTotalDistributedCoinsPerEpoch sdk.Coins + }{ + { + name: "Valid case: Valid perp-GroupGauge Creation and Distribution", + createGauge: GroupGaugeCreationFields{ + coins: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100_000_000))), + numEpochPaidOver: 1, + owner: s.TestAccs[1], + internalGaugeIds: []uint64{2, 3, 4, 5}, + }, + expectedDistibutionCoinsPerInternalGauge: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(25_000_000))), // 100osmo / 4 = 25osmo + expectedTotalDistributedCoinsPerEpoch: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100_000_000))), + }, + { + name: "Valid case: Valid non-perpGroupGauge Creation with and Distribution", + createGauge: GroupGaugeCreationFields{ + coins: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100_000_000))), + numEpochPaidOver: 4, + owner: s.TestAccs[1], + internalGaugeIds: []uint64{2, 3, 4, 5}, + }, + expectedDistibutionCoinsPerInternalGauge: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(6_250_000))), + expectedTotalDistributedCoinsPerEpoch: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(25_000_000))), + }, + { + name: "Valid case: Valid GroupGauge Creation with 2 coins and Distribution", + createGauge: GroupGaugeCreationFields{ + coins: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100_000_000)), sdk.NewCoin("uatom", sdk.NewInt(100_000_000))), + numEpochPaidOver: 1, + owner: s.TestAccs[1], + internalGaugeIds: []uint64{2, 3, 4, 5}, + }, + expectedDistibutionCoinsPerInternalGauge: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(25_000_000)), sdk.NewCoin("uatom", sdk.NewInt(25_000_000))), // 100osmo / 4 = 25osmo + expectedTotalDistributedCoinsPerEpoch: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100_000_000)), sdk.NewCoin("uatom", sdk.NewInt(100_000_000))), }, - s.Ctx.BlockTime(), - 1, - 0, - ) - s.Require().NoError(err) - - // Regular gauge no group gauge - _ = s.CreateNoLockExternalGauges(clPool.GetId(), sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100))), s.TestAccs[1], uint64(1)) // gauge id = 5 - - // Step 2 - // create GroupGauge - groupGaugeId, err := s.App.IncentivesKeeper.CreateGroupGauge(s.Ctx, sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100_000_000))), uint64(3), s.TestAccs[1], []uint64{internalGauge1, internalGauge2, internalGauge3}) // gauge id = 6 - s.Require().NoError(err) - - groupGauges, err := s.App.IncentivesKeeper.GetAllGroupGauges(s.Ctx) - s.Require().NoError(err) - - s.Require().NotEmpty(groupGauges) - - // Step 3 - //let epoch 1 pass - // ******************** EPOCH 1 ********************* - s.Ctx = s.Ctx.WithBlockTime(s.Ctx.BlockTime().Add(epochInfo.Duration)) - s.App.EpochsKeeper.AfterEpochEnd(s.Ctx, epochInfo.GetIdentifier(), 1) - - // Validate that group gauge coins went down by 33_333_333uosmo - groupGauge, err := s.App.IncentivesKeeper.GetGaugeByID(s.Ctx, groupGaugeId) - s.Require().NoError(err) - - s.Require().Equal(groupGauge.Coins.Sub(groupGauge.DistributedCoins), groupGaugeCoinAfterEpoch1) - - s.ValidateDistributedGauge(internalGauge1, 1, expectedCoinsDistributed) - s.ValidateDistributedGauge(internalGauge2, 1, expectedCoinsDistributed) - - // Validate that we created incentive record after distributing gaugeId 2,3,5 - clPoolIncentiveRecordsAtEpoch1, err := s.App.ConcentratedLiquidityKeeper.GetAllIncentiveRecordsForPool(s.Ctx, clPool.GetId()) - s.Require().NoError(err) - - s.Require().Equal(3, len(clPoolIncentiveRecordsAtEpoch1)) - - for i := 0; i < len(clPoolIncentiveRecordsAtEpoch1); i++ { - if i == 2 { - s.ValidateIncentiveRecord(clPool.GetId(), expectedCoinsDistributedRegularGauge[0], newEmissionRateForClPool, clPoolIncentiveRecordsAtEpoch1[i]) - } else { - s.ValidateIncentiveRecord(clPool.GetId(), expectedCoinsDistributedDecCoins[0], emissionRateForPoolClPool, clPoolIncentiveRecordsAtEpoch1[i]) - } + // { + // name: "Valid case: Valid GroupGauge Creation With Balancer & Cl internalGauges and Distribution", + // }, } - // Step 4 - //let epoch 2 pass - // ******************** EPOCH 2 ********************* - s.Ctx = s.Ctx.WithBlockTime(s.Ctx.BlockTime().Add(epochInfo.Duration)) - s.App.EpochsKeeper.AfterEpochEnd(s.Ctx, epochInfo.GetIdentifier(), 2) - - // Validate that group gauge coins went down by 33_333_333uosmo - groupGauge, err = s.App.IncentivesKeeper.GetGaugeByID(s.Ctx, groupGaugeId) - s.Require().NoError(err) - s.Require().Equal(groupGauge.Coins.Sub(groupGauge.DistributedCoins), groupGaugeCoinAfterEpoch2) + for _, tc := range tests { + s.Run(tc.name, func() { + s.SetupTest() - s.ValidateDistributedGauge(internalGauge1, 2, expectedCoinsDistributedEpoch2) - s.ValidateDistributedGauge(internalGauge2, 2, expectedCoinsDistributedEpoch2) + s.FundAcc(s.TestAccs[1], sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(1_000_000_000)), sdk.NewCoin("uatom", sdk.NewInt(1_000_000_000)))) // 1,000 osmo + clPool := s.PrepareConcentratedPool() + lockOwner := sdk.AccAddress([]byte("addr1---------------")) + s.SetupGroupGauge(clPool.GetId(), lockOwner, uint64(3), uint64(1)) - // Validate that we created incentive record after distributing gaugeId 2,3,5 - clPoolIncentiveRecordsAtEpoch2, err := s.App.ConcentratedLiquidityKeeper.GetAllIncentiveRecordsForPool(s.Ctx, clPool.GetId()) - s.Require().NoError(err) + groupGaugeId, err := s.App.IncentivesKeeper.CreateGroupGauge(s.Ctx, tc.createGauge.coins, tc.createGauge.numEpochPaidOver, tc.createGauge.owner, tc.createGauge.internalGaugeIds) // gauge id = 6 + s.Require().NoError(err) - s.Require().Equal(5, len(clPoolIncentiveRecordsAtEpoch2)) + //fmt.Println(groupGaugeId) - for i := 0; i < len(clPoolIncentiveRecordsAtEpoch2); i++ { - if i == 2 { - s.ValidateIncentiveRecord(clPool.GetId(), expectedCoinsDistributedRegularGauge[0], newEmissionRateForClPool, clPoolIncentiveRecordsAtEpoch2[i]) - } else { - s.ValidateIncentiveRecord(clPool.GetId(), expectedCoinsDistributedDecCoins[0], emissionRateForPoolClPool, clPoolIncentiveRecordsAtEpoch2[i]) - } + // TODO check internal incentives matches what we created - } + epochInfo := s.App.IncentivesKeeper.GetEpochInfo(s.Ctx) + for i := uint64(1); i <= tc.createGauge.numEpochPaidOver; i++ { + // ******************** EPOCH PASSED ********************* // + s.Ctx = s.Ctx.WithBlockTime(s.Ctx.BlockTime().Add(epochInfo.Duration)) + s.App.EpochsKeeper.AfterEpochEnd(s.Ctx, epochInfo.GetIdentifier(), int64(i)) - // Step 4 - //let epoch 3 pass - // ******************** EPOCH 3 ********************* - s.Ctx = s.Ctx.WithBlockTime(s.Ctx.BlockTime().Add(epochInfo.Duration)) - s.App.EpochsKeeper.AfterEpochEnd(s.Ctx, epochInfo.GetIdentifier(), 3) + // Validate GroupGauge + groupGauge, err := s.App.IncentivesKeeper.GetGaugeByID(s.Ctx, groupGaugeId) + s.Require().NoError(err) - // Validate that group gauge coins went down by 33_333_333uosmo - groupGauge, err = s.App.IncentivesKeeper.GetGaugeByID(s.Ctx, groupGaugeId) - s.Require().NoError(err) + for _, coin := range tc.expectedTotalDistributedCoinsPerEpoch { + s.ValidateDistributedGauge(groupGauge.Id, i, sdk.NewCoins(sdk.NewCoin(coin.Denom, coin.Amount.Mul(sdk.NewIntFromUint64(i))))) + } - s.Require().Equal(groupGauge.Coins.Sub(groupGauge.DistributedCoins), sdk.Coins(nil)) + // Validate Internal Gauges + internalGauges, err := s.App.IncentivesKeeper.GetGaugeFromIDs(s.Ctx, tc.createGauge.internalGaugeIds) + s.Require().NoError(err) - s.ValidateDistributedGauge(internalGauge1, 3, expectedCoinsDistributedEpoch3) - s.ValidateDistributedGauge(internalGauge2, 3, expectedCoinsDistributedEpoch3) + for _, internalGauge := range internalGauges { + for _, coin := range tc.expectedDistibutionCoinsPerInternalGauge { + s.ValidateDistributedGauge(internalGauge.Id, i, sdk.NewCoins(sdk.NewCoin(coin.Denom, coin.Amount.Mul(sdk.NewIntFromUint64(i))))) + } + } - // Validate that we created incentive record after distributing gaugeId 2,3,5 - clPoolIncentiveRecordsAtEpoch3, err := s.App.ConcentratedLiquidityKeeper.GetAllIncentiveRecordsForPool(s.Ctx, clPool.GetId()) - s.Require().NoError(err) + // Validate CL Incentive distribution + poolIncentives, err := s.App.ConcentratedLiquidityKeeper.GetAllIncentiveRecordsForPool(s.Ctx, clPool.GetId()) + s.Require().NoError(err) - s.Require().Equal(7, len(clPoolIncentiveRecordsAtEpoch3)) + // fmt.Println(poolIncentives) + for i := 0; i < len(poolIncentives); i++ { + s.ValidateIncentiveRecord(clPool.GetId(), tc.expectedDistibutionCoinsPerInternalGauge[0], poolIncentives[i]) + } - for i := 0; i < len(clPoolIncentiveRecordsAtEpoch3); i++ { - if i == 2 { - s.ValidateIncentiveRecord(clPool.GetId(), expectedCoinsDistributedRegularGauge[0], newEmissionRateForClPool, clPoolIncentiveRecordsAtEpoch3[i]) - } else { - s.ValidateIncentiveRecord(clPool.GetId(), expectedCoinsDistributedDecCoins[0], emissionRateForPoolClPool, clPoolIncentiveRecordsAtEpoch3[i]) - } + // Validate GAMM incentive distribution + bal := s.App.BankKeeper.GetAllBalances(s.Ctx, lockOwner) + fmt.Println(bal) + } + }) } - // Step 5 - // let epoch 4 pass - // There should not be any distribution since all the tokens have been distributed - // ******************** EPOCH 4 ********************* - s.Ctx = s.Ctx.WithBlockTime(s.Ctx.BlockTime().Add(epochInfo.Duration)) - s.App.EpochsKeeper.AfterEpochEnd(s.Ctx, epochInfo.GetIdentifier(), 4) - - clPoolIncentiveRecordsAtEpoch4, err := s.App.ConcentratedLiquidityKeeper.GetAllIncentiveRecordsForPool(s.Ctx, clPool.GetId()) - s.Require().NoError(err) - - s.Require().Equal(7, len(clPoolIncentiveRecordsAtEpoch4)) } diff --git a/x/incentives/keeper/gauge.go b/x/incentives/keeper/gauge.go index 7de5acd3ae4..26b3540a67f 100644 --- a/x/incentives/keeper/gauge.go +++ b/x/incentives/keeper/gauge.go @@ -212,21 +212,28 @@ func (k Keeper) CreateGauge(ctx sdk.Context, isPerpetual bool, owner sdk.AccAddr // Note: we should expect that the internal gauges consist of the gauges that are automatically created for each pool upon pool creation, as even non-perpetual // external incentives would likely want to route through these. func (k Keeper) CreateGroupGauge(ctx sdk.Context, coins sdk.Coins, numEpochPaidOver uint64, owner sdk.AccAddress, internalGaugeIds []uint64) (uint64, error) { - isPerp := false - if numEpochPaidOver == 1 { - isPerp = true + if len(internalGaugeIds) == 0 { + return 0, fmt.Errorf("No internalGauge provided.") } // check that all the internalGaugeIds exist - if _, err := k.GetGaugeFromIDs(ctx, internalGaugeIds); err != nil { + internalGauges, err := k.GetGaugeFromIDs(ctx, internalGaugeIds) + if err != nil { return 0, fmt.Errorf("Invalid internalGaugeIds, please make sure all the internalGauge have been created.") } + // check that all internalGauges are perp + for _, gauge := range internalGauges { + if !gauge.IsPerpetual { + return 0, fmt.Errorf("Internal Gauge id %d is non-perp, all internalGauge must be perpetual Gauge.", gauge.Id) + } + } + nextGaugeId := k.GetLastGaugeID(ctx) + 1 gauge := types.Gauge{ Id: nextGaugeId, - IsPerpetual: isPerp, + IsPerpetual: numEpochPaidOver == 1, DistributeTo: lockuptypes.QueryCondition{ LockQueryType: lockuptypes.ByGroup, }, @@ -244,13 +251,15 @@ func (k Keeper) CreateGroupGauge(ctx sdk.Context, coins sdk.Coins, numEpochPaidO } newGroupGauge := types.GroupGauge{ - GroupGaugeId: nextGaugeId, - InternalIds: internalGaugeIds, + GroupGaugeId: nextGaugeId, + InternalIds: internalGaugeIds, + SplittingPolicy: types.Evenly, } k.SetGroupGauge(ctx, newGroupGauge) k.SetLastGaugeID(ctx, gauge.Id) + // TODO: check if this is necessary combinedKeys := combineKeys(types.KeyPrefixUpcomingGauges, getTimeKey(gauge.StartTime)) activeOrUpcomingGauge := true diff --git a/x/incentives/keeper/gauge_test.go b/x/incentives/keeper/gauge_test.go index c048990f1d3..70e0e788ad0 100644 --- a/x/incentives/keeper/gauge_test.go +++ b/x/incentives/keeper/gauge_test.go @@ -614,6 +614,20 @@ func (s *KeeperTestSuite) TestCreateGroupGauge() { internalGaugeIds: []uint64{2, 3, 4}, expectErr: true, }, + { + name: "Error: One of the internal Gauge is non-perp", + coins: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(200_000_000))), + numEpochPaidOver: 1, + internalGaugeIds: []uint64{2, 3, 4, 5}, + expectErr: true, + }, + { + name: "Error: No InternalGaugeIds provided", + coins: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(200_000_000))), + numEpochPaidOver: 1, + internalGaugeIds: []uint64{}, + expectErr: true, + }, } for _, tc := range tests { @@ -622,12 +636,15 @@ func (s *KeeperTestSuite) TestCreateGroupGauge() { s.FundAcc(s.TestAccs[1], sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100_000_000)))) // 1,000 osmo clPool := s.PrepareConcentratedPool() // gaugeid = 1 - // create 3 internal Gauge + // create 3 perp-internal Gauge for i := 0; i <= 2; i++ { s.CreateNoLockExternalGauges(clPool.GetId(), sdk.NewCoins(), s.TestAccs[1], uint64(1)) // gauge id = 2,3,4 } - groupGaugeId, err := s.App.IncentivesKeeper.CreateGroupGauge(s.Ctx, tc.coins, tc.numEpochPaidOver, s.TestAccs[1], tc.internalGaugeIds) // gauge id = 5 + //create 1 non-perp internal Gauge + s.CreateNoLockExternalGauges(clPool.GetId(), sdk.NewCoins(), s.TestAccs[1], uint64(2)) // gauge id = 5 + + groupGaugeId, err := s.App.IncentivesKeeper.CreateGroupGauge(s.Ctx, tc.coins, tc.numEpochPaidOver, s.TestAccs[1], tc.internalGaugeIds) // gauge id = 6 if tc.expectErr { s.Require().Error(err) } else { diff --git a/x/incentives/keeper/keeper_test.go b/x/incentives/keeper/keeper_test.go index 095474fce45..7f5b43dddcd 100644 --- a/x/incentives/keeper/keeper_test.go +++ b/x/incentives/keeper/keeper_test.go @@ -47,9 +47,13 @@ func (s *KeeperTestSuite) ValidateNotDistributedGauge(gaugeID uint64) { s.ValidateDistributedGauge(gaugeID, 0, sdk.Coins(nil)) } -func (s *KeeperTestSuite) ValidateIncentiveRecord(poolId uint64, remainingCoin sdk.DecCoin, emissionRate sdk.Dec, incentiveRecord cltypes.IncentiveRecord) { +func (s *KeeperTestSuite) ValidateIncentiveRecord(poolId uint64, remainingCoin sdk.Coin, incentiveRecord cltypes.IncentiveRecord) { + epochInfo := s.App.IncentivesKeeper.GetEpochInfo(s.Ctx) + distributedDecCoin := sdk.NewDecCoinFromCoin(remainingCoin) + emissionRateForPoolClPool := distributedDecCoin.Amount.QuoTruncate(sdk.NewDec(epochInfo.Duration.Milliseconds()).QuoInt(sdk.NewInt(1000))) + s.Require().Equal(poolId, incentiveRecord.PoolId) - s.Require().Equal(emissionRate, incentiveRecord.GetIncentiveRecordBody().EmissionRate) + s.Require().Equal(emissionRateForPoolClPool, incentiveRecord.GetIncentiveRecordBody().EmissionRate) s.Require().Equal(types.DefaultConcentratedUptime, incentiveRecord.MinUptime) - s.Require().Equal(remainingCoin, incentiveRecord.GetIncentiveRecordBody().RemainingCoin) + s.Require().Equal(distributedDecCoin, incentiveRecord.GetIncentiveRecordBody().RemainingCoin) } diff --git a/x/incentives/types/gauge.pb.go b/x/incentives/types/gauge.pb.go index 9a307b98c0a..7a12ef1e368 100644 --- a/x/incentives/types/gauge.pb.go +++ b/x/incentives/types/gauge.pb.go @@ -30,6 +30,35 @@ var _ = time.Kitchen // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package +// SplittingPolicy determines the way we want to split incentives in groupGauges +type SplittingPolicy int32 + +const ( + Volume SplittingPolicy = 0 + Liquidity SplittingPolicy = 1 + Evenly SplittingPolicy = 2 +) + +var SplittingPolicy_name = map[int32]string{ + 0: "Volume", + 1: "Liquidity", + 2: "Evenly", +} + +var SplittingPolicy_value = map[string]int32{ + "Volume": 0, + "Liquidity": 1, + "Evenly": 2, +} + +func (x SplittingPolicy) String() string { + return proto.EnumName(SplittingPolicy_name, int32(x)) +} + +func (SplittingPolicy) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_c0304e2bb0159901, []int{0} +} + // Gauge is an object that stores and distributes yields to recipients who // satisfy certain conditions. Currently gauges support conditions around the // duration for which a given denom is locked. @@ -153,8 +182,9 @@ func (m *Gauge) GetDistributedCoins() github_com_cosmos_cosmos_sdk_types.Coins { // linked these two together so that we can distribute tokens from groupGauge to // internalGauges. type GroupGauge struct { - GroupGaugeId uint64 `protobuf:"varint,1,opt,name=group_gauge_id,json=groupGaugeId,proto3" json:"group_gauge_id,omitempty"` - InternalIds []uint64 `protobuf:"varint,2,rep,packed,name=internal_ids,json=internalIds,proto3" json:"internal_ids,omitempty"` + GroupGaugeId uint64 `protobuf:"varint,1,opt,name=group_gauge_id,json=groupGaugeId,proto3" json:"group_gauge_id,omitempty"` + InternalIds []uint64 `protobuf:"varint,2,rep,packed,name=internal_ids,json=internalIds,proto3" json:"internal_ids,omitempty"` + SplittingPolicy SplittingPolicy `protobuf:"varint,3,opt,name=splitting_policy,json=splittingPolicy,proto3,enum=osmosis.incentives.SplittingPolicy" json:"splitting_policy,omitempty"` } func (m *GroupGauge) Reset() { *m = GroupGauge{} } @@ -204,6 +234,13 @@ func (m *GroupGauge) GetInternalIds() []uint64 { return nil } +func (m *GroupGauge) GetSplittingPolicy() SplittingPolicy { + if m != nil { + return m.SplittingPolicy + } + return Volume +} + type LockableDurationsInfo struct { // List of incentivised durations that gauges will pay out to LockableDurations []time.Duration `protobuf:"bytes,1,rep,name=lockable_durations,json=lockableDurations,proto3,stdduration" json:"lockable_durations" yaml:"lockable_durations"` @@ -250,6 +287,7 @@ func (m *LockableDurationsInfo) GetLockableDurations() []time.Duration { } func init() { + proto.RegisterEnum("osmosis.incentives.SplittingPolicy", SplittingPolicy_name, SplittingPolicy_value) proto.RegisterType((*Gauge)(nil), "osmosis.incentives.Gauge") proto.RegisterType((*GroupGauge)(nil), "osmosis.incentives.GroupGauge") proto.RegisterType((*LockableDurationsInfo)(nil), "osmosis.incentives.LockableDurationsInfo") @@ -258,45 +296,50 @@ func init() { func init() { proto.RegisterFile("osmosis/incentives/gauge.proto", fileDescriptor_c0304e2bb0159901) } var fileDescriptor_c0304e2bb0159901 = []byte{ - // 593 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x53, 0xcf, 0x6e, 0xd3, 0x30, - 0x1c, 0x6e, 0xba, 0x6e, 0x0c, 0xb7, 0x9b, 0xa8, 0x35, 0xa4, 0x6c, 0x12, 0x69, 0x09, 0x20, 0xe5, - 0x32, 0x9b, 0x0d, 0x09, 0x24, 0x8e, 0x1d, 0x68, 0xaa, 0x84, 0xc4, 0x88, 0x86, 0x84, 0xb8, 0x44, - 0x4e, 0xec, 0x65, 0xd6, 0x92, 0x38, 0x8a, 0x9d, 0x6a, 0x7d, 0x03, 0x8e, 0x13, 0x27, 0x9e, 0x81, - 0x27, 0xd9, 0x71, 0x47, 0x4e, 0x1b, 0x6a, 0xdf, 0x80, 0x27, 0x40, 0xb1, 0x93, 0xb5, 0x2a, 0x57, - 0x4e, 0xa9, 0x7f, 0xdf, 0xef, 0xdf, 0xf7, 0xfd, 0xbe, 0x02, 0x47, 0xc8, 0x54, 0x48, 0x2e, 0x31, - 0xcf, 0x22, 0x96, 0x29, 0x3e, 0x61, 0x12, 0xc7, 0xa4, 0x8c, 0x19, 0xca, 0x0b, 0xa1, 0x04, 0x84, - 0x35, 0x8e, 0x16, 0xf8, 0xde, 0x4e, 0x2c, 0x62, 0xa1, 0x61, 0x5c, 0xfd, 0x32, 0x99, 0x7b, 0x4e, - 0x2c, 0x44, 0x9c, 0x30, 0xac, 0x5f, 0x61, 0x79, 0x86, 0x69, 0x59, 0x10, 0xc5, 0x45, 0x56, 0xe3, - 0x83, 0x55, 0x5c, 0xf1, 0x94, 0x49, 0x45, 0xd2, 0xbc, 0x69, 0x10, 0xe9, 0x59, 0x38, 0x24, 0x92, - 0xe1, 0xc9, 0x41, 0xc8, 0x14, 0x39, 0xc0, 0x91, 0xe0, 0x4d, 0x83, 0xdd, 0x66, 0xd5, 0x44, 0x44, - 0x17, 0x65, 0xae, 0x3f, 0x06, 0x72, 0xbf, 0x77, 0xc0, 0xfa, 0x71, 0xb5, 0x35, 0xdc, 0x06, 0x6d, - 0x4e, 0x6d, 0x6b, 0x68, 0x79, 0x1d, 0xbf, 0xcd, 0x29, 0x7c, 0x0a, 0x7a, 0x5c, 0x06, 0x39, 0x2b, - 0x72, 0xa6, 0x4a, 0x92, 0xd8, 0xed, 0xa1, 0xe5, 0x6d, 0xfa, 0x5d, 0x2e, 0x4f, 0x9a, 0x10, 0x1c, - 0x83, 0x2d, 0xca, 0xa5, 0x2a, 0x78, 0x58, 0x2a, 0x16, 0x28, 0x61, 0xaf, 0x0d, 0x2d, 0xaf, 0x7b, - 0xe8, 0xa0, 0x86, 0xba, 0x99, 0x87, 0x3e, 0x95, 0xac, 0x98, 0x1e, 0x89, 0x8c, 0xf2, 0x8a, 0xd5, - 0xa8, 0x73, 0x7d, 0x3b, 0x68, 0xf9, 0xbd, 0x45, 0xe9, 0xa9, 0x80, 0x04, 0xac, 0x57, 0x0b, 0x4b, - 0xbb, 0x33, 0x5c, 0xf3, 0xba, 0x87, 0xbb, 0xc8, 0x50, 0x42, 0x15, 0x25, 0x54, 0x53, 0x42, 0x47, - 0x82, 0x67, 0xa3, 0x97, 0x55, 0xf5, 0xcf, 0xbb, 0x81, 0x17, 0x73, 0x75, 0x5e, 0x86, 0x28, 0x12, - 0x29, 0xae, 0xf9, 0x9b, 0xcf, 0xbe, 0xa4, 0x17, 0x58, 0x4d, 0x73, 0x26, 0x75, 0x81, 0xf4, 0x4d, - 0x67, 0xf8, 0x05, 0x00, 0xa9, 0x48, 0xa1, 0x82, 0x4a, 0x3e, 0x7b, 0x5d, 0xaf, 0xba, 0x87, 0x8c, - 0xb6, 0xa8, 0xd1, 0x16, 0x9d, 0x36, 0xda, 0x8e, 0x9e, 0x54, 0x83, 0xfe, 0xdc, 0x0e, 0xfa, 0x53, - 0x92, 0x26, 0x6f, 0xdd, 0x45, 0xad, 0x7b, 0x75, 0x37, 0xb0, 0xfc, 0x87, 0x3a, 0x50, 0xa5, 0x43, - 0x0c, 0x76, 0xb2, 0x32, 0x0d, 0x58, 0x2e, 0xa2, 0x73, 0x19, 0xe4, 0x84, 0xd3, 0x40, 0x4c, 0x58, - 0x61, 0x6f, 0x68, 0x31, 0xfb, 0x59, 0x99, 0xbe, 0xd7, 0xd0, 0x09, 0xe1, 0xf4, 0xe3, 0x84, 0x15, - 0xf0, 0x19, 0xd8, 0x3a, 0xe3, 0x49, 0xc2, 0x68, 0x5d, 0x63, 0x3f, 0xd0, 0x99, 0x3d, 0x13, 0x34, - 0xc9, 0xf0, 0x12, 0xf4, 0x17, 0x12, 0xd1, 0xc0, 0xc8, 0xb3, 0xf9, 0xff, 0xe5, 0x79, 0xb4, 0x34, - 0x45, 0x47, 0xdc, 0xcf, 0x00, 0x1c, 0x17, 0xa2, 0xcc, 0x8d, 0x31, 0x9e, 0x83, 0xed, 0xb8, 0x7a, - 0x05, 0xda, 0xdd, 0xc1, 0xbd, 0x49, 0x7a, 0xf1, 0x7d, 0xce, 0xd8, 0xd8, 0x25, 0x53, 0xac, 0xc8, - 0x48, 0x12, 0x70, 0x2a, 0xed, 0xf6, 0x70, 0xcd, 0xeb, 0xf8, 0xdd, 0x26, 0x36, 0xa6, 0xd2, 0xfd, - 0x66, 0x81, 0xc7, 0x1f, 0x44, 0x74, 0x41, 0xc2, 0x84, 0xbd, 0xab, 0x2d, 0x2e, 0xc7, 0xd9, 0x99, - 0x80, 0x02, 0xc0, 0xa4, 0x06, 0x82, 0xc6, 0xfc, 0xd2, 0xb6, 0x6a, 0xae, 0xab, 0x27, 0x6a, 0x6a, - 0x47, 0x2f, 0xea, 0x0b, 0xed, 0x9a, 0x0b, 0xfd, 0xdb, 0xc2, 0xfd, 0x51, 0x5d, 0xaa, 0x9f, 0xac, - 0x0e, 0x1d, 0x9d, 0x5c, 0xcf, 0x1c, 0xeb, 0x66, 0xe6, 0x58, 0xbf, 0x67, 0x8e, 0x75, 0x35, 0x77, - 0x5a, 0x37, 0x73, 0xa7, 0xf5, 0x6b, 0xee, 0xb4, 0xbe, 0xbe, 0x5e, 0xd2, 0xad, 0xb6, 0xf1, 0x7e, - 0x42, 0x42, 0xd9, 0x3c, 0xf0, 0xe4, 0xe0, 0x0d, 0xbe, 0x5c, 0xfe, 0xd3, 0x6b, 0x2d, 0xc3, 0x0d, - 0xbd, 0xde, 0xab, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x24, 0x31, 0x6f, 0xa8, 0x17, 0x04, 0x00, - 0x00, + // 676 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0x4f, 0x4f, 0xdb, 0x3e, + 0x18, 0x6e, 0x4a, 0xe1, 0x07, 0x6e, 0x81, 0xd6, 0xe2, 0x27, 0x85, 0x4a, 0x4b, 0xbb, 0xb2, 0x49, + 0xd5, 0x24, 0x9c, 0xc1, 0xa4, 0x4d, 0xda, 0x61, 0x87, 0x32, 0x84, 0x2a, 0xa1, 0xad, 0xcb, 0xd0, + 0x34, 0xed, 0x12, 0x39, 0x89, 0x09, 0x16, 0x4e, 0x9c, 0xc5, 0x4e, 0x45, 0xbf, 0x01, 0x47, 0xb4, + 0xd3, 0xee, 0xd3, 0x2e, 0xfb, 0x24, 0x1c, 0x39, 0xee, 0x04, 0x13, 0x7c, 0x83, 0x7d, 0x82, 0x29, + 0x76, 0x42, 0x59, 0xb9, 0xee, 0xe4, 0xf8, 0x7d, 0xde, 0x7f, 0xcf, 0xf3, 0xbe, 0x0e, 0xb0, 0xb8, + 0x88, 0xb8, 0xa0, 0xc2, 0xa6, 0xb1, 0x4f, 0x62, 0x49, 0xc7, 0x44, 0xd8, 0x21, 0xce, 0x42, 0x82, + 0x92, 0x94, 0x4b, 0x0e, 0x61, 0x81, 0xa3, 0x29, 0xde, 0x5e, 0x0b, 0x79, 0xc8, 0x15, 0x6c, 0xe7, + 0x5f, 0xda, 0xb3, 0x6d, 0x85, 0x9c, 0x87, 0x8c, 0xd8, 0xea, 0xe6, 0x65, 0x87, 0x76, 0x90, 0xa5, + 0x58, 0x52, 0x1e, 0x17, 0x78, 0x67, 0x16, 0x97, 0x34, 0x22, 0x42, 0xe2, 0x28, 0x29, 0x13, 0xf8, + 0xaa, 0x96, 0xed, 0x61, 0x41, 0xec, 0xf1, 0x96, 0x47, 0x24, 0xde, 0xb2, 0x7d, 0x4e, 0xcb, 0x04, + 0xeb, 0x65, 0xab, 0x8c, 0xfb, 0xc7, 0x59, 0xa2, 0x0e, 0x0d, 0xf5, 0xbe, 0xd4, 0xc0, 0xfc, 0x5e, + 0xde, 0x35, 0x5c, 0x01, 0x55, 0x1a, 0x98, 0x46, 0xd7, 0xe8, 0xd7, 0x9c, 0x2a, 0x0d, 0xe0, 0x43, + 0xd0, 0xa0, 0xc2, 0x4d, 0x48, 0x9a, 0x10, 0x99, 0x61, 0x66, 0x56, 0xbb, 0x46, 0x7f, 0xd1, 0xa9, + 0x53, 0x31, 0x2a, 0x4d, 0x70, 0x08, 0x96, 0x03, 0x2a, 0x64, 0x4a, 0xbd, 0x4c, 0x12, 0x57, 0x72, + 0x73, 0xae, 0x6b, 0xf4, 0xeb, 0xdb, 0x16, 0x2a, 0xa9, 0xeb, 0x7a, 0xe8, 0x5d, 0x46, 0xd2, 0xc9, + 0x0e, 0x8f, 0x03, 0x9a, 0xb3, 0x1a, 0xd4, 0xce, 0x2f, 0x3b, 0x15, 0xa7, 0x31, 0x0d, 0x3d, 0xe0, + 0x10, 0x83, 0xf9, 0xbc, 0x61, 0x61, 0xd6, 0xba, 0x73, 0xfd, 0xfa, 0xf6, 0x3a, 0xd2, 0x94, 0x50, + 0x4e, 0x09, 0x15, 0x94, 0xd0, 0x0e, 0xa7, 0xf1, 0xe0, 0x69, 0x1e, 0xfd, 0xe3, 0xaa, 0xd3, 0x0f, + 0xa9, 0x3c, 0xca, 0x3c, 0xe4, 0xf3, 0xc8, 0x2e, 0xf8, 0xeb, 0x63, 0x53, 0x04, 0xc7, 0xb6, 0x9c, + 0x24, 0x44, 0xa8, 0x00, 0xe1, 0xe8, 0xcc, 0xf0, 0x23, 0x00, 0x42, 0xe2, 0x54, 0xba, 0xb9, 0x7c, + 0xe6, 0xbc, 0x6a, 0xb5, 0x8d, 0xb4, 0xb6, 0xa8, 0xd4, 0x16, 0x1d, 0x94, 0xda, 0x0e, 0x1e, 0xe4, + 0x85, 0x7e, 0x5f, 0x76, 0x5a, 0x13, 0x1c, 0xb1, 0x97, 0xbd, 0x69, 0x6c, 0xef, 0xec, 0xaa, 0x63, + 0x38, 0x4b, 0xca, 0x90, 0xbb, 0x43, 0x1b, 0xac, 0xc5, 0x59, 0xe4, 0x92, 0x84, 0xfb, 0x47, 0xc2, + 0x4d, 0x30, 0x0d, 0x5c, 0x3e, 0x26, 0xa9, 0xb9, 0xa0, 0xc4, 0x6c, 0xc5, 0x59, 0xb4, 0xab, 0xa0, + 0x11, 0xa6, 0xc1, 0xdb, 0x31, 0x49, 0xe1, 0x06, 0x58, 0x3e, 0xa4, 0x8c, 0x91, 0xa0, 0x88, 0x31, + 0xff, 0x53, 0x9e, 0x0d, 0x6d, 0xd4, 0xce, 0xf0, 0x04, 0xb4, 0xa6, 0x12, 0x05, 0xae, 0x96, 0x67, + 0xf1, 0xdf, 0xcb, 0xd3, 0xbc, 0x53, 0x45, 0x59, 0x7a, 0xdf, 0x0d, 0x00, 0xf6, 0x52, 0x9e, 0x25, + 0x7a, 0x33, 0x1e, 0x81, 0x95, 0x30, 0xbf, 0xb9, 0x6a, 0xbd, 0xdd, 0xdb, 0x2d, 0x69, 0x84, 0xb7, + 0x3e, 0x43, 0xbd, 0x2f, 0xb1, 0x24, 0x69, 0x8c, 0x99, 0x4b, 0x03, 0x61, 0x56, 0xbb, 0x73, 0xfd, + 0x9a, 0x53, 0x2f, 0x6d, 0xc3, 0x40, 0xc0, 0x37, 0xa0, 0x29, 0x12, 0x46, 0xa5, 0xa4, 0x71, 0xe8, + 0x26, 0x9c, 0x51, 0x7f, 0xa2, 0x56, 0x66, 0x65, 0x7b, 0x03, 0xdd, 0x7f, 0x2d, 0xe8, 0x7d, 0xe9, + 0x3b, 0x52, 0xae, 0xce, 0xaa, 0xf8, 0xdb, 0xd0, 0x3b, 0x35, 0xc0, 0xff, 0xfb, 0xdc, 0x3f, 0xc6, + 0x1e, 0x23, 0xaf, 0x8b, 0x37, 0x23, 0x86, 0xf1, 0x21, 0x87, 0x1c, 0x40, 0x56, 0x00, 0x6e, 0xf9, + 0x9a, 0x84, 0x69, 0x14, 0xe2, 0xcd, 0xce, 0xbc, 0x8c, 0x1d, 0x3c, 0x2e, 0x46, 0xbe, 0xae, 0x47, + 0x7e, 0x3f, 0x45, 0xef, 0x6b, 0x3e, 0xfa, 0x16, 0x9b, 0x2d, 0xfa, 0xe4, 0x15, 0x58, 0x9d, 0x69, + 0x17, 0x02, 0xb0, 0xf0, 0x81, 0xb3, 0x2c, 0x22, 0xcd, 0x0a, 0x5c, 0x06, 0x4b, 0xfb, 0xf4, 0x73, + 0x46, 0x03, 0x2a, 0x27, 0x4d, 0x23, 0x87, 0x76, 0xc7, 0x24, 0x66, 0x93, 0x66, 0xb5, 0x5d, 0x3b, + 0xfd, 0x66, 0x55, 0x06, 0xa3, 0xf3, 0x6b, 0xcb, 0xb8, 0xb8, 0xb6, 0x8c, 0x5f, 0xd7, 0x96, 0x71, + 0x76, 0x63, 0x55, 0x2e, 0x6e, 0xac, 0xca, 0xcf, 0x1b, 0xab, 0xf2, 0xe9, 0xf9, 0x9d, 0x41, 0x16, + 0x22, 0x6d, 0x32, 0xec, 0x89, 0xf2, 0x62, 0x8f, 0xb7, 0x5e, 0xd8, 0x27, 0x77, 0xff, 0x42, 0x6a, + 0xb8, 0xde, 0x82, 0xa2, 0xf7, 0xec, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xef, 0x59, 0x63, 0xaf, + 0xa8, 0x04, 0x00, 0x00, } func (m *Gauge) Marshal() (dAtA []byte, err error) { @@ -413,6 +456,11 @@ func (m *GroupGauge) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.SplittingPolicy != 0 { + i = encodeVarintGauge(dAtA, i, uint64(m.SplittingPolicy)) + i-- + dAtA[i] = 0x18 + } if len(m.InternalIds) > 0 { dAtA4 := make([]byte, len(m.InternalIds)*10) var j3 int @@ -538,6 +586,9 @@ func (m *GroupGauge) Size() (n int) { } n += 1 + sovGauge(uint64(l)) + l } + if m.SplittingPolicy != 0 { + n += 1 + sovGauge(uint64(m.SplittingPolicy)) + } return n } @@ -947,6 +998,25 @@ func (m *GroupGauge) Unmarshal(dAtA []byte) error { } else { return fmt.Errorf("proto: wrong wireType = %d for field InternalIds", wireType) } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SplittingPolicy", wireType) + } + m.SplittingPolicy = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGauge + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.SplittingPolicy |= SplittingPolicy(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipGauge(dAtA[iNdEx:]) From 58dde1a38c368a1621ddb9bc273b7d270a28c46d Mon Sep 17 00:00:00 2001 From: stackman27 Date: Thu, 17 Aug 2023 22:55:36 +0000 Subject: [PATCH 4/7] refactored test --- x/incentives/keeper/distribute_test.go | 160 ++++++++++++++++--------- x/incentives/keeper/keeper_test.go | 1 + 2 files changed, 106 insertions(+), 55 deletions(-) diff --git a/x/incentives/keeper/distribute_test.go b/x/incentives/keeper/distribute_test.go index 9ac2ca0a8c3..1eed7658a7b 100644 --- a/x/incentives/keeper/distribute_test.go +++ b/x/incentives/keeper/distribute_test.go @@ -1,7 +1,6 @@ package keeper_test import ( - "fmt" "strings" "time" @@ -18,6 +17,13 @@ import ( var _ = suite.TestingSuite(nil) +type GroupGaugeCreationFields struct { + coins sdk.Coins + numEpochPaidOver uint64 + owner sdk.AccAddress + internalGaugeIds []uint64 +} + // 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 (s *KeeperTestSuite) TestDistribute() { @@ -1176,112 +1182,156 @@ func (s *KeeperTestSuite) SetupGroupGauge(clPoolId uint64, lockOwner sdk.AccAddr return internalGauges } +func (s *KeeperTestSuite) WithBaseCaseDifferentCoins(baseCase GroupGaugeCreationFields, newCoins sdk.Coins) GroupGaugeCreationFields { + baseCase.coins = newCoins + return baseCase +} + +func (s *KeeperTestSuite) WithBaseCaseDifferentEpochPaidOver(baseCase GroupGaugeCreationFields, numEpochPaidOver uint64) GroupGaugeCreationFields { + baseCase.numEpochPaidOver = numEpochPaidOver + return baseCase +} + +func (s *KeeperTestSuite) WithBaseCaseDifferentInternalGauges(baseCase GroupGaugeCreationFields, internalGauges []uint64) GroupGaugeCreationFields { + baseCase.internalGaugeIds = internalGauges + return baseCase +} + func (s *KeeperTestSuite) TestCreateGroupGaugeAndDistribute() { - type GroupGaugeCreationFields struct { - coins sdk.Coins - numEpochPaidOver uint64 - owner sdk.AccAddress - internalGaugeIds []uint64 + hundredKUosmo := sdk.NewCoin("uosmo", sdk.NewInt(100_000_000)) + hundredKUatom := sdk.NewCoin("uatom", sdk.NewInt(100_000_000)) + fifetyKUosmo := sdk.NewCoin("uosmo", sdk.NewInt(50_000_000)) + fifetyKUatom := sdk.NewCoin("uatom", sdk.NewInt(50_000_000)) + twentyfiveKUosmo := sdk.NewCoin("uosmo", sdk.NewInt(25_000_000)) + twentyfiveKUatom := sdk.NewCoin("uatom", sdk.NewInt(25_000_000)) + + baseCase := &GroupGaugeCreationFields{ + coins: sdk.NewCoins(hundredKUosmo), + numEpochPaidOver: 1, + owner: s.TestAccs[1], + internalGaugeIds: []uint64{2, 3, 4, 5}, } tests := []struct { - name string - createGauge GroupGaugeCreationFields - expectedDistibutionCoinsPerInternalGauge sdk.Coins - expectedTotalDistributedCoinsPerEpoch sdk.Coins + name string + createGauge GroupGaugeCreationFields + expectedCoinsPerInternalGauge sdk.Coins + expectedCoinsDistributedPerEpoch sdk.Coins }{ { - name: "Valid case: Valid perp-GroupGauge Creation and Distribution", - createGauge: GroupGaugeCreationFields{ - coins: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100_000_000))), - numEpochPaidOver: 1, - owner: s.TestAccs[1], - internalGaugeIds: []uint64{2, 3, 4, 5}, - }, - expectedDistibutionCoinsPerInternalGauge: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(25_000_000))), // 100osmo / 4 = 25osmo - expectedTotalDistributedCoinsPerEpoch: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100_000_000))), + name: "Valid case: Valid perp-GroupGauge Creation and Distribution", + createGauge: *baseCase, + expectedCoinsPerInternalGauge: sdk.NewCoins(twentyfiveKUosmo), // 100osmo / 4 = 25osmo + expectedCoinsDistributedPerEpoch: sdk.NewCoins(hundredKUosmo), }, { - name: "Valid case: Valid non-perpGroupGauge Creation with and Distribution", - createGauge: GroupGaugeCreationFields{ - coins: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100_000_000))), - numEpochPaidOver: 4, - owner: s.TestAccs[1], - internalGaugeIds: []uint64{2, 3, 4, 5}, - }, - expectedDistibutionCoinsPerInternalGauge: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(6_250_000))), - expectedTotalDistributedCoinsPerEpoch: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(25_000_000))), + name: "Valid case: Valid perp-GroupGauge Creation with only CL internal gauges and Distribution", + createGauge: s.WithBaseCaseDifferentInternalGauges(*baseCase, []uint64{2, 3, 4}), + expectedCoinsPerInternalGauge: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(33_333_333))), + expectedCoinsDistributedPerEpoch: sdk.NewCoins(hundredKUosmo), }, { - name: "Valid case: Valid GroupGauge Creation with 2 coins and Distribution", - createGauge: GroupGaugeCreationFields{ - coins: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100_000_000)), sdk.NewCoin("uatom", sdk.NewInt(100_000_000))), - numEpochPaidOver: 1, - owner: s.TestAccs[1], - internalGaugeIds: []uint64{2, 3, 4, 5}, - }, - expectedDistibutionCoinsPerInternalGauge: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(25_000_000)), sdk.NewCoin("uatom", sdk.NewInt(25_000_000))), // 100osmo / 4 = 25osmo - expectedTotalDistributedCoinsPerEpoch: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100_000_000)), sdk.NewCoin("uatom", sdk.NewInt(100_000_000))), + name: "Valid case: Valid perp-GroupGauge Creation with only GAMM internal gauge and Distribution", + createGauge: s.WithBaseCaseDifferentInternalGauges(*baseCase, []uint64{5}), + expectedCoinsPerInternalGauge: sdk.NewCoins(hundredKUosmo), + expectedCoinsDistributedPerEpoch: sdk.NewCoins(hundredKUosmo), + }, + { + name: "Valid case: Valid non-perpGroupGauge Creation with and Distribution", + createGauge: s.WithBaseCaseDifferentEpochPaidOver(*baseCase, uint64(4)), + expectedCoinsPerInternalGauge: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(6_250_000))), + expectedCoinsDistributedPerEpoch: sdk.NewCoins(twentyfiveKUosmo), + }, + { + name: "Valid case: Valid perp-GroupGauge Creation with 2 coins and Distribution", + createGauge: s.WithBaseCaseDifferentCoins(*baseCase, sdk.NewCoins(hundredKUosmo, hundredKUatom)), + expectedCoinsPerInternalGauge: sdk.NewCoins(twentyfiveKUosmo, twentyfiveKUatom), + expectedCoinsDistributedPerEpoch: sdk.NewCoins(hundredKUosmo, hundredKUatom), + }, + { + name: "Valid case: Valid non-perp GroupGauge Creation with 2 coins and Distribution", + createGauge: s.WithBaseCaseDifferentEpochPaidOver(s.WithBaseCaseDifferentCoins(*baseCase, sdk.NewCoins(hundredKUosmo, hundredKUatom)), uint64(2)), + expectedCoinsPerInternalGauge: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(12_500_000)), sdk.NewCoin("uatom", sdk.NewInt(12_500_000))), + expectedCoinsDistributedPerEpoch: sdk.NewCoins(fifetyKUosmo, fifetyKUatom), }, - - // { - // name: "Valid case: Valid GroupGauge Creation With Balancer & Cl internalGauges and Distribution", - // }, } for _, tc := range tests { s.Run(tc.name, func() { s.SetupTest() + s.FundAcc(s.TestAccs[1], sdk.NewCoins(hundredKUosmo, hundredKUatom)) // 100osmo, 100atom - s.FundAcc(s.TestAccs[1], sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(1_000_000_000)), sdk.NewCoin("uatom", sdk.NewInt(1_000_000_000)))) // 1,000 osmo + // Setup clPool := s.PrepareConcentratedPool() lockOwner := sdk.AccAddress([]byte("addr1---------------")) + epochInfo := s.App.IncentivesKeeper.GetEpochInfo(s.Ctx) s.SetupGroupGauge(clPool.GetId(), lockOwner, uint64(3), uint64(1)) groupGaugeId, err := s.App.IncentivesKeeper.CreateGroupGauge(s.Ctx, tc.createGauge.coins, tc.createGauge.numEpochPaidOver, tc.createGauge.owner, tc.createGauge.internalGaugeIds) // gauge id = 6 s.Require().NoError(err) - //fmt.Println(groupGaugeId) + groupGaugeObj, err := s.App.IncentivesKeeper.GetGroupGaugeById(s.Ctx, groupGaugeId) + s.Require().NoError(err) - // TODO check internal incentives matches what we created + // check internalGauges matches what we expect + s.Require().Equal(groupGaugeObj.InternalIds, tc.createGauge.internalGaugeIds) - epochInfo := s.App.IncentivesKeeper.GetEpochInfo(s.Ctx) - for i := uint64(1); i <= tc.createGauge.numEpochPaidOver; i++ { + for epoch := uint64(1); epoch <= tc.createGauge.numEpochPaidOver; epoch++ { // ******************** EPOCH PASSED ********************* // s.Ctx = s.Ctx.WithBlockTime(s.Ctx.BlockTime().Add(epochInfo.Duration)) - s.App.EpochsKeeper.AfterEpochEnd(s.Ctx, epochInfo.GetIdentifier(), int64(i)) + s.App.EpochsKeeper.AfterEpochEnd(s.Ctx, epochInfo.GetIdentifier(), int64(epoch)) // Validate GroupGauge groupGauge, err := s.App.IncentivesKeeper.GetGaugeByID(s.Ctx, groupGaugeId) s.Require().NoError(err) - for _, coin := range tc.expectedTotalDistributedCoinsPerEpoch { - s.ValidateDistributedGauge(groupGauge.Id, i, sdk.NewCoins(sdk.NewCoin(coin.Denom, coin.Amount.Mul(sdk.NewIntFromUint64(i))))) + var expectedDistributedCoins []sdk.Coin + for _, coin := range tc.expectedCoinsDistributedPerEpoch { + expectedDistributedCoins = append(expectedDistributedCoins, sdk.NewCoin(coin.Denom, coin.Amount.Mul(sdk.NewIntFromUint64(epoch)))) } + s.ValidateDistributedGauge(groupGauge.Id, epoch, expectedDistributedCoins) + // Validate Internal Gauges internalGauges, err := s.App.IncentivesKeeper.GetGaugeFromIDs(s.Ctx, tc.createGauge.internalGaugeIds) s.Require().NoError(err) for _, internalGauge := range internalGauges { - for _, coin := range tc.expectedDistibutionCoinsPerInternalGauge { - s.ValidateDistributedGauge(internalGauge.Id, i, sdk.NewCoins(sdk.NewCoin(coin.Denom, coin.Amount.Mul(sdk.NewIntFromUint64(i))))) + var expectedDistributedCoinsPerInternalGauge []sdk.Coin + for _, coin := range tc.expectedCoinsPerInternalGauge { + expectedDistributedCoinsPerInternalGauge = append(expectedDistributedCoinsPerInternalGauge, (sdk.NewCoin(coin.Denom, coin.Amount.Mul(sdk.NewIntFromUint64(epoch))))) } + s.ValidateDistributedGauge(internalGauge.Id, epoch, expectedDistributedCoinsPerInternalGauge) } // Validate CL Incentive distribution poolIncentives, err := s.App.ConcentratedLiquidityKeeper.GetAllIncentiveRecordsForPool(s.Ctx, clPool.GetId()) s.Require().NoError(err) - // fmt.Println(poolIncentives) for i := 0; i < len(poolIncentives); i++ { - s.ValidateIncentiveRecord(clPool.GetId(), tc.expectedDistibutionCoinsPerInternalGauge[0], poolIncentives[i]) + idx := 0 + // the logic below is for indexing incentiveRecord, flips idx from 0,1,0,1 or 1,0,1,0 etc. + if len(tc.expectedCoinsPerInternalGauge) > 1 { + if epoch == 2 { + idx = 1 - (i % 2) + } else { + idx = i % 2 + } + } + s.ValidateIncentiveRecord(clPool.GetId(), tc.expectedCoinsPerInternalGauge[idx], poolIncentives[i]) } // Validate GAMM incentive distribution - bal := s.App.BankKeeper.GetAllBalances(s.Ctx, lockOwner) - fmt.Println(bal) + balances := s.App.BankKeeper.GetAllBalances(s.Ctx, lockOwner) + if len(balances) != 0 { + var coins sdk.Coins + for _, bal := range tc.expectedCoinsPerInternalGauge { + coin := sdk.NewCoin(bal.Denom, bal.Amount.Mul(sdk.NewIntFromUint64(epoch))) + coins = append(coins, coin) + } + s.Require().Equal(balances, coins) + } } }) } diff --git a/x/incentives/keeper/keeper_test.go b/x/incentives/keeper/keeper_test.go index 7f5b43dddcd..45580456613 100644 --- a/x/incentives/keeper/keeper_test.go +++ b/x/incentives/keeper/keeper_test.go @@ -39,6 +39,7 @@ func (s *KeeperTestSuite) ValidateDistributedGauge(gaugeID uint64, expectedFille s.Require().NoError(err) s.Require().Equal(expectedFilledEpoch, gauge.FilledEpochs) // Check that distributed coins is not updated + s.Require().Equal(expectedDistributions, gauge.DistributedCoins) } From c99cb1de19308284b9f84184660245572de9bdda Mon Sep 17 00:00:00 2001 From: stackman27 Date: Fri, 18 Aug 2023 07:20:53 +0000 Subject: [PATCH 5/7] alp comments and refactored tests --- x/incentives/keeper/distribute.go | 24 +++-- x/incentives/keeper/distribute_test.go | 132 ++++++++++++++++--------- x/incentives/keeper/gauge.go | 16 ++- x/incentives/keeper/gauge_test.go | 34 ++++++- x/incentives/keeper/keeper_test.go | 26 +++++ x/incentives/keeper/store_test.go | 8 +- 6 files changed, 174 insertions(+), 66 deletions(-) diff --git a/x/incentives/keeper/distribute.go b/x/incentives/keeper/distribute.go index c4f910c7a59..f66d4bbac82 100644 --- a/x/incentives/keeper/distribute.go +++ b/x/incentives/keeper/distribute.go @@ -285,9 +285,9 @@ func (k Keeper) AllocateAcrossGauges(ctx sdk.Context) error { // only allow distribution if the GroupGauge is Active if !currTime.Before(gauge.StartTime) && (gauge.IsPerpetual || gauge.FilledEpochs < gauge.NumEpochsPaidOver) { - coinsToDistributePerInternalGauge, coinsToDistributeThisEpoch := k.CalcSplitPolicyCoins(ctx, groupGauge.SplittingPolicy, gauge, groupGauge) - if coinsToDistributePerInternalGauge == nil || coinsToDistributeThisEpoch == nil { - return fmt.Errorf("GroupGauge id %d doesnot have enought coins to distribute.", groupGauge.GroupGaugeId) + coinsToDistributePerInternalGauge, coinsToDistributeThisEpoch, err := k.CalcSplitPolicyCoins(ctx, groupGauge.SplittingPolicy, gauge, groupGauge) + if err != nil { + return err } for _, internalGaugeId := range groupGauge.InternalIds { @@ -307,24 +307,28 @@ func (k Keeper) AllocateAcrossGauges(ctx sdk.Context) error { } // CalcSplitPolicyCoins calculates tokens to split given a policy and groupGauge. -func (k Keeper) CalcSplitPolicyCoins(ctx sdk.Context, policy types.SplittingPolicy, groupGauge *types.Gauge, groupGaugeObj types.GroupGauge) (sdk.Coins, sdk.Coins) { +func (k Keeper) CalcSplitPolicyCoins(ctx sdk.Context, policy types.SplittingPolicy, groupGauge *types.Gauge, groupGaugeObj types.GroupGauge) (sdk.Coins, sdk.Coins, error) { // TODO: add volume split policy if policy == types.Evenly { remainCoins := groupGauge.Coins.Sub(groupGauge.DistributedCoins) var coinsDistPerInternalGauge, coinsDistThisEpoch sdk.Coins for _, coin := range remainCoins { - amountToDistributeThisEpoch := coin.Amount.Quo(sdk.NewIntFromUint64(groupGauge.NumEpochsPaidOver - groupGauge.FilledEpochs)) - amountToDistributePerInternalGauge := amountToDistributeThisEpoch.Quo(sdk.NewInt(int64(len(groupGaugeObj.InternalIds)))) + epochDiff := groupGauge.NumEpochsPaidOver - groupGauge.FilledEpochs + internalGaugeLen := len(groupGaugeObj.InternalIds) + + distPerEpoch := coin.Amount.Quo(sdk.NewIntFromUint64(epochDiff)) + distPerGauge := distPerEpoch.Quo(sdk.NewInt(int64(internalGaugeLen))) - coinsDistThisEpoch = coinsDistThisEpoch.Add(sdk.NewCoin(coin.Denom, amountToDistributeThisEpoch)) - coinsDistPerInternalGauge = coinsDistPerInternalGauge.Add(sdk.NewCoin(coin.Denom, amountToDistributePerInternalGauge)) + coinsDistThisEpoch = coinsDistThisEpoch.Add(sdk.NewCoin(coin.Denom, distPerEpoch)) + coinsDistPerInternalGauge = coinsDistPerInternalGauge.Add(sdk.NewCoin(coin.Denom, distPerGauge)) } - return coinsDistPerInternalGauge, coinsDistThisEpoch + return coinsDistPerInternalGauge, coinsDistThisEpoch, nil + } else { + return nil, nil, fmt.Errorf("GroupGauge id %d doesnot have enought coins to distribute.", &groupGauge.Id) } - return nil, nil } // distributeInternal runs the distribution logic for a gauge, and adds the sends to diff --git a/x/incentives/keeper/distribute_test.go b/x/incentives/keeper/distribute_test.go index 1eed7658a7b..88eab753bdb 100644 --- a/x/incentives/keeper/distribute_test.go +++ b/x/incentives/keeper/distribute_test.go @@ -1126,60 +1126,78 @@ func (s *KeeperTestSuite) IncentivizeInternalGauge(poolIds []uint64, epochDurati s.Require().NoError(err) } func (s *KeeperTestSuite) TestAllocateAcrossGauges() { - s.SetupTest() - expectedInternalGaugeCoins := sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(33_333_333))) - s.FundAcc(s.TestAccs[1], sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100_000_000)))) // 1,000 osmo - clPool := s.PrepareConcentratedPool() // gaugeid = 1 - - // create 3 internal Gauge - var internalGauges []uint64 - for i := 0; i <= 2; i++ { - internalGauge := s.CreateNoLockExternalGauges(clPool.GetId(), sdk.NewCoins(), s.TestAccs[1], uint64(1)) // gauge id = 2,3,4 - internalGauges = append(internalGauges, internalGauge) + tests := []struct { + name string + GroupGauge types.GroupGauge + expectedAllocationPerGroupGauge sdk.Coins + expectedAllocationPerInternalGauge sdk.Coins + expectError bool + }{ + { + name: "Happy case: Valid perp Group Gauge", + GroupGauge: types.GroupGauge{ + GroupGaugeId: 9, + InternalIds: []uint64{2, 3, 4}, + SplittingPolicy: types.Evenly, + }, + expectedAllocationPerGroupGauge: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100_000_000))), + expectedAllocationPerInternalGauge: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(33_333_333))), + expectError: false, + }, + { + name: "Happy Case: Valid non-perp Group Gauge", + GroupGauge: types.GroupGauge{ + GroupGaugeId: 10, + InternalIds: []uint64{5, 6, 7}, + SplittingPolicy: types.Evenly, + }, + expectedAllocationPerGroupGauge: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(50_000_000))), + expectedAllocationPerInternalGauge: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(16_666_666))), + expectError: false, + }, } - // create group gauge - groupGauge, err := s.App.IncentivesKeeper.CreateGroupGauge(s.Ctx, sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100_000_000))), uint64(1), s.TestAccs[1], internalGauges) // gauge id = 3 - s.Require().NoError(err) - - // Call AllocateAcrossGauges - // Allocate 100 osmo across 3 internal gauges evenly - s.App.IncentivesKeeper.AllocateAcrossGauges(s.Ctx) - - groupGaugePostAllocate, err := s.App.IncentivesKeeper.GetGaugeByID(s.Ctx, groupGauge) - s.Require().NoError(err) + for _, tc := range tests { + s.Run(tc.name, func() { + s.SetupTest() + s.FundAcc(s.TestAccs[1], sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(200_000_000)))) + clPool := s.PrepareConcentratedPool() - s.Require().Equal(groupGaugePostAllocate.Coins.Sub(groupGaugePostAllocate.DistributedCoins), sdk.Coins(nil)) + // create 3 internal Gauge + internalGauges := s.setupNoLockInternalGauge(clPool.GetId(), uint64(6)) // gauge Id = 2,3,4,5,6,7 - for _, gauge := range internalGauges { - internalGauge, err := s.App.IncentivesKeeper.GetGaugeByID(s.Ctx, gauge) - s.Require().NoError(err) + // create non-perp internal Gauge + s.CreateNoLockExternalGauges(clPool.GetId(), sdk.NewCoins(), s.TestAccs[1], uint64(2)) // gaugeid= 8 - s.Require().Equal(internalGauge.Coins.Sub(internalGauge.DistributedCoins), expectedInternalGaugeCoins) - } + // create perp group gauge + _, err := s.App.IncentivesKeeper.CreateGroupGauge(s.Ctx, sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100_000_000))), uint64(1), s.TestAccs[1], internalGauges[:3], lockuptypes.ByGroup, types.Evenly) // gauge id = 2,3,4 + s.Require().NoError(err) -} + // create non-perp group gauge + _, err = s.App.IncentivesKeeper.CreateGroupGauge(s.Ctx, sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100_000_000))), uint64(2), s.TestAccs[1], internalGauges[len(internalGauges)-3:], lockuptypes.ByGroup, types.Evenly) // gauge id = 5,6,7 + s.Require().NoError(err) -func (s *KeeperTestSuite) SetupGroupGauge(clPoolId uint64, lockOwner sdk.AccAddress, numOfNoLockGauges uint64, numOfLockGauges uint64) []uint64 { - var internalGauges []uint64 + // Call Testing function + err = s.App.IncentivesKeeper.AllocateAcrossGauges(s.Ctx) + if tc.expectError { + s.Require().Error(err) + } else { + s.Require().NoError(err) - // create Internal Gauges - for i := uint64(1); i <= numOfNoLockGauges; i++ { - clNoLockGaugeId := s.CreateNoLockExternalGauges(clPoolId, sdk.NewCoins(), s.TestAccs[1], uint64(1)) // gauge id = 2,3,4 - internalGauges = append(internalGauges, clNoLockGaugeId) - } + groupGaugePostAllocate, err := s.App.IncentivesKeeper.GetGaugeByID(s.Ctx, tc.GroupGauge.GroupGaugeId) + s.Require().NoError(err) - for i := uint64(1); i <= numOfLockGauges; i++ { - // setup lock - s.LockTokens(lockOwner, sdk.Coins{sdk.NewInt64Coin("lptoken", 10)}, time.Hour*7) + s.Require().Equal(groupGaugePostAllocate.DistributedCoins, tc.expectedAllocationPerGroupGauge) - // create gauge - gaugeID, _, _, _ := s.SetupNewGauge(true, sdk.NewCoins()) + for _, gauge := range tc.GroupGauge.InternalIds { + internalGauge, err := s.App.IncentivesKeeper.GetGaugeByID(s.Ctx, gauge) + s.Require().NoError(err) - internalGauges = append(internalGauges, gaugeID) + s.Require().Equal(internalGauge.Coins, tc.expectedAllocationPerInternalGauge) + } + } + }) } - - return internalGauges } func (s *KeeperTestSuite) WithBaseCaseDifferentCoins(baseCase GroupGaugeCreationFields, newCoins sdk.Coins) GroupGaugeCreationFields { @@ -1213,10 +1231,12 @@ func (s *KeeperTestSuite) TestCreateGroupGaugeAndDistribute() { } tests := []struct { - name string - createGauge GroupGaugeCreationFields - expectedCoinsPerInternalGauge sdk.Coins - expectedCoinsDistributedPerEpoch sdk.Coins + name string + createGauge GroupGaugeCreationFields + expectedCoinsPerInternalGauge sdk.Coins + expectedCoinsDistributedPerEpoch sdk.Coins + expectCreateGroupGaugeError bool + expectDistributeToInternalGaugeError bool }{ { name: "Valid case: Valid perp-GroupGauge Creation and Distribution", @@ -1254,6 +1274,16 @@ func (s *KeeperTestSuite) TestCreateGroupGaugeAndDistribute() { expectedCoinsPerInternalGauge: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(12_500_000)), sdk.NewCoin("uatom", sdk.NewInt(12_500_000))), expectedCoinsDistributedPerEpoch: sdk.NewCoins(fifetyKUosmo, fifetyKUatom), }, + { + name: "InValid case: Creating a GroupGauge with invalid internalIds", + createGauge: s.WithBaseCaseDifferentInternalGauges(*baseCase, []uint64{100, 101}), + expectCreateGroupGaugeError: true, + }, + { + name: "InValid case: Creating a GroupGauge with non-perpetual internalId", + createGauge: s.WithBaseCaseDifferentInternalGauges(*baseCase, []uint64{2, 3, 4, 6}), + expectCreateGroupGaugeError: true, + }, } for _, tc := range tests { @@ -1267,7 +1297,15 @@ func (s *KeeperTestSuite) TestCreateGroupGaugeAndDistribute() { epochInfo := s.App.IncentivesKeeper.GetEpochInfo(s.Ctx) s.SetupGroupGauge(clPool.GetId(), lockOwner, uint64(3), uint64(1)) - groupGaugeId, err := s.App.IncentivesKeeper.CreateGroupGauge(s.Ctx, tc.createGauge.coins, tc.createGauge.numEpochPaidOver, tc.createGauge.owner, tc.createGauge.internalGaugeIds) // gauge id = 6 + //create 1 non-perp internal Gauge + s.CreateNoLockExternalGauges(clPool.GetId(), sdk.NewCoins(), s.TestAccs[1], uint64(2)) // gauge id = 6 + + groupGaugeId, err := s.App.IncentivesKeeper.CreateGroupGauge(s.Ctx, tc.createGauge.coins, tc.createGauge.numEpochPaidOver, tc.createGauge.owner, tc.createGauge.internalGaugeIds, lockuptypes.ByGroup, types.Evenly) // gauge id = 6 + if tc.expectCreateGroupGaugeError { + s.Require().Error(err) + return + } + s.Require().NoError(err) groupGaugeObj, err := s.App.IncentivesKeeper.GetGroupGaugeById(s.Ctx, groupGaugeId) diff --git a/x/incentives/keeper/gauge.go b/x/incentives/keeper/gauge.go index 26b3540a67f..f140d13eaa7 100644 --- a/x/incentives/keeper/gauge.go +++ b/x/incentives/keeper/gauge.go @@ -211,11 +211,19 @@ func (k Keeper) CreateGauge(ctx sdk.Context, isPerpetual bool, owner sdk.AccAddr // CreateGroupGauge creates a new gauge, that allocates rewards dynamically across its internal gauges based on the given splitting policy. // Note: we should expect that the internal gauges consist of the gauges that are automatically created for each pool upon pool creation, as even non-perpetual // external incentives would likely want to route through these. -func (k Keeper) CreateGroupGauge(ctx sdk.Context, coins sdk.Coins, numEpochPaidOver uint64, owner sdk.AccAddress, internalGaugeIds []uint64) (uint64, error) { +func (k Keeper) CreateGroupGauge(ctx sdk.Context, coins sdk.Coins, numEpochPaidOver uint64, owner sdk.AccAddress, internalGaugeIds []uint64, gaugetype lockuptypes.LockQueryType, splittingPolicy types.SplittingPolicy) (uint64, error) { if len(internalGaugeIds) == 0 { return 0, fmt.Errorf("No internalGauge provided.") } + if gaugetype != lockuptypes.ByGroup { + return 0, fmt.Errorf("Invalid gauge type needs to be ByGroup, got %s.", gaugetype) + } + + if splittingPolicy != types.Evenly { + return 0, fmt.Errorf("Invalid splitting policy, needs to be Evenly got %s", splittingPolicy) + } + // check that all the internalGaugeIds exist internalGauges, err := k.GetGaugeFromIDs(ctx, internalGaugeIds) if err != nil { @@ -235,7 +243,7 @@ func (k Keeper) CreateGroupGauge(ctx sdk.Context, coins sdk.Coins, numEpochPaidO Id: nextGaugeId, IsPerpetual: numEpochPaidOver == 1, DistributeTo: lockuptypes.QueryCondition{ - LockQueryType: lockuptypes.ByGroup, + LockQueryType: gaugetype, }, Coins: coins, StartTime: ctx.BlockTime(), @@ -253,13 +261,13 @@ func (k Keeper) CreateGroupGauge(ctx sdk.Context, coins sdk.Coins, numEpochPaidO newGroupGauge := types.GroupGauge{ GroupGaugeId: nextGaugeId, InternalIds: internalGaugeIds, - SplittingPolicy: types.Evenly, + SplittingPolicy: splittingPolicy, } k.SetGroupGauge(ctx, newGroupGauge) k.SetLastGaugeID(ctx, gauge.Id) - // TODO: check if this is necessary + // TODO: check if this is necessary, will investigate this in following PR. combinedKeys := combineKeys(types.KeyPrefixUpcomingGauges, getTimeKey(gauge.StartTime)) activeOrUpcomingGauge := true diff --git a/x/incentives/keeper/gauge_test.go b/x/incentives/keeper/gauge_test.go index 70e0e788ad0..4a7547d8435 100644 --- a/x/incentives/keeper/gauge_test.go +++ b/x/incentives/keeper/gauge_test.go @@ -590,6 +590,8 @@ func (s *KeeperTestSuite) TestCreateGroupGauge() { coins sdk.Coins numEpochPaidOver uint64 internalGaugeIds []uint64 + gaugeType lockuptypes.LockQueryType + splittiingPolicy types.SplittingPolicy expectErr bool }{ { @@ -597,6 +599,8 @@ func (s *KeeperTestSuite) TestCreateGroupGauge() { coins: coinsToAdd, numEpochPaidOver: 1, internalGaugeIds: []uint64{2, 3, 4}, + gaugeType: lockuptypes.ByGroup, + splittiingPolicy: types.Evenly, expectErr: false, }, @@ -605,6 +609,8 @@ func (s *KeeperTestSuite) TestCreateGroupGauge() { coins: coinsToAdd, numEpochPaidOver: 1, internalGaugeIds: []uint64{2, 3, 4, 5}, + gaugeType: lockuptypes.ByGroup, + splittiingPolicy: types.Evenly, expectErr: true, }, { @@ -612,6 +618,8 @@ func (s *KeeperTestSuite) TestCreateGroupGauge() { coins: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(200_000_000))), numEpochPaidOver: 1, internalGaugeIds: []uint64{2, 3, 4}, + gaugeType: lockuptypes.ByGroup, + splittiingPolicy: types.Evenly, expectErr: true, }, { @@ -619,6 +627,8 @@ func (s *KeeperTestSuite) TestCreateGroupGauge() { coins: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(200_000_000))), numEpochPaidOver: 1, internalGaugeIds: []uint64{2, 3, 4, 5}, + gaugeType: lockuptypes.ByGroup, + splittiingPolicy: types.Evenly, expectErr: true, }, { @@ -626,6 +636,26 @@ func (s *KeeperTestSuite) TestCreateGroupGauge() { coins: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(200_000_000))), numEpochPaidOver: 1, internalGaugeIds: []uint64{}, + splittiingPolicy: types.Evenly, + gaugeType: lockuptypes.ByGroup, + expectErr: true, + }, + { + name: "Error: Invalid Splitting Policy", + coins: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(200_000_000))), + numEpochPaidOver: 1, + internalGaugeIds: []uint64{}, + gaugeType: lockuptypes.ByGroup, + splittiingPolicy: types.Volume, + expectErr: true, + }, + { + name: "Error: Invalid gauge type", + coins: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(200_000_000))), + numEpochPaidOver: 1, + internalGaugeIds: []uint64{}, + gaugeType: lockuptypes.NoLock, + splittiingPolicy: types.Evenly, expectErr: true, }, } @@ -644,7 +674,7 @@ func (s *KeeperTestSuite) TestCreateGroupGauge() { //create 1 non-perp internal Gauge s.CreateNoLockExternalGauges(clPool.GetId(), sdk.NewCoins(), s.TestAccs[1], uint64(2)) // gauge id = 5 - groupGaugeId, err := s.App.IncentivesKeeper.CreateGroupGauge(s.Ctx, tc.coins, tc.numEpochPaidOver, s.TestAccs[1], tc.internalGaugeIds) // gauge id = 6 + groupGaugeId, err := s.App.IncentivesKeeper.CreateGroupGauge(s.Ctx, tc.coins, tc.numEpochPaidOver, s.TestAccs[1], tc.internalGaugeIds, tc.gaugeType, tc.splittiingPolicy) // gauge id = 6 if tc.expectErr { s.Require().Error(err) } else { @@ -719,7 +749,7 @@ func (s *KeeperTestSuite) TestAddToGaugeRewardsFromGauge() { internalGauge1 := s.CreateNoLockExternalGauges(clPool.GetId(), sdk.NewCoins(), s.TestAccs[1], uint64(1)) // gauge id = 2 // create group gauge - _, err := s.App.IncentivesKeeper.CreateGroupGauge(s.Ctx, sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100_000_000))), uint64(1), s.TestAccs[1], []uint64{internalGauge1}) // gauge id = 3 + _, err := s.App.IncentivesKeeper.CreateGroupGauge(s.Ctx, sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100_000_000))), uint64(1), s.TestAccs[1], []uint64{internalGauge1}, lockuptypes.ByGroup, types.Evenly) // gauge id = 3 s.Require().NoError(err) err = s.App.IncentivesKeeper.AddToGaugeRewardsFromGauge(s.Ctx, tc.groupGaugeId, tc.coinsToTransfer, tc.internalGaugeId) diff --git a/x/incentives/keeper/keeper_test.go b/x/incentives/keeper/keeper_test.go index 45580456613..4d17ebcae9c 100644 --- a/x/incentives/keeper/keeper_test.go +++ b/x/incentives/keeper/keeper_test.go @@ -32,6 +32,32 @@ func TestKeeperTestSuite(t *testing.T) { suite.Run(t, new(KeeperTestSuite)) } +func (s *KeeperTestSuite) SetupGroupGauge(clPoolId uint64, lockOwner sdk.AccAddress, numOfNoLockGauges uint64, numOfLockGauges uint64) []uint64 { + internalGauges := s.setupNoLockInternalGauge(clPoolId, numOfNoLockGauges) + + for i := uint64(1); i <= numOfLockGauges; i++ { + // setup lock + s.LockTokens(lockOwner, sdk.Coins{sdk.NewInt64Coin("lptoken", 10)}, time.Hour*7) + + // create gauge + gaugeID, _, _, _ := s.SetupNewGauge(true, sdk.NewCoins()) + internalGauges = append(internalGauges, gaugeID) + } + + return internalGauges +} + +// setupNoLockInternalGauge create no lock perp internal gauges. +func (s *KeeperTestSuite) setupNoLockInternalGauge(poolId uint64, numberOfExistingGauges uint64) []uint64 { + var internalGauges []uint64 + for i := uint64(1); i <= numberOfExistingGauges; i++ { + internalGauge := s.CreateNoLockExternalGauges(poolId, sdk.NewCoins(), s.TestAccs[1], uint64(1)) + internalGauges = append(internalGauges, internalGauge) + } + + return internalGauges +} + // ValidateDistributedGauge checks that the gauge is updated as expected after distribution func (s *KeeperTestSuite) ValidateDistributedGauge(gaugeID uint64, expectedFilledEpoch uint64, expectedDistributions sdk.Coins) { // Check that filled epcohs is not updated diff --git a/x/incentives/keeper/store_test.go b/x/incentives/keeper/store_test.go index b0c2cde73c4..cde6c4b82d6 100644 --- a/x/incentives/keeper/store_test.go +++ b/x/incentives/keeper/store_test.go @@ -5,6 +5,7 @@ import ( "github.com/stretchr/testify/suite" "github.com/osmosis-labs/osmosis/v17/x/incentives/types" + lockuptypes "github.com/osmosis-labs/osmosis/v17/x/lockup/types" ) var _ = suite.TestingSuite(nil) @@ -47,8 +48,9 @@ func (s *KeeperTestSuite) TestGetGroupGaugeById() { "Valid record": { groupGaugeId: uint64(5), expectedRecord: types.GroupGauge{ - GroupGaugeId: uint64(5), - InternalIds: []uint64{2, 3, 4}, + GroupGaugeId: uint64(5), + InternalIds: []uint64{2, 3, 4}, + SplittingPolicy: types.Evenly, }, }, @@ -70,7 +72,7 @@ func (s *KeeperTestSuite) TestGetGroupGaugeById() { internalGauges = append(internalGauges, internalGauge) } - _, err := s.App.IncentivesKeeper.CreateGroupGauge(s.Ctx, sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100_000_000))), 1, s.TestAccs[1], internalGauges) // gauge id = 5 + _, err := s.App.IncentivesKeeper.CreateGroupGauge(s.Ctx, sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(100_000_000))), 1, s.TestAccs[1], internalGauges, lockuptypes.ByGroup, types.Evenly) // gauge id = 5 s.Require().NoError(err) record, err := s.App.IncentivesKeeper.GetGroupGaugeById(s.Ctx, test.groupGaugeId) From 2fe63343582c6616bbdff7047f777c6a04344b9a Mon Sep 17 00:00:00 2001 From: stackman27 Date: Fri, 18 Aug 2023 20:26:41 +0000 Subject: [PATCH 6/7] alp comments --- proto/osmosis/incentives/gauge.proto | 3 +- x/incentives/keeper/distribute.go | 5 +- x/incentives/keeper/gauge.go | 1 + x/incentives/types/gauge.pb.go | 98 +++++++++++++--------------- x/incentives/types/keys.go | 3 +- 5 files changed, 53 insertions(+), 57 deletions(-) diff --git a/proto/osmosis/incentives/gauge.proto b/proto/osmosis/incentives/gauge.proto index 2706d8f345c..4f18a88b90a 100644 --- a/proto/osmosis/incentives/gauge.proto +++ b/proto/osmosis/incentives/gauge.proto @@ -55,8 +55,7 @@ enum SplittingPolicy { option (gogoproto.goproto_enum_prefix) = false; Volume = 0; - Liquidity = 1; - Evenly = 2; + Evenly = 1; } // Gauge is an object that stores GroupGaugeId as well as internalGaugeIds. We diff --git a/x/incentives/keeper/distribute.go b/x/incentives/keeper/distribute.go index f66d4bbac82..f14b1ae98d7 100644 --- a/x/incentives/keeper/distribute.go +++ b/x/incentives/keeper/distribute.go @@ -268,7 +268,6 @@ func (k Keeper) distributeSyntheticInternal( // AllocateAcrossGauges gets all the active groupGauges and distributes tokens evenly based on the internalGauges set for that // groupGauge. After each iteration we update the groupGauge by modifying filledEpoch and distributed coins. -// TODO: Replace even split by volume split once its implemented. func (k Keeper) AllocateAcrossGauges(ctx sdk.Context) error { currTime := ctx.BlockTime() @@ -284,7 +283,7 @@ func (k Keeper) AllocateAcrossGauges(ctx sdk.Context) error { } // only allow distribution if the GroupGauge is Active - if !currTime.Before(gauge.StartTime) && (gauge.IsPerpetual || gauge.FilledEpochs < gauge.NumEpochsPaidOver) { + if gauge.IsActiveGauge(currTime) { coinsToDistributePerInternalGauge, coinsToDistributeThisEpoch, err := k.CalcSplitPolicyCoins(ctx, groupGauge.SplittingPolicy, gauge, groupGauge) if err != nil { return err @@ -505,7 +504,7 @@ func (k Keeper) Distribute(ctx sdk.Context, gauges []types.Gauge) (sdk.Coins, er ctx.Logger().Debug("distributeSyntheticInternal, gauge id %d, %d", "module", types.ModuleName, "gaugeId", gauge.Id, "height", ctx.BlockHeight()) gaugeDistributedCoins, err = k.distributeSyntheticInternal(ctx, gauge, filteredLocks, &distrInfo) } else { - // Donot distribue if LockQueryType = Group, because if we distribute here we will be double distributing. + // Do not distribue if LockQueryType = Group, because if we distribute here we will be double distributing. if gauge.DistributeTo.LockQueryType == lockuptypes.ByGroup { continue } diff --git a/x/incentives/keeper/gauge.go b/x/incentives/keeper/gauge.go index f140d13eaa7..499efbb478d 100644 --- a/x/incentives/keeper/gauge.go +++ b/x/incentives/keeper/gauge.go @@ -220,6 +220,7 @@ func (k Keeper) CreateGroupGauge(ctx sdk.Context, coins sdk.Coins, numEpochPaidO return 0, fmt.Errorf("Invalid gauge type needs to be ByGroup, got %s.", gaugetype) } + // TODO: remove this check once volume splitting is implemented if splittingPolicy != types.Evenly { return 0, fmt.Errorf("Invalid splitting policy, needs to be Evenly got %s", splittingPolicy) } diff --git a/x/incentives/types/gauge.pb.go b/x/incentives/types/gauge.pb.go index 7a12ef1e368..57f9ee718a2 100644 --- a/x/incentives/types/gauge.pb.go +++ b/x/incentives/types/gauge.pb.go @@ -34,21 +34,18 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type SplittingPolicy int32 const ( - Volume SplittingPolicy = 0 - Liquidity SplittingPolicy = 1 - Evenly SplittingPolicy = 2 + Volume SplittingPolicy = 0 + Evenly SplittingPolicy = 1 ) var SplittingPolicy_name = map[int32]string{ 0: "Volume", - 1: "Liquidity", - 2: "Evenly", + 1: "Evenly", } var SplittingPolicy_value = map[string]int32{ - "Volume": 0, - "Liquidity": 1, - "Evenly": 2, + "Volume": 0, + "Evenly": 1, } func (x SplittingPolicy) String() string { @@ -296,50 +293,49 @@ func init() { func init() { proto.RegisterFile("osmosis/incentives/gauge.proto", fileDescriptor_c0304e2bb0159901) } var fileDescriptor_c0304e2bb0159901 = []byte{ - // 676 bytes of a gzipped FileDescriptorProto + // 662 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0x4f, 0x4f, 0xdb, 0x3e, - 0x18, 0x6e, 0x4a, 0xe1, 0x07, 0x6e, 0x81, 0xd6, 0xe2, 0x27, 0x85, 0x4a, 0x4b, 0xbb, 0xb2, 0x49, - 0xd5, 0x24, 0x9c, 0xc1, 0xa4, 0x4d, 0xda, 0x61, 0x87, 0x32, 0x84, 0x2a, 0xa1, 0xad, 0xcb, 0xd0, - 0x34, 0xed, 0x12, 0x39, 0x89, 0x09, 0x16, 0x4e, 0x9c, 0xc5, 0x4e, 0x45, 0xbf, 0x01, 0x47, 0xb4, - 0xd3, 0xee, 0xd3, 0x2e, 0xfb, 0x24, 0x1c, 0x39, 0xee, 0x04, 0x13, 0x7c, 0x83, 0x7d, 0x82, 0x29, - 0x76, 0x42, 0x59, 0xb9, 0xee, 0xe4, 0xf8, 0x7d, 0xde, 0x7f, 0xcf, 0xf3, 0xbe, 0x0e, 0xb0, 0xb8, - 0x88, 0xb8, 0xa0, 0xc2, 0xa6, 0xb1, 0x4f, 0x62, 0x49, 0xc7, 0x44, 0xd8, 0x21, 0xce, 0x42, 0x82, - 0x92, 0x94, 0x4b, 0x0e, 0x61, 0x81, 0xa3, 0x29, 0xde, 0x5e, 0x0b, 0x79, 0xc8, 0x15, 0x6c, 0xe7, - 0x5f, 0xda, 0xb3, 0x6d, 0x85, 0x9c, 0x87, 0x8c, 0xd8, 0xea, 0xe6, 0x65, 0x87, 0x76, 0x90, 0xa5, - 0x58, 0x52, 0x1e, 0x17, 0x78, 0x67, 0x16, 0x97, 0x34, 0x22, 0x42, 0xe2, 0x28, 0x29, 0x13, 0xf8, - 0xaa, 0x96, 0xed, 0x61, 0x41, 0xec, 0xf1, 0x96, 0x47, 0x24, 0xde, 0xb2, 0x7d, 0x4e, 0xcb, 0x04, - 0xeb, 0x65, 0xab, 0x8c, 0xfb, 0xc7, 0x59, 0xa2, 0x0e, 0x0d, 0xf5, 0xbe, 0xd4, 0xc0, 0xfc, 0x5e, - 0xde, 0x35, 0x5c, 0x01, 0x55, 0x1a, 0x98, 0x46, 0xd7, 0xe8, 0xd7, 0x9c, 0x2a, 0x0d, 0xe0, 0x43, - 0xd0, 0xa0, 0xc2, 0x4d, 0x48, 0x9a, 0x10, 0x99, 0x61, 0x66, 0x56, 0xbb, 0x46, 0x7f, 0xd1, 0xa9, - 0x53, 0x31, 0x2a, 0x4d, 0x70, 0x08, 0x96, 0x03, 0x2a, 0x64, 0x4a, 0xbd, 0x4c, 0x12, 0x57, 0x72, - 0x73, 0xae, 0x6b, 0xf4, 0xeb, 0xdb, 0x16, 0x2a, 0xa9, 0xeb, 0x7a, 0xe8, 0x5d, 0x46, 0xd2, 0xc9, - 0x0e, 0x8f, 0x03, 0x9a, 0xb3, 0x1a, 0xd4, 0xce, 0x2f, 0x3b, 0x15, 0xa7, 0x31, 0x0d, 0x3d, 0xe0, - 0x10, 0x83, 0xf9, 0xbc, 0x61, 0x61, 0xd6, 0xba, 0x73, 0xfd, 0xfa, 0xf6, 0x3a, 0xd2, 0x94, 0x50, - 0x4e, 0x09, 0x15, 0x94, 0xd0, 0x0e, 0xa7, 0xf1, 0xe0, 0x69, 0x1e, 0xfd, 0xe3, 0xaa, 0xd3, 0x0f, - 0xa9, 0x3c, 0xca, 0x3c, 0xe4, 0xf3, 0xc8, 0x2e, 0xf8, 0xeb, 0x63, 0x53, 0x04, 0xc7, 0xb6, 0x9c, - 0x24, 0x44, 0xa8, 0x00, 0xe1, 0xe8, 0xcc, 0xf0, 0x23, 0x00, 0x42, 0xe2, 0x54, 0xba, 0xb9, 0x7c, - 0xe6, 0xbc, 0x6a, 0xb5, 0x8d, 0xb4, 0xb6, 0xa8, 0xd4, 0x16, 0x1d, 0x94, 0xda, 0x0e, 0x1e, 0xe4, - 0x85, 0x7e, 0x5f, 0x76, 0x5a, 0x13, 0x1c, 0xb1, 0x97, 0xbd, 0x69, 0x6c, 0xef, 0xec, 0xaa, 0x63, - 0x38, 0x4b, 0xca, 0x90, 0xbb, 0x43, 0x1b, 0xac, 0xc5, 0x59, 0xe4, 0x92, 0x84, 0xfb, 0x47, 0xc2, - 0x4d, 0x30, 0x0d, 0x5c, 0x3e, 0x26, 0xa9, 0xb9, 0xa0, 0xc4, 0x6c, 0xc5, 0x59, 0xb4, 0xab, 0xa0, - 0x11, 0xa6, 0xc1, 0xdb, 0x31, 0x49, 0xe1, 0x06, 0x58, 0x3e, 0xa4, 0x8c, 0x91, 0xa0, 0x88, 0x31, - 0xff, 0x53, 0x9e, 0x0d, 0x6d, 0xd4, 0xce, 0xf0, 0x04, 0xb4, 0xa6, 0x12, 0x05, 0xae, 0x96, 0x67, - 0xf1, 0xdf, 0xcb, 0xd3, 0xbc, 0x53, 0x45, 0x59, 0x7a, 0xdf, 0x0d, 0x00, 0xf6, 0x52, 0x9e, 0x25, - 0x7a, 0x33, 0x1e, 0x81, 0x95, 0x30, 0xbf, 0xb9, 0x6a, 0xbd, 0xdd, 0xdb, 0x2d, 0x69, 0x84, 0xb7, - 0x3e, 0x43, 0xbd, 0x2f, 0xb1, 0x24, 0x69, 0x8c, 0x99, 0x4b, 0x03, 0x61, 0x56, 0xbb, 0x73, 0xfd, - 0x9a, 0x53, 0x2f, 0x6d, 0xc3, 0x40, 0xc0, 0x37, 0xa0, 0x29, 0x12, 0x46, 0xa5, 0xa4, 0x71, 0xe8, - 0x26, 0x9c, 0x51, 0x7f, 0xa2, 0x56, 0x66, 0x65, 0x7b, 0x03, 0xdd, 0x7f, 0x2d, 0xe8, 0x7d, 0xe9, - 0x3b, 0x52, 0xae, 0xce, 0xaa, 0xf8, 0xdb, 0xd0, 0x3b, 0x35, 0xc0, 0xff, 0xfb, 0xdc, 0x3f, 0xc6, - 0x1e, 0x23, 0xaf, 0x8b, 0x37, 0x23, 0x86, 0xf1, 0x21, 0x87, 0x1c, 0x40, 0x56, 0x00, 0x6e, 0xf9, - 0x9a, 0x84, 0x69, 0x14, 0xe2, 0xcd, 0xce, 0xbc, 0x8c, 0x1d, 0x3c, 0x2e, 0x46, 0xbe, 0xae, 0x47, - 0x7e, 0x3f, 0x45, 0xef, 0x6b, 0x3e, 0xfa, 0x16, 0x9b, 0x2d, 0xfa, 0xe4, 0x15, 0x58, 0x9d, 0x69, - 0x17, 0x02, 0xb0, 0xf0, 0x81, 0xb3, 0x2c, 0x22, 0xcd, 0x0a, 0x5c, 0x06, 0x4b, 0xfb, 0xf4, 0x73, - 0x46, 0x03, 0x2a, 0x27, 0x4d, 0x23, 0x87, 0x76, 0xc7, 0x24, 0x66, 0x93, 0x66, 0xb5, 0x5d, 0x3b, - 0xfd, 0x66, 0x55, 0x06, 0xa3, 0xf3, 0x6b, 0xcb, 0xb8, 0xb8, 0xb6, 0x8c, 0x5f, 0xd7, 0x96, 0x71, - 0x76, 0x63, 0x55, 0x2e, 0x6e, 0xac, 0xca, 0xcf, 0x1b, 0xab, 0xf2, 0xe9, 0xf9, 0x9d, 0x41, 0x16, - 0x22, 0x6d, 0x32, 0xec, 0x89, 0xf2, 0x62, 0x8f, 0xb7, 0x5e, 0xd8, 0x27, 0x77, 0xff, 0x42, 0x6a, - 0xb8, 0xde, 0x82, 0xa2, 0xf7, 0xec, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xef, 0x59, 0x63, 0xaf, - 0xa8, 0x04, 0x00, 0x00, + 0x18, 0x6e, 0x4a, 0xe1, 0xc7, 0xcf, 0x2d, 0xd0, 0x5a, 0x4c, 0x0a, 0x95, 0x96, 0x76, 0x65, 0x93, + 0xaa, 0x49, 0xd8, 0x83, 0x49, 0x9b, 0xb4, 0x63, 0x19, 0x42, 0x95, 0xa6, 0xad, 0xeb, 0xd0, 0x34, + 0xed, 0x12, 0x39, 0x89, 0x09, 0x16, 0x4e, 0x1c, 0xc5, 0x4e, 0x45, 0xbf, 0x01, 0x47, 0xb4, 0xd3, + 0xee, 0xd3, 0x2e, 0xfb, 0x24, 0x1c, 0x39, 0xee, 0x04, 0x13, 0x7c, 0x83, 0x7d, 0x82, 0x29, 0x76, + 0x42, 0x59, 0xb9, 0xee, 0x14, 0xfb, 0x7d, 0xde, 0x7f, 0xcf, 0xf3, 0xbe, 0x0e, 0x70, 0x84, 0x8c, + 0x84, 0x64, 0x12, 0xb3, 0xd8, 0xa7, 0xb1, 0x62, 0x13, 0x2a, 0x71, 0x48, 0xb2, 0x90, 0xa2, 0x24, + 0x15, 0x4a, 0x40, 0x58, 0xe0, 0x68, 0x86, 0xb7, 0xd7, 0x43, 0x11, 0x0a, 0x0d, 0xe3, 0xfc, 0x64, + 0x3c, 0xdb, 0x4e, 0x28, 0x44, 0xc8, 0x29, 0xd6, 0x37, 0x2f, 0x3b, 0xc4, 0x41, 0x96, 0x12, 0xc5, + 0x44, 0x5c, 0xe0, 0x9d, 0x79, 0x5c, 0xb1, 0x88, 0x4a, 0x45, 0xa2, 0xa4, 0x4c, 0xe0, 0xeb, 0x5a, + 0xd8, 0x23, 0x92, 0xe2, 0xc9, 0xb6, 0x47, 0x15, 0xd9, 0xc6, 0xbe, 0x60, 0x65, 0x82, 0x8d, 0xb2, + 0x55, 0x2e, 0xfc, 0xe3, 0x2c, 0xd1, 0x1f, 0x03, 0xf5, 0xbe, 0xd4, 0xc0, 0xe2, 0x7e, 0xde, 0x35, + 0x5c, 0x05, 0x55, 0x16, 0xd8, 0x56, 0xd7, 0xea, 0xd7, 0xc6, 0x55, 0x16, 0xc0, 0x47, 0xa0, 0xc1, + 0xa4, 0x9b, 0xd0, 0x34, 0xa1, 0x2a, 0x23, 0xdc, 0xae, 0x76, 0xad, 0xfe, 0xf2, 0xb8, 0xce, 0xe4, + 0xa8, 0x34, 0xc1, 0x21, 0x58, 0x09, 0x98, 0x54, 0x29, 0xf3, 0x32, 0x45, 0x5d, 0x25, 0xec, 0x85, + 0xae, 0xd5, 0xaf, 0xef, 0x38, 0xa8, 0xa4, 0x6e, 0xea, 0xa1, 0xf7, 0x19, 0x4d, 0xa7, 0xbb, 0x22, + 0x0e, 0x58, 0xce, 0x6a, 0x50, 0x3b, 0xbf, 0xec, 0x54, 0xc6, 0x8d, 0x59, 0xe8, 0x81, 0x80, 0x04, + 0x2c, 0xe6, 0x0d, 0x4b, 0xbb, 0xd6, 0x5d, 0xe8, 0xd7, 0x77, 0x36, 0x90, 0xa1, 0x84, 0x72, 0x4a, + 0xa8, 0xa0, 0x84, 0x76, 0x05, 0x8b, 0x07, 0xcf, 0xf2, 0xe8, 0x1f, 0x57, 0x9d, 0x7e, 0xc8, 0xd4, + 0x51, 0xe6, 0x21, 0x5f, 0x44, 0xb8, 0xe0, 0x6f, 0x3e, 0x5b, 0x32, 0x38, 0xc6, 0x6a, 0x9a, 0x50, + 0xa9, 0x03, 0xe4, 0xd8, 0x64, 0x86, 0x9f, 0x00, 0x90, 0x8a, 0xa4, 0xca, 0xcd, 0xe5, 0xb3, 0x17, + 0x75, 0xab, 0x6d, 0x64, 0xb4, 0x45, 0xa5, 0xb6, 0xe8, 0xa0, 0xd4, 0x76, 0xf0, 0x30, 0x2f, 0xf4, + 0xfb, 0xb2, 0xd3, 0x9a, 0x92, 0x88, 0xbf, 0xea, 0xcd, 0x62, 0x7b, 0x67, 0x57, 0x1d, 0x6b, 0xfc, + 0xbf, 0x36, 0xe4, 0xee, 0x10, 0x83, 0xf5, 0x38, 0x8b, 0x5c, 0x9a, 0x08, 0xff, 0x48, 0xba, 0x09, + 0x61, 0x81, 0x2b, 0x26, 0x34, 0xb5, 0x97, 0xb4, 0x98, 0xad, 0x38, 0x8b, 0xf6, 0x34, 0x34, 0x22, + 0x2c, 0x78, 0x37, 0xa1, 0x29, 0xdc, 0x04, 0x2b, 0x87, 0x8c, 0x73, 0x1a, 0x14, 0x31, 0xf6, 0x7f, + 0xda, 0xb3, 0x61, 0x8c, 0xc6, 0x19, 0x9e, 0x80, 0xd6, 0x4c, 0xa2, 0xc0, 0x35, 0xf2, 0x2c, 0xff, + 0x7b, 0x79, 0x9a, 0x77, 0xaa, 0x68, 0x4b, 0xef, 0xbb, 0x05, 0xc0, 0x7e, 0x2a, 0xb2, 0xc4, 0x6c, + 0xc6, 0x63, 0xb0, 0x1a, 0xe6, 0x37, 0x57, 0xaf, 0xb7, 0x7b, 0xbb, 0x25, 0x8d, 0xf0, 0xd6, 0x67, + 0x68, 0xf6, 0x25, 0x56, 0x34, 0x8d, 0x09, 0x77, 0x59, 0x20, 0xed, 0x6a, 0x77, 0xa1, 0x5f, 0x1b, + 0xd7, 0x4b, 0xdb, 0x30, 0x90, 0xf0, 0x2d, 0x68, 0xca, 0x84, 0x33, 0xa5, 0x58, 0x1c, 0xba, 0x89, + 0xe0, 0xcc, 0x9f, 0xea, 0x95, 0x59, 0xdd, 0xd9, 0x44, 0xf7, 0x5f, 0x0b, 0xfa, 0x50, 0xfa, 0x8e, + 0xb4, 0xeb, 0x78, 0x4d, 0xfe, 0x6d, 0xe8, 0x9d, 0x5a, 0xe0, 0xc1, 0x1b, 0xe1, 0x1f, 0x13, 0x8f, + 0xd3, 0xd7, 0xc5, 0x9b, 0x91, 0xc3, 0xf8, 0x50, 0x40, 0x01, 0x20, 0x2f, 0x00, 0xb7, 0x7c, 0x4d, + 0xd2, 0xb6, 0x0a, 0xf1, 0xe6, 0x67, 0x5e, 0xc6, 0x0e, 0x9e, 0x14, 0x23, 0xdf, 0x30, 0x23, 0xbf, + 0x9f, 0xa2, 0xf7, 0x35, 0x1f, 0x7d, 0x8b, 0xcf, 0x17, 0x7d, 0x8a, 0xc1, 0xda, 0x5c, 0xbb, 0x10, + 0x80, 0xa5, 0x8f, 0x82, 0x67, 0x11, 0x6d, 0x56, 0xf2, 0xf3, 0xde, 0x84, 0xc6, 0x7c, 0xda, 0xb4, + 0xda, 0xb5, 0xd3, 0x6f, 0x4e, 0x65, 0x30, 0x3a, 0xbf, 0x76, 0xac, 0x8b, 0x6b, 0xc7, 0xfa, 0x75, + 0xed, 0x58, 0x67, 0x37, 0x4e, 0xe5, 0xe2, 0xc6, 0xa9, 0xfc, 0xbc, 0x71, 0x2a, 0x9f, 0x5f, 0xdc, + 0x99, 0x5c, 0xa1, 0xca, 0x16, 0x27, 0x9e, 0x2c, 0x2f, 0x78, 0xb2, 0xfd, 0x12, 0x9f, 0xdc, 0xfd, + 0xed, 0xe8, 0x69, 0x7a, 0x4b, 0x9a, 0xcf, 0xf3, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x00, 0x40, + 0x27, 0xeb, 0x99, 0x04, 0x00, 0x00, } func (m *Gauge) Marshal() (dAtA []byte, err error) { diff --git a/x/incentives/types/keys.go b/x/incentives/types/keys.go index 5654687c900..fe85d4f8652 100644 --- a/x/incentives/types/keys.go +++ b/x/incentives/types/keys.go @@ -70,5 +70,6 @@ func NoLockInternalGaugeDenom(poolId uint64) string { // KeyGroupGaugeForId returns key for a given groupGaugeId. func KeyGroupGaugeForId(groupGaugeId uint64) []byte { - return []byte(fmt.Sprintf("%s%s%d%s", "group_gauge", "|", groupGaugeId, "|")) + return []byte(fmt.Sprintf("%s%s%d%s", GroupGaugePrefix, "|", groupGaugeId, "|")) + } From cad538f9cad7fa2b71d144d161cefae05d60251b Mon Sep 17 00:00:00 2001 From: stackman27 Date: Fri, 18 Aug 2023 20:27:49 +0000 Subject: [PATCH 7/7] nits --- x/incentives/keeper/distribute.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/x/incentives/keeper/distribute.go b/x/incentives/keeper/distribute.go index f14b1ae98d7..b599b40eb71 100644 --- a/x/incentives/keeper/distribute.go +++ b/x/incentives/keeper/distribute.go @@ -284,7 +284,7 @@ func (k Keeper) AllocateAcrossGauges(ctx sdk.Context) error { // only allow distribution if the GroupGauge is Active if gauge.IsActiveGauge(currTime) { - coinsToDistributePerInternalGauge, coinsToDistributeThisEpoch, err := k.CalcSplitPolicyCoins(ctx, groupGauge.SplittingPolicy, gauge, groupGauge) + coinsToDistributePerInternalGauge, coinsToDistributeThisEpoch, err := k.calcSplitPolicyCoins(ctx, groupGauge.SplittingPolicy, gauge, groupGauge) if err != nil { return err } @@ -305,9 +305,9 @@ func (k Keeper) AllocateAcrossGauges(ctx sdk.Context) error { return nil } -// CalcSplitPolicyCoins calculates tokens to split given a policy and groupGauge. -func (k Keeper) CalcSplitPolicyCoins(ctx sdk.Context, policy types.SplittingPolicy, groupGauge *types.Gauge, groupGaugeObj types.GroupGauge) (sdk.Coins, sdk.Coins, error) { - // TODO: add volume split policy +// calcSplitPolicyCoins calculates tokens to split given a policy and groupGauge. +// TODO: add volume split policy +func (k Keeper) calcSplitPolicyCoins(ctx sdk.Context, policy types.SplittingPolicy, groupGauge *types.Gauge, groupGaugeObj types.GroupGauge) (sdk.Coins, sdk.Coins, error) { if policy == types.Evenly { remainCoins := groupGauge.Coins.Sub(groupGauge.DistributedCoins)