mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-12-27 00:35:18 +00:00
cf009647e6
* Add accumulators * Move accumulator back to keeper package * Add earn specific accumulators * Move store methods to sub-package * Move earn accumulator * Rename accumulator files * Add store doc comment * Add earn accumulator tests, panic if accumulator not used with earn claim type * Update earn accumulator tests to use new methods * Add staking test for earn accumulator * Add test for accumulator proportional rewards * Remove old copy of GetProportionalRewardsPerSecond * Add test for basic accumulator * Fix AddIncentiveMultiRewardPeriod replacement * Deduplicate base earn reward accumulator * Check errors in tests * Validate RewardPeriods in Params.Validate() * Use adapter to fetch earn total shares
428 lines
12 KiB
Go
428 lines
12 KiB
Go
package keeper_test
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/kava-labs/kava/x/incentive/types"
|
|
)
|
|
|
|
func (suite *KeeperTestSuite) TestGetSetDeleteClaims() {
|
|
suite.SetupApp()
|
|
|
|
for claimTypeName, claimTypeValue := range types.ClaimType_value {
|
|
suite.Run(claimTypeName, func() {
|
|
claimType := types.ClaimType(claimTypeValue)
|
|
|
|
c := types.NewClaim(
|
|
claimType,
|
|
suite.addrs[0],
|
|
arbitraryCoins(),
|
|
nonEmptyMultiRewardIndexes,
|
|
)
|
|
|
|
_, found := suite.keeper.Store.GetClaim(suite.ctx, claimType, suite.addrs[0])
|
|
suite.Require().False(found)
|
|
|
|
suite.Require().NotPanics(func() {
|
|
suite.keeper.Store.SetClaim(suite.ctx, c)
|
|
})
|
|
testC, found := suite.keeper.Store.GetClaim(suite.ctx, claimType, suite.addrs[0])
|
|
suite.Require().True(found)
|
|
suite.Require().Equal(c, testC)
|
|
|
|
// Check that other claim types do not exist for the same address
|
|
for otherClaimTypeName, otherClaimTypeValue := range types.ClaimType_value {
|
|
// Skip the current claim type
|
|
if otherClaimTypeValue == claimTypeValue {
|
|
continue
|
|
}
|
|
|
|
otherClaimType := types.ClaimType(otherClaimTypeValue)
|
|
_, found := suite.keeper.Store.GetClaim(suite.ctx, otherClaimType, suite.addrs[0])
|
|
suite.Require().False(found, "claim type %s should not exist", otherClaimTypeName)
|
|
}
|
|
|
|
suite.Require().NotPanics(func() {
|
|
suite.keeper.Store.DeleteClaim(suite.ctx, claimType, suite.addrs[0])
|
|
})
|
|
_, found = suite.keeper.Store.GetClaim(suite.ctx, claimType, suite.addrs[0])
|
|
suite.Require().False(found)
|
|
})
|
|
}
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestIterateClaims() {
|
|
suite.SetupApp()
|
|
var claims types.Claims
|
|
|
|
// Add 2 of each type of claim
|
|
for _, claimTypeValue := range types.ClaimType_value {
|
|
c := types.Claims{
|
|
types.NewClaim(types.ClaimType(claimTypeValue), suite.addrs[0], arbitraryCoins(), nonEmptyMultiRewardIndexes),
|
|
types.NewClaim(types.ClaimType(claimTypeValue), suite.addrs[1], nil, nil),
|
|
}
|
|
claims = append(claims, c...)
|
|
}
|
|
|
|
for _, claim := range claims {
|
|
suite.keeper.Store.SetClaim(suite.ctx, claim)
|
|
}
|
|
|
|
for _, claimTypeValue := range types.ClaimType_value {
|
|
claimType := types.ClaimType(claimTypeValue)
|
|
|
|
// Claims of specific claim type only should be returned
|
|
claims := suite.keeper.Store.GetClaims(suite.ctx, claimType)
|
|
suite.Require().Len(claims, 2)
|
|
suite.Require().Equalf(
|
|
claims, types.Claims{
|
|
types.NewClaim(claimType, suite.addrs[0], arbitraryCoins(), nonEmptyMultiRewardIndexes),
|
|
types.NewClaim(claimType, suite.addrs[1], nil, nil),
|
|
},
|
|
"GetClaims(%s) should only return claims of those type", claimType,
|
|
)
|
|
}
|
|
|
|
allClaims := suite.keeper.Store.GetAllClaims(suite.ctx)
|
|
suite.Require().Len(allClaims, len(claims))
|
|
suite.Require().ElementsMatch(allClaims, claims, "GetAllClaims() should return claims of all types")
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestGetSetRewardAccrualTimes() {
|
|
testCases := []struct {
|
|
name string
|
|
subKey string
|
|
accrualTime time.Time
|
|
panics bool
|
|
}{
|
|
{
|
|
name: "normal time can be written and read",
|
|
subKey: "btc/usdx",
|
|
accrualTime: time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC),
|
|
},
|
|
{
|
|
name: "zero time can be written and read",
|
|
subKey: "btc/usdx",
|
|
accrualTime: time.Time{},
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
suite.Run(tc.name, func() {
|
|
suite.SetupApp()
|
|
|
|
_, found := suite.keeper.Store.GetRewardAccrualTime(suite.ctx, types.CLAIM_TYPE_USDX_MINTING, tc.subKey)
|
|
suite.False(found)
|
|
|
|
setFunc := func() {
|
|
suite.keeper.Store.SetRewardAccrualTime(suite.ctx, types.CLAIM_TYPE_USDX_MINTING, tc.subKey, tc.accrualTime)
|
|
}
|
|
if tc.panics {
|
|
suite.Panics(setFunc)
|
|
return
|
|
} else {
|
|
suite.NotPanics(setFunc)
|
|
}
|
|
|
|
for _, claimTypeValue := range types.ClaimType_value {
|
|
claimType := types.ClaimType(claimTypeValue)
|
|
|
|
if claimType == types.CLAIM_TYPE_USDX_MINTING {
|
|
continue
|
|
}
|
|
|
|
_, found := suite.keeper.Store.GetRewardAccrualTime(suite.ctx, claimType, tc.subKey)
|
|
suite.False(found, "reward accrual time for claim type %s should not exist", claimType)
|
|
}
|
|
|
|
storedTime, found := suite.keeper.Store.GetRewardAccrualTime(suite.ctx, types.CLAIM_TYPE_USDX_MINTING, tc.subKey)
|
|
suite.True(found)
|
|
suite.Equal(tc.accrualTime, storedTime)
|
|
})
|
|
}
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestGetSetRewardIndexes() {
|
|
testCases := []struct {
|
|
name string
|
|
collateralType string
|
|
indexes types.RewardIndexes
|
|
wantIndex types.RewardIndexes
|
|
panics bool
|
|
}{
|
|
{
|
|
name: "two factors can be written and read",
|
|
collateralType: "btc/usdx",
|
|
indexes: types.RewardIndexes{
|
|
{
|
|
CollateralType: "hard",
|
|
RewardFactor: d("0.02"),
|
|
},
|
|
{
|
|
CollateralType: "ukava",
|
|
RewardFactor: d("0.04"),
|
|
},
|
|
},
|
|
wantIndex: types.RewardIndexes{
|
|
{
|
|
CollateralType: "hard",
|
|
RewardFactor: d("0.02"),
|
|
},
|
|
{
|
|
CollateralType: "ukava",
|
|
RewardFactor: d("0.04"),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "indexes with empty pool name panics",
|
|
collateralType: "",
|
|
indexes: types.RewardIndexes{
|
|
{
|
|
CollateralType: "hard",
|
|
RewardFactor: d("0.02"),
|
|
},
|
|
{
|
|
CollateralType: "ukava",
|
|
RewardFactor: d("0.04"),
|
|
},
|
|
},
|
|
panics: true,
|
|
},
|
|
{
|
|
// this test is to detect any changes in behavior
|
|
name: "setting empty indexes does not panic",
|
|
collateralType: "btc/usdx",
|
|
// Marshalling empty slice results in [] bytes, unmarshalling the []
|
|
// empty bytes results in a nil slice instead of an empty slice
|
|
indexes: types.RewardIndexes{},
|
|
wantIndex: nil,
|
|
panics: false,
|
|
},
|
|
{
|
|
// this test is to detect any changes in behavior
|
|
name: "setting nil indexes does not panic",
|
|
collateralType: "btc/usdx",
|
|
indexes: nil,
|
|
wantIndex: nil,
|
|
panics: false,
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
suite.Run(tc.name, func() {
|
|
suite.SetupApp()
|
|
|
|
_, found := suite.keeper.Store.GetRewardIndexesOfClaimType(suite.ctx, types.CLAIM_TYPE_SWAP, tc.collateralType)
|
|
suite.False(found)
|
|
|
|
setFunc := func() {
|
|
suite.keeper.Store.SetRewardIndexes(suite.ctx, types.CLAIM_TYPE_SWAP, tc.collateralType, tc.indexes)
|
|
}
|
|
if tc.panics {
|
|
suite.Panics(setFunc)
|
|
return
|
|
} else {
|
|
suite.NotPanics(setFunc)
|
|
}
|
|
|
|
storedIndexes, found := suite.keeper.Store.GetRewardIndexesOfClaimType(suite.ctx, types.CLAIM_TYPE_SWAP, tc.collateralType)
|
|
suite.True(found)
|
|
suite.Equal(tc.wantIndex, storedIndexes)
|
|
|
|
for _, otherClaimTypeValue := range types.ClaimType_value {
|
|
// Skip swap
|
|
if types.ClaimType(otherClaimTypeValue) == types.CLAIM_TYPE_SWAP {
|
|
continue
|
|
}
|
|
|
|
otherClaimType := types.ClaimType(otherClaimTypeValue)
|
|
|
|
// Other claim types should not be affected
|
|
_, found := suite.keeper.Store.GetRewardIndexesOfClaimType(suite.ctx, otherClaimType, tc.collateralType)
|
|
suite.False(found)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestIterateRewardAccrualTimes() {
|
|
suite.SetupApp()
|
|
|
|
expectedAccrualTimes := nonEmptyAccrualTimes
|
|
|
|
for _, at := range expectedAccrualTimes {
|
|
suite.keeper.Store.SetRewardAccrualTime(suite.ctx, types.CLAIM_TYPE_USDX_MINTING, at.denom, at.time)
|
|
}
|
|
|
|
var actualAccrualTimes []accrualtime
|
|
suite.keeper.Store.IterateRewardAccrualTimesByClaimType(suite.ctx, types.CLAIM_TYPE_USDX_MINTING, func(denom string, accrualTime time.Time) bool {
|
|
actualAccrualTimes = append(actualAccrualTimes, accrualtime{denom: denom, time: accrualTime})
|
|
return false
|
|
})
|
|
|
|
suite.ElementsMatch(expectedAccrualTimes, actualAccrualTimes)
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestIterateAllRewardAccrualTimes() {
|
|
suite.SetupApp()
|
|
|
|
var expectedAccrualTimes types.AccrualTimes
|
|
|
|
for _, claimTypeValue := range types.ClaimType_value {
|
|
claimType := types.ClaimType(claimTypeValue)
|
|
|
|
// Skip invalid claim type
|
|
if claimType.Validate() != nil {
|
|
continue
|
|
}
|
|
|
|
for _, at := range nonEmptyAccrualTimes {
|
|
suite.keeper.Store.SetRewardAccrualTime(suite.ctx, claimType, at.denom, at.time)
|
|
|
|
expectedAccrualTimes = append(expectedAccrualTimes, types.NewAccrualTime(
|
|
claimType,
|
|
|
|
at.denom,
|
|
at.time,
|
|
))
|
|
}
|
|
}
|
|
|
|
var actualAccrualTimes types.AccrualTimes
|
|
suite.keeper.Store.IterateRewardAccrualTimes(
|
|
suite.ctx,
|
|
func(accrualTime types.AccrualTime) bool {
|
|
actualAccrualTimes = append(actualAccrualTimes, accrualTime)
|
|
return false
|
|
},
|
|
)
|
|
|
|
suite.ElementsMatch(expectedAccrualTimes, actualAccrualTimes)
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestIterateRewardIndexes() {
|
|
suite.SetupApp()
|
|
swapMultiIndexes := types.MultiRewardIndexes{
|
|
{
|
|
CollateralType: "bnb",
|
|
RewardIndexes: types.RewardIndexes{
|
|
{
|
|
CollateralType: "swap",
|
|
RewardFactor: d("0.0000002"),
|
|
},
|
|
{
|
|
CollateralType: "ukava",
|
|
RewardFactor: d("0.04"),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
CollateralType: "btcb",
|
|
RewardIndexes: types.RewardIndexes{
|
|
{
|
|
CollateralType: "hard",
|
|
RewardFactor: d("0.02"),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
earnMultiIndexes := types.MultiRewardIndexes{
|
|
{
|
|
CollateralType: "usdc",
|
|
RewardIndexes: types.RewardIndexes{
|
|
{
|
|
CollateralType: "usdc",
|
|
RewardFactor: d("0.0000002"),
|
|
},
|
|
{
|
|
CollateralType: "ukava",
|
|
RewardFactor: d("0.04"),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
CollateralType: "ukava",
|
|
RewardIndexes: types.RewardIndexes{
|
|
{
|
|
CollateralType: "ukava",
|
|
RewardFactor: d("0.02"),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, mi := range swapMultiIndexes {
|
|
suite.keeper.Store.SetRewardIndexes(suite.ctx, types.CLAIM_TYPE_SWAP, mi.CollateralType, mi.RewardIndexes)
|
|
}
|
|
|
|
for _, mi := range earnMultiIndexes {
|
|
// These should be excluded when iterating over swap indexes
|
|
suite.keeper.Store.SetRewardIndexes(suite.ctx, types.CLAIM_TYPE_EARN, mi.CollateralType, mi.RewardIndexes)
|
|
}
|
|
|
|
actualMultiIndexesMap := make(map[types.ClaimType]types.MultiRewardIndexes)
|
|
suite.keeper.Store.IterateRewardIndexesByClaimType(suite.ctx, types.CLAIM_TYPE_SWAP, func(rewardIndex types.TypedRewardIndexes) bool {
|
|
actualMultiIndexesMap[rewardIndex.ClaimType] = actualMultiIndexesMap[rewardIndex.ClaimType].With(rewardIndex.CollateralType, rewardIndex.RewardIndexes)
|
|
return false
|
|
})
|
|
|
|
suite.Require().Len(actualMultiIndexesMap, 1, "iteration should only include 1 claim type")
|
|
suite.Require().Equal(swapMultiIndexes, actualMultiIndexesMap[types.CLAIM_TYPE_SWAP])
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestIterateAllRewardIndexes() {
|
|
suite.SetupApp()
|
|
multiIndexes := types.MultiRewardIndexes{
|
|
{
|
|
CollateralType: "ukava",
|
|
RewardIndexes: types.RewardIndexes{
|
|
{
|
|
CollateralType: "swap",
|
|
RewardFactor: d("0.0000002"),
|
|
},
|
|
{
|
|
CollateralType: "ukava",
|
|
RewardFactor: d("0.04"),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
CollateralType: "usdc",
|
|
RewardIndexes: types.RewardIndexes{
|
|
{
|
|
CollateralType: "hard",
|
|
RewardFactor: d("0.02"),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, claimTypeValue := range types.ClaimType_value {
|
|
if types.ClaimType(claimTypeValue) == types.CLAIM_TYPE_UNSPECIFIED {
|
|
continue
|
|
}
|
|
|
|
claimType := types.ClaimType(claimTypeValue)
|
|
|
|
for _, mi := range multiIndexes {
|
|
suite.keeper.Store.SetRewardIndexes(suite.ctx, claimType, mi.CollateralType, mi.RewardIndexes)
|
|
}
|
|
}
|
|
|
|
actualMultiIndexesMap := make(map[types.ClaimType]types.MultiRewardIndexes)
|
|
suite.keeper.Store.IterateRewardIndexes(suite.ctx, func(rewardIndex types.TypedRewardIndexes) bool {
|
|
actualMultiIndexesMap[rewardIndex.ClaimType] = actualMultiIndexesMap[rewardIndex.ClaimType].With(rewardIndex.CollateralType, rewardIndex.RewardIndexes)
|
|
return false
|
|
})
|
|
|
|
// -1 to exclude the unspecified type
|
|
suite.Require().Len(actualMultiIndexesMap, len(types.ClaimType_value)-1)
|
|
|
|
for claimType, actualMultiIndexes := range actualMultiIndexesMap {
|
|
suite.Require().NoError(claimType.Validate())
|
|
suite.Require().Equal(multiIndexes, actualMultiIndexes)
|
|
}
|
|
}
|