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)