-
Notifications
You must be signed in to change notification settings - Fork 608
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Uptime Incentives]: Incorporate gov param in distribution logic #7419
Changes from all commits
fc05777
a855eab
48fb452
16dacb0
bed822b
650696b
83356f9
0a97633
3554d12
a914960
c861e7a
db4d377
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -251,45 +251,84 @@ func (s *KeeperTestSuite) TestDistribute_InternalIncentives_NoLock() { | |
tokensToAddToGauge sdk.Coins | ||
gaugeStartTime time.Time | ||
gaugeCoins sdk.Coins | ||
internalUptime time.Duration | ||
|
||
// expected | ||
expectErr bool | ||
// Note: internal gauge distributions should never error, so we don't expect any errors here. | ||
expectedDistributions sdk.Coins | ||
expectedUptime time.Duration | ||
}{ | ||
"valid case: one poolId and gaugeId": { | ||
numPools: 1, | ||
gaugeStartTime: defaultGaugeStartTime, | ||
gaugeCoins: sdk.NewCoins(fiveKRewardCoins), | ||
"one poolId and gaugeId": { | ||
numPools: 1, | ||
gaugeStartTime: defaultGaugeStartTime, | ||
gaugeCoins: sdk.NewCoins(fiveKRewardCoins), | ||
internalUptime: types.DefaultConcentratedUptime, | ||
|
||
expectedUptime: types.DefaultConcentratedUptime, | ||
expectedDistributions: sdk.NewCoins(fiveKRewardCoins), | ||
expectErr: false, | ||
}, | ||
"valid case: gauge with multiple coins": { | ||
numPools: 1, | ||
gaugeStartTime: defaultGaugeStartTime, | ||
gaugeCoins: sdk.NewCoins(fiveKRewardCoins, fiveKRewardCoinsUosmo), | ||
"gauge with multiple coins": { | ||
numPools: 1, | ||
gaugeStartTime: defaultGaugeStartTime, | ||
gaugeCoins: sdk.NewCoins(fiveKRewardCoins, fiveKRewardCoinsUosmo), | ||
internalUptime: types.DefaultConcentratedUptime, | ||
|
||
expectedUptime: types.DefaultConcentratedUptime, | ||
expectedDistributions: sdk.NewCoins(fiveKRewardCoins, fiveKRewardCoinsUosmo), | ||
expectErr: false, | ||
}, | ||
"valid case: multiple gaugeId and poolId": { | ||
numPools: 3, | ||
gaugeStartTime: defaultGaugeStartTime, | ||
gaugeCoins: sdk.NewCoins(fiveKRewardCoins), | ||
"multiple gaugeId and poolId": { | ||
numPools: 3, | ||
gaugeStartTime: defaultGaugeStartTime, | ||
gaugeCoins: sdk.NewCoins(fiveKRewardCoins), | ||
internalUptime: types.DefaultConcentratedUptime, | ||
|
||
expectedUptime: types.DefaultConcentratedUptime, | ||
expectedDistributions: sdk.NewCoins(fifteenKRewardCoins), | ||
expectErr: false, | ||
}, | ||
"valid case: one poolId and gaugeId, five 5000 coins": { | ||
numPools: 1, | ||
gaugeStartTime: defaultGaugeStartTime, | ||
gaugeCoins: sdk.NewCoins(fiveKRewardCoins), | ||
"one poolId and gaugeId, five 5000 coins": { | ||
numPools: 1, | ||
gaugeStartTime: defaultGaugeStartTime, | ||
gaugeCoins: sdk.NewCoins(fiveKRewardCoins), | ||
internalUptime: types.DefaultConcentratedUptime, | ||
|
||
expectedUptime: types.DefaultConcentratedUptime, | ||
expectedDistributions: sdk.NewCoins(fiveKRewardCoins), | ||
expectErr: false, | ||
}, | ||
"valid case: attempt to createIncentiveRecord with start time < currentBlockTime - gets set to block time in incentive record": { | ||
numPools: 1, | ||
gaugeStartTime: defaultGaugeStartTime.Add(-5 * time.Hour), | ||
gaugeCoins: sdk.NewCoins(fiveKRewardCoins), | ||
"attempt to createIncentiveRecord with start time < currentBlockTime - gets set to block time in incentive record": { | ||
numPools: 1, | ||
gaugeStartTime: defaultGaugeStartTime.Add(-5 * time.Hour), | ||
gaugeCoins: sdk.NewCoins(fiveKRewardCoins), | ||
internalUptime: types.DefaultConcentratedUptime, | ||
|
||
expectedUptime: types.DefaultConcentratedUptime, | ||
expectedDistributions: sdk.NewCoins(fiveKRewardCoins), | ||
expectErr: false, | ||
}, | ||
// We expect incentive record to fall back to the default uptime, since the internal uptime is unauthorized. | ||
"unauthorized internal uptime": { | ||
numPools: 3, | ||
gaugeStartTime: defaultGaugeStartTime, | ||
gaugeCoins: sdk.NewCoins(fiveKRewardCoins), | ||
internalUptime: time.Hour * 24 * 7, | ||
|
||
expectedUptime: types.DefaultConcentratedUptime, | ||
expectedDistributions: sdk.NewCoins(fifteenKRewardCoins), | ||
}, | ||
"invalid internal uptime": { | ||
numPools: 3, | ||
gaugeStartTime: defaultGaugeStartTime, | ||
gaugeCoins: sdk.NewCoins(fiveKRewardCoins), | ||
internalUptime: time.Hour * 4, | ||
|
||
expectedUptime: types.DefaultConcentratedUptime, | ||
expectedDistributions: sdk.NewCoins(fifteenKRewardCoins), | ||
}, | ||
"nil internal uptime": { | ||
numPools: 3, | ||
gaugeStartTime: defaultGaugeStartTime, | ||
gaugeCoins: sdk.NewCoins(fiveKRewardCoins), | ||
|
||
expectedUptime: types.DefaultConcentratedUptime, | ||
expectedDistributions: sdk.NewCoins(fifteenKRewardCoins), | ||
}, | ||
} | ||
|
||
|
@@ -301,6 +340,9 @@ func (s *KeeperTestSuite) TestDistribute_InternalIncentives_NoLock() { | |
// We fix blocktime to ensure tests are deterministic | ||
s.Ctx = s.Ctx.WithBlockTime(defaultGaugeStartTime) | ||
|
||
// Set internal uptime module param as defined in test case | ||
s.App.IncentivesKeeper.SetParam(s.Ctx, types.KeyInternalUptime, tc.internalUptime) | ||
|
||
var gauges []types.Gauge | ||
|
||
// prepare the minting account | ||
|
@@ -334,73 +376,51 @@ func (s *KeeperTestSuite) TestDistribute_InternalIncentives_NoLock() { | |
gauges = append(gauges, *gauge) | ||
} | ||
|
||
// Distribute tokens from the gauge | ||
// System under test: Distribute tokens from the gauge | ||
totalDistributedCoins, err := s.App.IncentivesKeeper.Distribute(s.Ctx, gauges) | ||
if tc.expectErr { | ||
s.Require().Error(err) | ||
|
||
// module account amount must stay the same | ||
balance := s.App.BankKeeper.GetAllBalances(s.Ctx, s.App.AccountKeeper.GetModuleAddress(types.ModuleName)) | ||
s.Require().Equal(coinsToMint, balance) | ||
|
||
for i, gauge := range gauges { | ||
for j := range gauge.Coins { | ||
incentiveId := i*len(gauge.Coins) + j + 1 | ||
|
||
// get poolId from GaugeId | ||
poolId, err := s.App.PoolIncentivesKeeper.GetPoolIdFromGaugeId(s.Ctx, gauge.GetId(), currentEpoch.Duration) | ||
s.Require().NoError(err) | ||
|
||
// check that incentive record wasn't created | ||
_, err = s.App.ConcentratedLiquidityKeeper.GetIncentiveRecord(s.Ctx, poolId, currentEpoch.Duration, uint64(incentiveId)) | ||
s.Require().Error(err) | ||
} | ||
} | ||
} else { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. After a couple cleanup attempts, it seems a messed up diff is unavoidable here. The core changes are:
Note: i made the changes for 1 in a separate commit in case we want to revert. I find this version of the tests to be much less verbose & more readable, but on the fence on this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is fine to me imo |
||
s.Require().NoError(err) | ||
s.Require().NoError(err) | ||
|
||
// check that gauge is not empty | ||
s.Require().NotEqual(len(gauges), 0) | ||
// check that gauge is not empty | ||
s.Require().NotEqual(len(gauges), 0) | ||
|
||
// check if module amount got deducted correctly | ||
balance := s.App.BankKeeper.GetAllBalances(s.Ctx, s.App.AccountKeeper.GetModuleAddress(types.ModuleName)) | ||
for _, coin := range balance { | ||
actualbalanceAfterDistribution := coinsToMint.AmountOf(coin.Denom).Sub(coin.Amount) | ||
s.Require().Equal(tc.expectedDistributions.AmountOf(coin.Denom).Add(osmomath.ZeroInt()), actualbalanceAfterDistribution.Add(osmomath.ZeroInt())) | ||
} | ||
// check if module amount got deducted correctly | ||
balance := s.App.BankKeeper.GetAllBalances(s.Ctx, s.App.AccountKeeper.GetModuleAddress(types.ModuleName)) | ||
for _, coin := range balance { | ||
actualbalanceAfterDistribution := coinsToMint.AmountOf(coin.Denom).Sub(coin.Amount) | ||
s.Require().Equal(tc.expectedDistributions.AmountOf(coin.Denom).Add(osmomath.ZeroInt()), actualbalanceAfterDistribution.Add(osmomath.ZeroInt())) | ||
} | ||
|
||
for i, gauge := range gauges { | ||
for j, coin := range gauge.Coins { | ||
incentiveId := i*len(gauge.Coins) + j + 1 | ||
for i, gauge := range gauges { | ||
for j, coin := range gauge.Coins { | ||
incentiveId := i*len(gauge.Coins) + j + 1 | ||
|
||
gaugeId := gauge.GetId() | ||
gaugeId := gauge.GetId() | ||
|
||
// get poolId from GaugeId | ||
poolId, err := s.App.PoolIncentivesKeeper.GetPoolIdFromGaugeId(s.Ctx, gaugeId, currentEpoch.Duration) | ||
s.Require().NoError(err) | ||
// get poolId from GaugeId | ||
poolId, err := s.App.PoolIncentivesKeeper.GetPoolIdFromGaugeId(s.Ctx, gaugeId, currentEpoch.Duration) | ||
s.Require().NoError(err) | ||
|
||
// GetIncentiveRecord to see if pools received incentives properly | ||
incentiveRecord, err := s.App.ConcentratedLiquidityKeeper.GetIncentiveRecord(s.Ctx, poolId, types.DefaultConcentratedUptime, uint64(incentiveId)) | ||
s.Require().NoError(err) | ||
// GetIncentiveRecord to see if pools received incentives properly | ||
incentiveRecord, err := s.App.ConcentratedLiquidityKeeper.GetIncentiveRecord(s.Ctx, poolId, tc.expectedUptime, uint64(incentiveId)) | ||
s.Require().NoError(err) | ||
|
||
expectedEmissionRate := osmomath.NewDecFromInt(coin.Amount).QuoTruncate(osmomath.NewDec(int64(currentEpoch.Duration.Seconds()))) | ||
expectedEmissionRate := osmomath.NewDecFromInt(coin.Amount).QuoTruncate(osmomath.NewDec(int64(currentEpoch.Duration.Seconds()))) | ||
|
||
// Check that gauge distribution state is updated. | ||
s.ValidateDistributedGauge(gaugeId, 1, tc.gaugeCoins) | ||
// Check that gauge distribution state is updated. | ||
s.ValidateDistributedGauge(gaugeId, 1, tc.gaugeCoins) | ||
|
||
// check every parameter in incentiveRecord so that it matches what we created | ||
incentiveRecordBody := incentiveRecord.GetIncentiveRecordBody() | ||
s.Require().Equal(poolId, incentiveRecord.PoolId) | ||
s.Require().Equal(expectedEmissionRate, incentiveRecordBody.EmissionRate) | ||
s.Require().Equal(s.Ctx.BlockTime().UTC().String(), incentiveRecordBody.StartTime.UTC().String()) | ||
s.Require().Equal(types.DefaultConcentratedUptime, incentiveRecord.MinUptime) | ||
s.Require().Equal(coin.Amount, incentiveRecordBody.RemainingCoin.Amount.TruncateInt()) | ||
s.Require().Equal(coin.Denom, incentiveRecordBody.RemainingCoin.Denom) | ||
} | ||
// check every parameter in incentiveRecord so that it matches what we created | ||
incentiveRecordBody := incentiveRecord.GetIncentiveRecordBody() | ||
s.Require().Equal(poolId, incentiveRecord.PoolId) | ||
s.Require().Equal(expectedEmissionRate, incentiveRecordBody.EmissionRate) | ||
s.Require().Equal(s.Ctx.BlockTime().UTC().String(), incentiveRecordBody.StartTime.UTC().String()) | ||
s.Require().Equal(tc.expectedUptime, incentiveRecord.MinUptime) | ||
s.Require().Equal(coin.Amount, incentiveRecordBody.RemainingCoin.Amount.TruncateInt()) | ||
s.Require().Equal(coin.Denom, incentiveRecordBody.RemainingCoin.Denom) | ||
} | ||
// check the totalAmount of tokens distributed, for both lock gauges and CL pool gauges | ||
s.Require().Equal(tc.expectedDistributions, totalDistributedCoins) | ||
} | ||
// check the totalAmount of tokens distributed, for both lock gauges and CL pool gauges | ||
s.Require().Equal(tc.expectedDistributions, totalDistributedCoins) | ||
}) | ||
} | ||
} | ||
|
@@ -2453,9 +2473,11 @@ func (s *KeeperTestSuite) TestHandleGroupPostDistribute() { | |
} | ||
|
||
func (s *KeeperTestSuite) TestGetNoLockGaugeUptime() { | ||
defaultPoolId := uint64(1) | ||
tests := map[string]struct { | ||
gauge types.Gauge | ||
authorizedUptimes []time.Duration | ||
internalUptime time.Duration | ||
expectedUptime time.Duration | ||
}{ | ||
"external gauge with authorized uptime": { | ||
|
@@ -2472,17 +2494,47 @@ func (s *KeeperTestSuite) TestGetNoLockGaugeUptime() { | |
authorizedUptimes: []time.Duration{types.DefaultConcentratedUptime}, | ||
expectedUptime: types.DefaultConcentratedUptime, | ||
}, | ||
"internal gauge with authorized uptime": { | ||
gauge: types.Gauge{ | ||
DistributeTo: lockuptypes.QueryCondition{ | ||
Denom: types.NoLockInternalGaugeDenom(defaultPoolId), | ||
Duration: time.Hour, | ||
}, | ||
}, | ||
authorizedUptimes: []time.Duration{types.DefaultConcentratedUptime, time.Hour}, | ||
internalUptime: time.Hour, | ||
expectedUptime: time.Hour, | ||
}, | ||
"internal gauge with unauthorized uptime": { | ||
gauge: types.Gauge{ | ||
DistributeTo: lockuptypes.QueryCondition{ | ||
Denom: types.NoLockInternalGaugeDenom(defaultPoolId), | ||
Duration: time.Hour, | ||
}, | ||
}, | ||
authorizedUptimes: []time.Duration{types.DefaultConcentratedUptime}, | ||
internalUptime: time.Hour, | ||
expectedUptime: types.DefaultConcentratedUptime, | ||
}, | ||
} | ||
|
||
for name, tc := range tests { | ||
s.Run(name, func() { | ||
// Prepare CL pool | ||
clPool := s.PrepareConcentratedPool() | ||
|
||
// Setup CL params with authorized uptimes | ||
clParams := s.App.ConcentratedLiquidityKeeper.GetParams(s.Ctx) | ||
clParams.AuthorizedUptimes = tc.authorizedUptimes | ||
s.App.ConcentratedLiquidityKeeper.SetParams(s.Ctx, clParams) | ||
|
||
// Set internal uptime module param if applicable | ||
if tc.internalUptime != time.Duration(0) { | ||
s.App.IncentivesKeeper.SetParam(s.Ctx, types.KeyInternalUptime, tc.internalUptime) | ||
} | ||
|
||
// System under test | ||
actualUptime := s.App.IncentivesKeeper.GetNoLockGaugeUptime(s.Ctx, tc.gauge) | ||
actualUptime := s.App.IncentivesKeeper.GetNoLockGaugeUptime(s.Ctx, tc.gauge, clPool.GetId()) | ||
|
||
// Ensure correct uptime was returned | ||
s.Require().Equal(tc.expectedUptime, actualUptime) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: diff is a bit messy due to driveby test case renaming/removal of
expectErr: false
s. Happy to undo either of these if anyone has strong qualms.