Skip to content

Commit

Permalink
Re[CL:Incentives] Add further tests to uptime accumulator update logic (
Browse files Browse the repository at this point in the history
#4370)

* all test

* added extra test

* fixed comments
  • Loading branch information
stackman27 authored Feb 23, 2023
1 parent 146b800 commit dd76980
Show file tree
Hide file tree
Showing 2 changed files with 185 additions and 0 deletions.
4 changes: 4 additions & 0 deletions x/concentrated-liquidity/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,3 +209,7 @@ func (k Keeper) SetIncentiveRecord(ctx sdk.Context, incentiveRecord types.Incent
func (k Keeper) SetMultipleIncentiveRecords(ctx sdk.Context, incentiveRecords []types.IncentiveRecord) {
k.setMultipleIncentiveRecords(ctx, incentiveRecords)
}

func (k Keeper) GetInitialUptimeGrowthOutsidesForTick(ctx sdk.Context, poolId uint64, tick int64) ([]sdk.DecCoins, error) {
return k.getInitialUptimeGrowthOutsidesForTick(ctx, poolId, tick)
}
181 changes: 181 additions & 0 deletions x/concentrated-liquidity/incentives_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,34 @@ func chargeIncentive(incentiveRecord types.IncentiveRecord, timeElapsed time.Dur
return incentiveRecord
}

func createIncentiveRecord(incentiveDenom string, remainingAmt, emissionRate sdk.Dec, startTime time.Time, minUpTime time.Duration) types.IncentiveRecord {
return types.IncentiveRecord{
IncentiveDenom: incentiveDenom,
RemainingAmount: remainingAmt,
EmissionRate: emissionRate,
StartTime: startTime,
MinUptime: minUpTime,
}
}

func withDenom(record types.IncentiveRecord, denom string) types.IncentiveRecord {
record.IncentiveDenom = denom

return record
}

func withStartTime(record types.IncentiveRecord, startTime time.Time) types.IncentiveRecord {
record.StartTime = startTime

return record
}

func withMinUpTimeTime(record types.IncentiveRecord, minUpTime time.Duration) types.IncentiveRecord {
record.MinUptime = minUpTime

return record
}

func (s *KeeperTestSuite) TestCreateAndGetUptimeAccumulators() {
// We expect there to be len(types.SupportedUptimes) number of initialized accumulators
// for a successful pool creation. We calculate this upfront to ensure test compatibility
Expand Down Expand Up @@ -363,6 +391,10 @@ func (s *KeeperTestSuite) TestCreateAndGetUptimeAccumulatorValues() {
}

func (s *KeeperTestSuite) TestCalcAccruedIncentivesForAccum() {
incentiveRecordOneWithDifferentStartTime := withStartTime(incentiveRecordOne, incentiveRecordOne.StartTime.Add(10))
incentiveRecordOneWithDifferentMinUpTime := withMinUpTimeTime(incentiveRecordOne, testUptimeTwo)
incentiveRecordOneWithDifferentDenom := withDenom(incentiveRecordOne, testDenomTwo)

type calcAccruedIncentivesTest struct {
poolId uint64
accumUptime time.Duration
Expand Down Expand Up @@ -430,6 +462,106 @@ func (s *KeeperTestSuite) TestCalcAccruedIncentivesForAccum() {
expectedIncentiveRecords: []types.IncentiveRecord{},
expectedPass: false,
},
"two incentive records with same denom, different start time": {
poolId: defaultPoolId,
accumUptime: types.SupportedUptimes[0],
qualifyingLiquidity: sdk.NewDec(100),
timeElapsed: time.Hour,

poolIncentiveRecords: []types.IncentiveRecord{incentiveRecordOne, incentiveRecordOneWithDifferentStartTime},

expectedResult: sdk.NewDecCoins(
// We expect both incentive records to qualify
expectedIncentives(incentiveRecordOne.IncentiveDenom, incentiveRecordOne.EmissionRate.Add(incentiveRecordOneWithDifferentStartTime.EmissionRate), time.Hour, sdk.NewDec(100)), // since we have 2 records with same denom, the rate of emission went up x2
),
expectedIncentiveRecords: []types.IncentiveRecord{
// We only going to charge both incentive records
chargeIncentive(incentiveRecordOne, time.Hour),
chargeIncentive(incentiveRecordOneWithDifferentStartTime, time.Hour),
},
expectedPass: true,
},
"two incentive records with different denom, different start time and same uptime": {
poolId: defaultPoolId,
accumUptime: types.SupportedUptimes[0],
qualifyingLiquidity: sdk.NewDec(100),
timeElapsed: time.Hour,

poolIncentiveRecords: []types.IncentiveRecord{incentiveRecordOneWithDifferentStartTime, incentiveRecordOneWithDifferentDenom},

expectedResult: sdk.DecCoins{
// We expect both incentive record to qualify
expectedIncentives(incentiveRecordOneWithDifferentStartTime.IncentiveDenom, incentiveRecordOne.EmissionRate, time.Hour, sdk.NewDec(100)),
expectedIncentives(incentiveRecordOneWithDifferentDenom.IncentiveDenom, incentiveRecordOne.EmissionRate, time.Hour, sdk.NewDec(100)),
},
expectedIncentiveRecords: []types.IncentiveRecord{
// We charge both incentive record here because both minUpTime has been hit
chargeIncentive(incentiveRecordOneWithDifferentStartTime, time.Hour),
chargeIncentive(incentiveRecordOneWithDifferentDenom, time.Hour),
},
expectedPass: true,
},
"two incentive records with same denom, different min up-time": {
poolId: defaultPoolId,
accumUptime: types.SupportedUptimes[0],
qualifyingLiquidity: sdk.NewDec(100),
timeElapsed: time.Hour,

poolIncentiveRecords: []types.IncentiveRecord{incentiveRecordOne, incentiveRecordOneWithDifferentMinUpTime},

expectedResult: sdk.DecCoins{
// We expect first incentive record to qualify
expectedIncentives(incentiveRecordOne.IncentiveDenom, incentiveRecordOne.EmissionRate, time.Hour, sdk.NewDec(100)),
},
expectedIncentiveRecords: []types.IncentiveRecord{
// We only charge the first incentive record because the second minUpTime hasn't been hit yet
chargeIncentive(incentiveRecordOne, time.Hour),
incentiveRecordOneWithDifferentMinUpTime,
},
expectedPass: true,
},
"two incentive records with same accum uptime and start time across multiple records with different denoms": {
poolId: defaultPoolId,
accumUptime: types.SupportedUptimes[0],
qualifyingLiquidity: sdk.NewDec(100),
timeElapsed: time.Hour,

poolIncentiveRecords: []types.IncentiveRecord{incentiveRecordOne, incentiveRecordOneWithDifferentDenom},

expectedResult: sdk.DecCoins{
// We expect both incentive record to qualify
expectedIncentives(incentiveRecordOne.IncentiveDenom, incentiveRecordOne.EmissionRate, time.Hour, sdk.NewDec(100)),
expectedIncentives(incentiveRecordOneWithDifferentDenom.IncentiveDenom, incentiveRecordOne.EmissionRate, time.Hour, sdk.NewDec(100)),
},
expectedIncentiveRecords: []types.IncentiveRecord{
// We charge both incentive record here because both minUpTime has been hit
chargeIncentive(incentiveRecordOne, time.Hour),
chargeIncentive(incentiveRecordOneWithDifferentDenom, time.Hour),
},
expectedPass: true,
},
"four incentive records with only two eligilbe for emitting incentives": {
poolId: defaultPoolId,
accumUptime: types.SupportedUptimes[0],
qualifyingLiquidity: sdk.NewDec(100),
timeElapsed: time.Hour,

poolIncentiveRecords: []types.IncentiveRecord{incentiveRecordOne, incentiveRecordOneWithDifferentStartTime, incentiveRecordOneWithDifferentDenom, incentiveRecordOneWithDifferentMinUpTime},

expectedResult: sdk.NewDecCoins(
// We expect three incentive record to qualify for incentive
expectedIncentives(incentiveRecordOne.IncentiveDenom, incentiveRecordOne.EmissionRate.Add(incentiveRecordOneWithDifferentStartTime.EmissionRate), time.Hour, sdk.NewDec(100)),
expectedIncentives(incentiveRecordOneWithDifferentDenom.IncentiveDenom, incentiveRecordOne.EmissionRate, time.Hour, sdk.NewDec(100)),
),
expectedIncentiveRecords: []types.IncentiveRecord{
// We only charge the first three incentive record because the fourth minUpTime hasn't been hit yet
chargeIncentive(incentiveRecordOne, time.Hour),
chargeIncentive(incentiveRecordOneWithDifferentStartTime, time.Hour),
chargeIncentive(incentiveRecordOneWithDifferentDenom, time.Hour),
incentiveRecordOneWithDifferentMinUpTime, // this uptime hasn't hit yet so we do not have to charge incentive
},
expectedPass: true,
},
}

for name, tc := range tests {
Expand Down Expand Up @@ -673,3 +805,52 @@ func (s *KeeperTestSuite) TestIncentiveRecordsSetAndGet() {
s.Require().NoError(err)
s.Require().Equal(emptyIncentiveRecords, allRecordsPoolTwo)
}

func (s *KeeperTestSuite) TestGetInitialUptimeGrowthOutsidesForTick() {
expectedUptimes := getExpectedUptimes()

type getInitialUptimeGrowthOutsidesForTick struct {
poolId uint64
tick int64
expectedUptimeAccumulatorValues []sdk.DecCoins
}
tests := map[string]getInitialUptimeGrowthOutsidesForTick{
"uptime growth for tick <= currentTick": {
poolId: 1,
tick: -2,
expectedUptimeAccumulatorValues: expectedUptimes.hundredTokensMultiDenom,
},
"uptime growth for tick > currentTick": {
poolId: 2,
tick: 1,
expectedUptimeAccumulatorValues: expectedUptimes.emptyExpectedAccumValues,
},
}

for name, tc := range tests {
tc := tc

s.Run(name, func() {
s.SetupTest()
clKeeper := s.App.ConcentratedLiquidityKeeper

// create 2 pools
s.PrepareConcentratedPool()
s.PrepareConcentratedPool()

poolUptimeAccumulators, err := clKeeper.GetUptimeAccumulators(s.Ctx, tc.poolId)
s.Require().NoError(err)

for uptimeId, uptimeAccum := range poolUptimeAccumulators {
uptimeAccum.AddToAccumulator(expectedUptimes.hundredTokensMultiDenom[uptimeId])
}

poolUptimeAccumulators, err = clKeeper.GetUptimeAccumulators(s.Ctx, tc.poolId)
s.Require().NoError(err)

val, err := clKeeper.GetInitialUptimeGrowthOutsidesForTick(s.Ctx, tc.poolId, tc.tick)
s.Require().NoError(err)
s.Require().Equal(val, tc.expectedUptimeAccumulatorValues)
})
}
}

0 comments on commit dd76980

Please sign in to comment.