Support per-module incentive claim denom multipliers (#1300)

* Add module name to multiplier

* Add claim test to use correct multiplier

* Add separate test for GetMultiplierByDenom

* Add 0 length lockup for earn to params test

* Add additional tests for genesis and params
This commit is contained in:
Derrick Lee 2022-09-23 09:53:26 -07:00 committed by GitHub
parent 50fdebe657
commit c20c954917
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 370 additions and 64 deletions

View File

@ -113,6 +113,8 @@ func (tApp TestApp) GetFeeMarketKeeper() feemarketkeeper.Keeper { return tApp.fe
func (tApp TestApp) GetLiquidKeeper() liquidkeeper.Keeper { return tApp.liquidKeeper }
func (tApp TestApp) GetEarnKeeper() earnkeeper.Keeper { return tApp.earnKeeper }
func (tApp TestApp) GetStoreKey(s string) sdk.StoreKey { return tApp.keys[s] }
// LegacyAmino returns the app's amino codec.
func (app *App) LegacyAmino() *codec.LegacyAmino {
return app.legacyAmino

View File

@ -4561,6 +4561,7 @@ MultipliersPerDenom is a map of denoms to a set of multipliers
| ----- | ---- | ----- | ----------- |
| `denom` | [string](#string) | | |
| `multipliers` | [Multiplier](#kava.incentive.v1beta1.Multiplier) | repeated | |
| `module_name` | [string](#string) | | |

View File

@ -50,6 +50,8 @@ message MultipliersPerDenom {
string denom = 1;
repeated Multiplier multipliers = 2 [(gogoproto.castrepeated) = "Multipliers", (gogoproto.nullable) = false];
string module_name = 3;
}
// Params

View File

@ -146,6 +146,13 @@ func (suite *GenesisTestSuite) TestExportedGenesisMatchesImported() {
types.NewMultiplier("large", 12, d("1.0")),
},
},
{
Denom: "ukava",
Multipliers: types.Multipliers{
types.NewMultiplier("large", 12, d("1.0")),
},
ModuleName: "earn",
},
{
Denom: "hard",
Multipliers: types.Multipliers{

View File

@ -5,6 +5,8 @@ import (
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/kava-labs/kava/x/incentive/types"
earntypes "github.com/kava-labs/kava/x/earn/types"
)
// ClaimUSDXMintingReward pays out funds from a claim to a receiver account.
@ -15,7 +17,7 @@ func (k Keeper) ClaimUSDXMintingReward(ctx sdk.Context, owner, receiver sdk.AccA
return sdkerrors.Wrapf(types.ErrClaimNotFound, "address: %s", owner)
}
multiplier, found := k.GetMultiplierByDenom(ctx, types.USDXMintingRewardDenom, multiplierName)
multiplier, found := k.GetMultiplierByDenom(ctx, types.USDXMintingRewardDenom, multiplierName, "")
if !found {
return sdkerrors.Wrapf(types.ErrInvalidMultiplier, "denom '%s' has no multiplier '%s'", types.USDXMintingRewardDenom, multiplierName)
}
@ -59,7 +61,7 @@ func (k Keeper) ClaimUSDXMintingReward(ctx sdk.Context, owner, receiver sdk.AccA
// ClaimHardReward pays out funds from a claim to a receiver account.
// Rewards are removed from a claim and paid out according to the multiplier, which reduces the reward amount in exchange for shorter vesting times.
func (k Keeper) ClaimHardReward(ctx sdk.Context, owner, receiver sdk.AccAddress, denom string, multiplierName string) error {
multiplier, found := k.GetMultiplierByDenom(ctx, denom, multiplierName)
multiplier, found := k.GetMultiplierByDenom(ctx, denom, multiplierName, "")
if !found {
return sdkerrors.Wrapf(types.ErrInvalidMultiplier, "denom '%s' has no multiplier '%s'", denom, multiplierName)
}
@ -114,7 +116,7 @@ func (k Keeper) ClaimDelegatorReward(ctx sdk.Context, owner, receiver sdk.AccAdd
return sdkerrors.Wrapf(types.ErrClaimNotFound, "address: %s", owner)
}
multiplier, found := k.GetMultiplierByDenom(ctx, denom, multiplierName)
multiplier, found := k.GetMultiplierByDenom(ctx, denom, multiplierName, "")
if !found {
return sdkerrors.Wrapf(types.ErrInvalidMultiplier, "denom '%s' has no multiplier '%s'", denom, multiplierName)
}
@ -163,7 +165,7 @@ func (k Keeper) ClaimDelegatorReward(ctx sdk.Context, owner, receiver sdk.AccAdd
// ClaimSwapReward pays out funds from a claim to a receiver account.
// Rewards are removed from a claim and paid out according to the multiplier, which reduces the reward amount in exchange for shorter vesting times.
func (k Keeper) ClaimSwapReward(ctx sdk.Context, owner, receiver sdk.AccAddress, denom string, multiplierName string) error {
multiplier, found := k.GetMultiplierByDenom(ctx, denom, multiplierName)
multiplier, found := k.GetMultiplierByDenom(ctx, denom, multiplierName, "")
if !found {
return sdkerrors.Wrapf(types.ErrInvalidMultiplier, "denom '%s' has no multiplier '%s'", denom, multiplierName)
}
@ -210,7 +212,7 @@ func (k Keeper) ClaimSwapReward(ctx sdk.Context, owner, receiver sdk.AccAddress,
// ClaimSavingsReward is a stub method for MsgServer interface compliance
func (k Keeper) ClaimSavingsReward(ctx sdk.Context, owner, receiver sdk.AccAddress, denom string, multiplierName string) error {
multiplier, found := k.GetMultiplierByDenom(ctx, denom, multiplierName)
multiplier, found := k.GetMultiplierByDenom(ctx, denom, multiplierName, "")
if !found {
return sdkerrors.Wrapf(types.ErrInvalidMultiplier, "denom '%s' has no multiplier '%s'", denom, multiplierName)
}
@ -260,7 +262,7 @@ func (k Keeper) ClaimSavingsReward(ctx sdk.Context, owner, receiver sdk.AccAddre
// ClaimEarnReward pays out funds from a claim to a receiver account.
// Rewards are removed from a claim and paid out according to the multiplier, which reduces the reward amount in exchange for shorter vesting times.
func (k Keeper) ClaimEarnReward(ctx sdk.Context, owner, receiver sdk.AccAddress, denom string, multiplierName string) error {
multiplier, found := k.GetMultiplierByDenom(ctx, denom, multiplierName)
multiplier, found := k.GetMultiplierByDenom(ctx, denom, multiplierName, earntypes.ModuleName)
if !found {
return sdkerrors.Wrapf(types.ErrInvalidMultiplier, "denom '%s' has no multiplier '%s'", denom, multiplierName)
}

View File

@ -7,7 +7,11 @@ import (
"github.com/stretchr/testify/suite"
earntypes "github.com/kava-labs/kava/x/earn/types"
"github.com/kava-labs/kava/x/incentive/types"
acctypes "github.com/cosmos/cosmos-sdk/x/auth/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)
// ClaimTests runs unit tests for the keeper Claim methods
@ -84,3 +88,97 @@ func (suite *ClaimTests) TestCannotClaimAfterEndTime() {
err := suite.keeper.ClaimDelegatorReward(suite.ctx, claim.Owner, claim.Owner, "hard", "small")
suite.ErrorIs(err, types.ErrClaimExpired)
}
func (suite *ClaimTests) TestClaimEarnNoLockup() {
vaultDenom1 := "bkava-meow"
vaultDenom2 := "bkava-woof"
suite.ctx = NewTestContext(
suite.incentiveStoreKey,
suite.app.GetStoreKey(acctypes.StoreKey),
suite.app.GetStoreKey(banktypes.StoreKey),
)
err := suite.app.FundModuleAccount(suite.ctx, types.IncentiveMacc, cs(c("ukava", 100000000000)))
suite.NoError(err)
accAddr := arbitraryAddress()
ak := suite.app.GetAccountKeeper()
acc := ak.NewAccountWithAddress(suite.ctx, accAddr)
ak.SetAccount(suite.ctx, acc)
bk := suite.app.GetBankKeeper()
earnKeeper := newFakeEarnKeeper().
addVault(vaultDenom1, earntypes.NewVaultShare(vaultDenom1, d("1000000"))).
addVault(vaultDenom2, earntypes.NewVaultShare(vaultDenom2, d("1000000")))
liquidKeeper := newFakeLiquidKeeper().
addDerivative(vaultDenom1, i(1000000)).
addDerivative(vaultDenom2, i(1000000))
suite.keeper = suite.NewKeeper(
&fakeParamSubspace{},
bk,
nil, nil,
ak,
nil, nil, nil,
liquidKeeper, earnKeeper,
)
suite.keeper.SetParams(suite.ctx, types.Params{
ClaimMultipliers: types.MultipliersPerDenoms{
{
Denom: "ukava",
Multipliers: types.Multipliers{
types.NewMultiplier("large", 0, d("1")),
},
ModuleName: earntypes.ModuleName,
},
{
Denom: "ukava",
Multipliers: types.Multipliers{
types.NewMultiplier("small", 1, d("0.2")),
},
// No module name to apply to other non-earn modules
ModuleName: "",
},
},
ClaimEnd: distantFuture,
})
earnClaim := types.EarnClaim{
BaseMultiClaim: types.BaseMultiClaim{
Owner: accAddr,
Reward: cs(c("earn", 100), c("ukava", 100)),
},
}
suite.storeEarnClaim(earnClaim)
claim := types.DelegatorClaim{
BaseMultiClaim: types.BaseMultiClaim{
Owner: accAddr,
Reward: cs(c("earn", 100), c("ukava", 100)),
},
}
suite.storeDelegatorClaim(claim)
balBefore := bk.GetAllBalances(suite.ctx, accAddr)
suite.Equal(cs(), balBefore)
// Claim for earn module
err = suite.keeper.ClaimEarnReward(suite.ctx, earnClaim.Owner, earnClaim.Owner, "ukava", "large")
suite.NoError(err)
// Check balances
balAfter := bk.GetAllBalances(suite.ctx, accAddr)
suite.Equal(cs(c("ukava", 100)), balAfter)
// Claim for non-earn module
err = suite.keeper.ClaimDelegatorReward(suite.ctx, claim.Owner, claim.Owner, "ukava", "small")
suite.NoError(err)
balAfter2 := bk.GetAllBalances(suite.ctx, accAddr)
suite.Equal(cs(c("ukava", 120)), balAfter2, "claiming ukava for non-earn is multiplied by 0.2")
}

View File

@ -76,12 +76,26 @@ func (k Keeper) GetSavingsRewardPeriods(ctx sdk.Context, denom string) (types.Mu
}
// GetMultiplierByDenom fetches a multiplier from the params matching the denom and name.
func (k Keeper) GetMultiplierByDenom(ctx sdk.Context, denom string, name string) (types.Multiplier, bool) {
func (k Keeper) GetMultiplierByDenom(
ctx sdk.Context,
denom string,
multiplierName string,
moduleName string,
) (types.Multiplier, bool) {
params := k.GetParams(ctx)
// Try specific exact module/CollateralType match first
for _, dm := range params.ClaimMultipliers {
if dm.Denom == denom {
m, found := dm.Multipliers.Get(name)
if dm.Denom == denom && dm.ModuleName == moduleName {
m, found := dm.Multipliers.Get(multiplierName)
return m, found
}
}
// Fallback to generic denom match
for _, dm := range params.ClaimMultipliers {
if dm.Denom == denom && dm.ModuleName == "" {
m, found := dm.Multipliers.Get(multiplierName)
return m, found
}
}

View File

@ -0,0 +1,117 @@
package keeper_test
import (
"testing"
earntypes "github.com/kava-labs/kava/x/earn/types"
"github.com/kava-labs/kava/x/incentive/types"
"github.com/stretchr/testify/suite"
)
type ParamsTests struct {
unitTester
}
func TestParamsTests(t *testing.T) {
suite.Run(t, new(ParamsTests))
}
func (suite *ParamsTests) TestGetMultiplierByDenom() {
subspace := &fakeParamSubspace{
params: types.Params{
ClaimMultipliers: types.MultipliersPerDenoms{
{
Denom: "hard",
Multipliers: types.Multipliers{
types.NewMultiplier("small", 1, d("0.2")),
},
},
{
Denom: "ukava",
Multipliers: types.Multipliers{
types.NewMultiplier("large", 0, d("1")),
},
ModuleName: earntypes.ModuleName,
},
{
Denom: "ukava",
Multipliers: types.Multipliers{
types.NewMultiplier("large", 1, d("0.2")),
},
ModuleName: "",
},
},
},
}
suite.keeper = suite.NewKeeper(subspace, nil, nil, nil, nil, nil, nil, nil, nil, nil)
tests := []struct {
name string
denom string
moduleName string
multiplier string
expected types.Multiplier
}{
{
name: "hard claim",
denom: "hard",
moduleName: "",
multiplier: "small",
expected: types.NewMultiplier("small", 1, d("0.2")),
},
{
name: "ukava earn",
denom: "ukava",
moduleName: earntypes.ModuleName,
multiplier: "large",
expected: types.NewMultiplier("large", 0, d("1.0")),
},
{
name: "ukava non-earn",
denom: "ukava",
moduleName: "",
multiplier: "large",
expected: types.NewMultiplier("large", 1, d("0.2")),
},
}
for _, tc := range tests {
suite.Run(tc.name, func() {
multiplier, found := suite.keeper.GetMultiplierByDenom(
suite.ctx,
tc.denom,
tc.multiplier,
tc.moduleName,
)
suite.Require().True(found)
suite.Require().Equal(tc.expected, multiplier)
})
}
}
func (suite *ParamsTests) TestEmptyModuleNameByDefault() {
subspace := &fakeParamSubspace{
params: types.Params{
ClaimMultipliers: types.MultipliersPerDenoms{
{
Denom: "hard",
Multipliers: types.Multipliers{
types.NewMultiplier("small", 1, d("0.2")),
},
},
{
Denom: "ukava",
Multipliers: types.Multipliers{
types.NewMultiplier("large", 0, d("1")),
},
},
},
},
}
suite.keeper = suite.NewKeeper(subspace, nil, nil, nil, nil, nil, nil, nil, nil, nil)
params := suite.keeper.GetParams(suite.ctx)
for _, m := range params.ClaimMultipliers {
suite.Require().Equal("", m.ModuleName)
}
}

View File

@ -45,6 +45,7 @@ func NewTestContext(requiredStoreKeys ...sdk.StoreKey) sdk.Context {
type unitTester struct {
suite.Suite
keeper keeper.Keeper
app app.TestApp
ctx sdk.Context
cdc codec.Codec
@ -52,8 +53,8 @@ type unitTester struct {
}
func (suite *unitTester) SetupSuite() {
tApp := app.NewTestApp()
suite.cdc = tApp.AppCodec()
suite.app = app.NewTestApp()
suite.cdc = suite.app.AppCodec()
suite.incentiveStoreKey = sdk.NewKVStoreKey(types.StoreKey)
}
@ -74,7 +75,12 @@ func (suite *unitTester) NewKeeper(
ak types.AccountKeeper, stk types.StakingKeeper, swk types.SwapKeeper,
svk types.SavingsKeeper, lqk types.LiquidKeeper, ek types.EarnKeeper,
) keeper.Keeper {
return keeper.NewKeeper(suite.cdc, suite.incentiveStoreKey, paramSubspace, bk, cdpk, hk, ak, stk, swk, svk, lqk, ek)
return keeper.NewKeeper(
suite.cdc,
suite.incentiveStoreKey,
paramSubspace,
bk, cdpk, hk, ak, stk, swk, svk, lqk, ek,
)
}
func (suite *unitTester) storeGlobalBorrowIndexes(indexes types.MultiRewardIndexes) {

View File

@ -70,10 +70,12 @@ func (mpd MultipliersPerDenoms) Validate() error {
return err
}
if foundDenoms[item.Denom] {
return fmt.Errorf("")
// Allow multiple multipliers per denom with different module names
// Effectively a composite key (Denom, ModuleName)
if foundDenoms[item.Denom+item.ModuleName] {
return fmt.Errorf("duplicate denom+moduleName %s", item.Denom+item.ModuleName)
}
foundDenoms[item.Denom] = true
foundDenoms[item.Denom+item.ModuleName] = true
}
return nil
}

View File

@ -157,6 +157,7 @@ var xxx_messageInfo_Multiplier proto.InternalMessageInfo
type MultipliersPerDenom struct {
Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty"`
Multipliers Multipliers `protobuf:"bytes,2,rep,name=multipliers,proto3,castrepeated=Multipliers" json:"multipliers"`
ModuleName string `protobuf:"bytes,3,opt,name=module_name,json=moduleName,proto3" json:"module_name,omitempty"`
}
func (m *MultipliersPerDenom) Reset() { *m = MultipliersPerDenom{} }
@ -251,56 +252,57 @@ func init() {
}
var fileDescriptor_bb8833f5d745eac9 = []byte{
// 774 bytes of a gzipped FileDescriptorProto
// 792 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x96, 0xcf, 0x6e, 0xd3, 0x4a,
0x14, 0xc6, 0xe3, 0xfc, 0xbb, 0xc9, 0xb4, 0xbd, 0xb7, 0x9d, 0x46, 0xb9, 0xbe, 0xb9, 0xc8, 0xa9,
0x52, 0x04, 0x41, 0x55, 0x6d, 0x0a, 0x12, 0x0b, 0x76, 0x98, 0x82, 0x84, 0x44, 0xa5, 0xca, 0x2d,
0x12, 0xb0, 0x89, 0x26, 0xf6, 0xd4, 0xb5, 0x6a, 0x7b, 0xac, 0x99, 0x49, 0xda, 0x88, 0x05, 0x12,
0x0b, 0x76, 0x48, 0x15, 0x0b, 0x1e, 0xa2, 0xaf, 0xc1, 0xa6, 0xcb, 0x8a, 0x15, 0x62, 0xd1, 0x42,
0xfa, 0x22, 0x68, 0xc6, 0x6e, 0xe3, 0xa4, 0x69, 0xa1, 0x52, 0x36, 0xac, 0x32, 0x3e, 0x73, 0xce,
0xf9, 0x7d, 0xfe, 0xc6, 0x67, 0x14, 0xb0, 0xb8, 0x83, 0xba, 0xc8, 0xf0, 0x42, 0x1b, 0x87, 0xdc,
0xeb, 0x62, 0xa3, 0xbb, 0xd2, 0xc6, 0x1c, 0xad, 0x18, 0x11, 0xa2, 0x28, 0x60, 0x7a, 0x44, 0x09,
0x27, 0xb0, 0x2a, 0x92, 0xf4, 0xf3, 0x24, 0x3d, 0x49, 0xaa, 0x55, 0x5c, 0xe2, 0x12, 0x99, 0x62,
0x88, 0x55, 0x9c, 0x5d, 0xab, 0xbb, 0x84, 0xb8, 0x3e, 0x36, 0xe4, 0x53, 0xbb, 0xb3, 0x65, 0x70,
0x2f, 0xc0, 0x8c, 0xa3, 0x20, 0x4a, 0x12, 0x34, 0x9b, 0xb0, 0x80, 0x30, 0xa3, 0x8d, 0xd8, 0x00,
0x68, 0x13, 0x2f, 0x8c, 0xf7, 0x1b, 0x1f, 0xb3, 0x60, 0xda, 0xc2, 0xbb, 0x88, 0x3a, 0xeb, 0x98,
0x7a, 0xc4, 0x81, 0x55, 0x50, 0x44, 0xb6, 0x20, 0xab, 0xca, 0x82, 0xd2, 0x2c, 0x59, 0xc9, 0x13,
0xbc, 0x0d, 0xfe, 0xb1, 0x89, 0xef, 0x23, 0x8e, 0x29, 0xf2, 0x5b, 0xbc, 0x17, 0x61, 0x35, 0xbb,
0xa0, 0x34, 0xcb, 0xd6, 0xdf, 0x83, 0xf0, 0x66, 0x2f, 0xc2, 0xf0, 0x21, 0x28, 0x30, 0x8e, 0x28,
0x57, 0x73, 0x0b, 0x4a, 0x73, 0xea, 0x5e, 0x4d, 0x8f, 0x25, 0xea, 0x67, 0x12, 0xf5, 0xcd, 0x33,
0x89, 0x66, 0xe9, 0xf0, 0xb8, 0x9e, 0xd9, 0x3f, 0xa9, 0x2b, 0x56, 0x5c, 0x02, 0x1f, 0x80, 0x1c,
0x0e, 0x1d, 0x35, 0x7f, 0x8d, 0x4a, 0x51, 0x00, 0xd7, 0x00, 0xa4, 0xf2, 0x25, 0x58, 0x2b, 0xc2,
0xb4, 0xc5, 0xb0, 0x4d, 0x42, 0x47, 0x2d, 0xc8, 0x36, 0xff, 0xe9, 0xb1, 0x05, 0xba, 0xb0, 0xe0,
0xcc, 0x4e, 0xfd, 0x31, 0xf1, 0x42, 0x33, 0x2f, 0xba, 0x58, 0xb3, 0x49, 0xe9, 0x3a, 0xa6, 0x1b,
0xb2, 0xb0, 0xf1, 0x39, 0x0b, 0xe6, 0xd6, 0x3a, 0x3e, 0xf7, 0xfe, 0x7c, 0x67, 0x7a, 0x97, 0x38,
0x93, 0xbb, 0xda, 0x99, 0xbb, 0xa2, 0xcb, 0xc1, 0x49, 0xbd, 0xe9, 0x7a, 0x7c, 0xbb, 0xd3, 0xd6,
0x6d, 0x12, 0x18, 0xc9, 0x97, 0x14, 0xff, 0x2c, 0x33, 0x67, 0xc7, 0x10, 0xef, 0xca, 0x64, 0x01,
0x1b, 0xe3, 0xe2, 0x07, 0x05, 0x00, 0xe9, 0x62, 0xe4, 0x7b, 0x98, 0x42, 0x08, 0xf2, 0x21, 0x0a,
0x62, 0xf3, 0xca, 0x96, 0x5c, 0xc3, 0x45, 0x30, 0x13, 0x90, 0x90, 0x6f, 0xb3, 0x96, 0x4f, 0xec,
0x9d, 0x4e, 0x24, 0x8d, 0xcb, 0x59, 0xd3, 0x71, 0xf0, 0xb9, 0x8c, 0xc1, 0xa7, 0xa0, 0xb8, 0x85,
0x6c, 0x4e, 0xa8, 0xf4, 0x6d, 0xda, 0xd4, 0x85, 0xb6, 0x6f, 0xc7, 0xf5, 0x5b, 0xbf, 0xa1, 0x6d,
0x15, 0xdb, 0x56, 0x52, 0xdd, 0x78, 0xaf, 0x80, 0xf9, 0x81, 0x1e, 0x21, 0x74, 0x15, 0x87, 0x24,
0x80, 0x15, 0x50, 0x70, 0xc4, 0x22, 0x51, 0x16, 0x3f, 0xc0, 0x57, 0x60, 0x2a, 0x18, 0x24, 0xab,
0x59, 0xe9, 0x58, 0x43, 0x1f, 0x3f, 0x9d, 0xfa, 0xa0, 0xaf, 0x39, 0x9f, 0x58, 0x37, 0x95, 0x62,
0x59, 0xe9, 0x5e, 0x8d, 0x2f, 0x25, 0x50, 0x5c, 0x97, 0x33, 0x0f, 0x3f, 0x29, 0xe0, 0xff, 0x0e,
0x73, 0xf6, 0x5a, 0x81, 0x17, 0x72, 0x2f, 0x74, 0x5b, 0xb1, 0x8b, 0xe2, 0xac, 0x3c, 0xe2, 0x30,
0x55, 0x91, 0xd8, 0x9b, 0x97, 0x61, 0xd3, 0xdf, 0xa7, 0xb9, 0x22, 0xc0, 0xfd, 0xe3, 0xba, 0xfa,
0x62, 0x63, 0xf5, 0xe5, 0x5a, 0xdc, 0x2f, 0x9d, 0xc0, 0x0e, 0x4e, 0xea, 0x33, 0x43, 0x01, 0x4b,
0x15, 0xec, 0x71, 0xa9, 0xf0, 0x9d, 0x02, 0x6a, 0xdb, 0x42, 0x09, 0xeb, 0x44, 0x91, 0xdf, 0x1b,
0xd5, 0x15, 0xdb, 0x71, 0xe7, 0x4a, 0x3b, 0x86, 0xc4, 0xd5, 0x12, 0x57, 0xe0, 0x85, 0x2d, 0x66,
0xfd, 0x2b, 0x40, 0x1b, 0x92, 0x73, 0x89, 0x88, 0x36, 0xa1, 0x94, 0xec, 0x8e, 0x8a, 0xc8, 0x4d,
0x5c, 0x84, 0x29, 0x39, 0xc3, 0x22, 0xde, 0x02, 0xd5, 0xc1, 0x3e, 0x76, 0x11, 0x27, 0x74, 0x54,
0x41, 0x7e, 0x92, 0x0a, 0xaa, 0xe7, 0x98, 0x61, 0x01, 0x1d, 0x30, 0xcf, 0x76, 0x51, 0x34, 0xca,
0x2e, 0x4c, 0x92, 0x3d, 0x27, 0x08, 0xc3, 0xd8, 0x2e, 0x98, 0xb3, 0x7d, 0xe4, 0x05, 0xad, 0xf4,
0x18, 0x14, 0x25, 0x74, 0xe9, 0xd7, 0x63, 0x70, 0x3e, 0x5e, 0xe6, 0x8d, 0x04, 0x5b, 0x19, 0xb3,
0xc9, 0xac, 0x59, 0xc9, 0x48, 0x6d, 0xc1, 0x47, 0xa0, 0x1c, 0x73, 0xc5, 0x7d, 0xf7, 0xd7, 0x35,
0xee, 0xbb, 0x92, 0x2c, 0x7b, 0x12, 0x3a, 0xf0, 0x0d, 0xa8, 0x32, 0xd4, 0xf5, 0x42, 0x97, 0x8d,
0x9a, 0x56, 0x9a, 0xa4, 0x69, 0x95, 0x04, 0x72, 0xe1, 0xb8, 0x30, 0xa2, 0xe1, 0x28, 0xb9, 0x3c,
0xd1, 0xe3, 0x12, 0x84, 0xa1, 0x90, 0xf9, 0xec, 0xf0, 0x87, 0x96, 0x39, 0xec, 0x6b, 0xca, 0x51,
0x5f, 0x53, 0xbe, 0xf7, 0x35, 0x65, 0xff, 0x54, 0xcb, 0x1c, 0x9d, 0x6a, 0x99, 0xaf, 0xa7, 0x5a,
0xe6, 0xf5, 0x52, 0xea, 0xae, 0x14, 0x0a, 0x96, 0x7d, 0xd4, 0x66, 0x72, 0x65, 0xec, 0xa5, 0xfe,
0x91, 0xc8, 0x4b, 0xb3, 0x5d, 0x94, 0x36, 0xdf, 0xff, 0x19, 0x00, 0x00, 0xff, 0xff, 0x18, 0x89,
0x03, 0xa4, 0xb0, 0x08, 0x00, 0x00,
0x14, 0xc6, 0xe3, 0xfc, 0xbb, 0xc9, 0xa4, 0xbd, 0xb7, 0x9d, 0x46, 0xb9, 0x26, 0x20, 0xbb, 0x4a,
0x11, 0x04, 0x55, 0xb5, 0x29, 0x48, 0x2c, 0xd8, 0x61, 0x0a, 0x12, 0x12, 0x45, 0x95, 0x5b, 0x24,
0x60, 0x63, 0x4d, 0xec, 0xa9, 0x6b, 0xd5, 0xf6, 0x58, 0x1e, 0x3b, 0x6d, 0xc4, 0x02, 0x89, 0x3d,
0x52, 0xc5, 0x82, 0x57, 0x40, 0xea, 0x6b, 0xb0, 0xe9, 0xb2, 0x62, 0x85, 0x58, 0xb4, 0x90, 0xbe,
0x08, 0x9a, 0xb1, 0xdb, 0x38, 0x69, 0x5a, 0xa8, 0x94, 0x0d, 0xab, 0x8c, 0xcf, 0x9c, 0x73, 0xbe,
0x9f, 0xbf, 0xf1, 0x1c, 0x05, 0x2c, 0x6c, 0xa3, 0x2e, 0x52, 0x1d, 0xdf, 0xc4, 0x7e, 0xe4, 0x74,
0xb1, 0xda, 0x5d, 0xee, 0xe0, 0x08, 0x2d, 0xab, 0x01, 0x0a, 0x91, 0x47, 0x95, 0x20, 0x24, 0x11,
0x81, 0x0d, 0x96, 0xa4, 0x9c, 0x25, 0x29, 0x69, 0x52, 0xb3, 0x6e, 0x13, 0x9b, 0xf0, 0x14, 0x95,
0xad, 0x92, 0xec, 0xa6, 0x6c, 0x13, 0x62, 0xbb, 0x58, 0xe5, 0x4f, 0x9d, 0x78, 0x53, 0x8d, 0x1c,
0x0f, 0xd3, 0x08, 0x79, 0x41, 0x9a, 0x20, 0x99, 0x84, 0x7a, 0x84, 0xaa, 0x1d, 0x44, 0x07, 0x82,
0x26, 0x71, 0xfc, 0x64, 0xbf, 0xf5, 0x31, 0x0f, 0xa6, 0x74, 0xbc, 0x83, 0x42, 0x6b, 0x0d, 0x87,
0x0e, 0xb1, 0x60, 0x03, 0x94, 0x91, 0xc9, 0x94, 0x45, 0x61, 0x5e, 0x68, 0x57, 0xf4, 0xf4, 0x09,
0xde, 0x06, 0xff, 0x99, 0xc4, 0x75, 0x51, 0x84, 0x43, 0xe4, 0x1a, 0x51, 0x2f, 0xc0, 0x62, 0x7e,
0x5e, 0x68, 0x57, 0xf5, 0x7f, 0x07, 0xe1, 0x8d, 0x5e, 0x80, 0xe1, 0x43, 0x50, 0xa2, 0x11, 0x0a,
0x23, 0xb1, 0x30, 0x2f, 0xb4, 0x6b, 0xf7, 0x9a, 0x4a, 0x82, 0xa8, 0x9c, 0x22, 0x2a, 0x1b, 0xa7,
0x88, 0x5a, 0xe5, 0xe0, 0x48, 0xce, 0xed, 0x1d, 0xcb, 0x82, 0x9e, 0x94, 0xc0, 0x07, 0xa0, 0x80,
0x7d, 0x4b, 0x2c, 0x5e, 0xa1, 0x92, 0x15, 0xc0, 0x55, 0x00, 0x43, 0xfe, 0x12, 0xd4, 0x08, 0x70,
0x68, 0x50, 0x6c, 0x12, 0xdf, 0x12, 0x4b, 0xbc, 0xcd, 0x35, 0x25, 0xb1, 0x40, 0x61, 0x16, 0x9c,
0xda, 0xa9, 0x3c, 0x26, 0x8e, 0xaf, 0x15, 0x59, 0x17, 0x7d, 0x26, 0x2d, 0x5d, 0xc3, 0xe1, 0x3a,
0x2f, 0x6c, 0x7d, 0xc9, 0x83, 0xd9, 0xd5, 0xd8, 0x8d, 0x9c, 0xbf, 0xdf, 0x99, 0xde, 0x05, 0xce,
0x14, 0x2e, 0x77, 0xe6, 0x2e, 0xeb, 0xb2, 0x7f, 0x2c, 0xb7, 0x6d, 0x27, 0xda, 0x8a, 0x3b, 0x8a,
0x49, 0x3c, 0x35, 0xfd, 0x92, 0x92, 0x9f, 0x25, 0x6a, 0x6d, 0xab, 0xec, 0x5d, 0x29, 0x2f, 0xa0,
0x63, 0x5c, 0xfc, 0x20, 0x00, 0xc0, 0x5d, 0x0c, 0x5c, 0x07, 0x87, 0x10, 0x82, 0xa2, 0x8f, 0xbc,
0xc4, 0xbc, 0xaa, 0xce, 0xd7, 0x70, 0x01, 0x4c, 0x7b, 0xc4, 0x8f, 0xb6, 0xa8, 0xe1, 0x12, 0x73,
0x3b, 0x0e, 0xb8, 0x71, 0x05, 0x7d, 0x2a, 0x09, 0x3e, 0xe7, 0x31, 0xf8, 0x14, 0x94, 0x37, 0x91,
0x19, 0x91, 0x90, 0xfb, 0x36, 0xa5, 0x29, 0x8c, 0xed, 0xfb, 0x91, 0x7c, 0xeb, 0x0f, 0xd8, 0x56,
0xb0, 0xa9, 0xa7, 0xd5, 0xad, 0xcf, 0x02, 0x98, 0x1b, 0xf0, 0x30, 0xd0, 0x15, 0xec, 0x13, 0x0f,
0xd6, 0x41, 0xc9, 0x62, 0x8b, 0x94, 0x2c, 0x79, 0x80, 0xaf, 0x41, 0xcd, 0x1b, 0x24, 0x8b, 0x79,
0xee, 0x58, 0x4b, 0x19, 0x7f, 0x3b, 0x95, 0x41, 0x5f, 0x6d, 0x2e, 0xb5, 0xae, 0x96, 0xd1, 0xd2,
0xb3, 0xbd, 0xa0, 0x0c, 0x6a, 0x1e, 0xb1, 0x62, 0x17, 0x1b, 0xdc, 0x90, 0x02, 0x97, 0x05, 0x49,
0xe8, 0x05, 0xf2, 0x70, 0xeb, 0x6b, 0x05, 0x94, 0xd7, 0xf8, 0x50, 0x80, 0x9f, 0x04, 0x70, 0x3d,
0xa6, 0xd6, 0xae, 0xe1, 0x39, 0x7e, 0xe4, 0xf8, 0xb6, 0x91, 0xd8, 0xcc, 0x0e, 0xd3, 0x21, 0x16,
0x15, 0x05, 0xce, 0x75, 0xf3, 0x22, 0xae, 0xec, 0x07, 0xac, 0x2d, 0x33, 0xb2, 0xfe, 0x91, 0x2c,
0xbe, 0x5c, 0x5f, 0x79, 0xb5, 0x9a, 0xf4, 0xcb, 0x26, 0xd0, 0xfd, 0x63, 0x79, 0x7a, 0x28, 0xa0,
0x8b, 0x4c, 0x7b, 0x5c, 0x2a, 0x7c, 0x2f, 0x80, 0xe6, 0x16, 0x23, 0xa1, 0x71, 0x10, 0xb8, 0xbd,
0x51, 0xae, 0xc4, 0xaf, 0x3b, 0x97, 0xfa, 0x35, 0x04, 0xd7, 0x4c, 0x6d, 0x83, 0xe7, 0xb6, 0xa8,
0xfe, 0x3f, 0x13, 0x5a, 0xe7, 0x3a, 0x17, 0x40, 0x74, 0x48, 0x18, 0x92, 0x9d, 0x51, 0x88, 0xc2,
0xc4, 0x21, 0x34, 0xae, 0x33, 0x0c, 0xf1, 0x0e, 0x88, 0x16, 0x76, 0xb1, 0x8d, 0x22, 0x12, 0x8e,
0x12, 0x14, 0x27, 0x49, 0xd0, 0x38, 0x93, 0x19, 0x06, 0x88, 0xc1, 0x1c, 0xdd, 0x41, 0xc1, 0xa8,
0x76, 0x69, 0x92, 0xda, 0xb3, 0x4c, 0x61, 0x58, 0xb6, 0x0b, 0x66, 0x4d, 0x17, 0x39, 0x9e, 0x91,
0xbd, 0x27, 0x65, 0x2e, 0xba, 0xf8, 0xfb, 0x7b, 0x72, 0x76, 0xff, 0xb4, 0x1b, 0xa9, 0x6c, 0x7d,
0xcc, 0x26, 0xd5, 0x67, 0xb8, 0x46, 0x66, 0x0b, 0x3e, 0x02, 0xd5, 0x44, 0x97, 0x0d, 0xc4, 0x7f,
0xae, 0x30, 0x10, 0x2b, 0xbc, 0xec, 0x89, 0x6f, 0xc1, 0xb7, 0xa0, 0x41, 0x51, 0xd7, 0xf1, 0x6d,
0x3a, 0x6a, 0x5a, 0x65, 0x92, 0xa6, 0xd5, 0x53, 0x91, 0x73, 0xc7, 0x85, 0x51, 0xe8, 0x8f, 0x2a,
0x57, 0x27, 0x7a, 0x5c, 0x4c, 0x61, 0x28, 0xa4, 0x3d, 0x3b, 0xf8, 0x29, 0xe5, 0x0e, 0xfa, 0x92,
0x70, 0xd8, 0x97, 0x84, 0x1f, 0x7d, 0x49, 0xd8, 0x3b, 0x91, 0x72, 0x87, 0x27, 0x52, 0xee, 0xdb,
0x89, 0x94, 0x7b, 0xb3, 0x98, 0x19, 0xa6, 0x8c, 0x60, 0xc9, 0x45, 0x1d, 0xca, 0x57, 0xea, 0x6e,
0xe6, 0x2f, 0x0b, 0x9f, 0xaa, 0x9d, 0x32, 0xb7, 0xf9, 0xfe, 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff,
0x87, 0x7b, 0x24, 0x65, 0xd1, 0x08, 0x00, 0x00,
}
func (m *RewardPeriod) Marshal() (dAtA []byte, err error) {
@ -504,6 +506,13 @@ func (m *MultipliersPerDenom) MarshalToSizedBuffer(dAtA []byte) (int, error) {
_ = i
var l int
_ = l
if len(m.ModuleName) > 0 {
i -= len(m.ModuleName)
copy(dAtA[i:], m.ModuleName)
i = encodeVarintParams(dAtA, i, uint64(len(m.ModuleName)))
i--
dAtA[i] = 0x1a
}
if len(m.Multipliers) > 0 {
for iNdEx := len(m.Multipliers) - 1; iNdEx >= 0; iNdEx-- {
{
@ -764,6 +773,10 @@ func (m *MultipliersPerDenom) Size() (n int) {
n += 1 + l + sovParams(uint64(l))
}
}
l = len(m.ModuleName)
if l > 0 {
n += 1 + l + sovParams(uint64(l))
}
return n
}
@ -1464,6 +1477,38 @@ func (m *MultipliersPerDenom) Unmarshal(dAtA []byte) error {
return err
}
iNdEx = postIndex
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field ModuleName", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowParams
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthParams
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthParams
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.ModuleName = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipParams(dAtA[iNdEx:])

View File

@ -10,6 +10,8 @@ import (
"github.com/stretchr/testify/suite"
"github.com/kava-labs/kava/x/incentive/types"
earntypes "github.com/kava-labs/kava/x/earn/types"
)
type ParamTestSuite struct {
@ -100,6 +102,14 @@ func (suite *ParamTestSuite) TestParamValidation() {
types.NewMultiplier("small", 1, sdk.MustNewDecFromStr("0.2")),
types.NewMultiplier("large", 12, sdk.MustNewDecFromStr("1.0")),
},
ModuleName: "",
},
{
Denom: "ukava",
Multipliers: types.Multipliers{
types.NewMultiplier("large", 0, sdk.MustNewDecFromStr("1.0")),
},
ModuleName: earntypes.ModuleName,
},
},
ClaimEnd: time.Date(2025, 10, 15, 14, 0, 0, 0, time.UTC),